From a0098eda2de970a7604985e5b2e242fd97ec879d Mon Sep 17 00:00:00 2001 From: Corey Bryant Date: Fri, 27 Sep 2013 10:42:51 -0500 Subject: [PATCH] Initial import of project This is the initial import of the libtpms library. The libtpms library provides software emulation of a Trusted Platform Module (TPM). It is intended to be used by applications when a hardware TPM is not adequate. For example, a hypervisor can use libtpms to emulate an independent TPM for each of it's virtual machine guests. The library provides a high- level API for developers to integrate the emulated TPM support into their application. The code was originally written by Kenneth Goldman and Stefan Berger . The code is licensed under the Modified BSD License. Signed-off-by: Corey Bryant --- CHANGES | 11 + INSTALL | 140 + LICENSE | 32 + Makefile.am | 42 + Makefile.in | 869 ++ README | 89 + aclocal.m4 | 988 ++ config.guess | 1530 +++ config.h.in | 80 + config.sub | 1773 +++ configure | 14857 +++++++++++++++++++++++ configure.in | 114 + depcomp | 708 ++ dist/libtpms.spec.in | 166 + include/Makefile.am | 7 + include/Makefile.in | 596 + include/libtpms/Makefile.am | 15 + include/libtpms/Makefile.in | 512 + include/libtpms/tpm_error.h | 249 + include/libtpms/tpm_library.h | 128 + include/libtpms/tpm_library.h.in | 128 + include/libtpms/tpm_memory.h | 49 + include/libtpms/tpm_nvfilename.h | 56 + include/libtpms/tpm_tis.h | 53 + include/libtpms/tpm_types.h | 138 + install-sh | 527 + libtpms.pc.in | 8 + ltmain.sh | 9655 +++++++++++++++ m4/Makefile.am | 0 m4/Makefile.in | 390 + m4/libtool.m4 | 7986 ++++++++++++ m4/ltoptions.m4 | 384 + m4/ltsugar.m4 | 123 + m4/ltversion.m4 | 23 + m4/lt~obsolete.m4 | 98 + man/Makefile.am | 7 + man/Makefile.in | 596 + man/man3/Makefile.am | 46 + man/man3/Makefile.in | 512 + man/man3/TPMLIB_DecodeBlob.3 | 179 + man/man3/TPMLIB_DecodeBlob.pod | 66 + man/man3/TPMLIB_GetTPMProperty.3 | 247 + man/man3/TPMLIB_GetTPMProperty.pod | 147 + man/man3/TPMLIB_GetVersion.3 | 157 + man/man3/TPMLIB_GetVersion.pod | 30 + man/man3/TPMLIB_MainInit.3 | 211 + man/man3/TPMLIB_MainInit.pod | 92 + man/man3/TPMLIB_Process.3 | 227 + man/man3/TPMLIB_Process.pod | 108 + man/man3/TPMLIB_RegisterCallbacks.3 | 378 + man/man3/TPMLIB_RegisterCallbacks.pod | 272 + man/man3/TPMLIB_Terminate.3 | 1 + man/man3/TPMLIB_VolatileAll_Store.3 | 164 + man/man3/TPMLIB_VolatileAll_Store.pod | 45 + man/man3/TPM_Free.3 | 1 + man/man3/TPM_IO_Hash_Data.3 | 1 + man/man3/TPM_IO_Hash_End.3 | 1 + man/man3/TPM_IO_Hash_Start.3 | 194 + man/man3/TPM_IO_Hash_Start.pod | 78 + man/man3/TPM_IO_TpmEstablished_Get.3 | 165 + man/man3/TPM_IO_TpmEstablished_Get.pod | 47 + man/man3/TPM_Malloc.3 | 190 + man/man3/TPM_Malloc.pod | 72 + man/man3/TPM_Realloc.3 | 1 + missing | 331 + src/Makefile.am | 166 + src/Makefile.in | 1046 ++ src/libtpms.syms | 22 + src/tpm_admin.c | 2004 +++ src/tpm_admin.h | 141 + src/tpm_audit.c | 1271 ++ src/tpm_audit.h | 117 + src/tpm_auth.c | 2297 ++++ src/tpm_auth.h | 176 + src/tpm_commands.h | 51 + src/tpm_constants.h | 1652 +++ src/tpm_counter.c | 1565 +++ src/tpm_counter.h | 140 + src/tpm_crypto.c | 2778 +++++ src/tpm_crypto.h | 219 + src/tpm_crypto_freebl.c | 2648 ++++ src/tpm_cryptoh.c | 5362 ++++++++ src/tpm_cryptoh.h | 358 + src/tpm_daa.c | 5728 +++++++++ src/tpm_daa.h | 405 + src/tpm_debug.c | 100 + src/tpm_debug.h | 65 + src/tpm_delegate.c | 3944 ++++++ src/tpm_delegate.h | 257 + src/tpm_digest.c | 161 + src/tpm_digest.h | 62 + src/tpm_error.c | 43 + src/tpm_global.c | 233 + src/tpm_global.h | 101 + src/tpm_identity.c | 1439 +++ src/tpm_identity.h | 129 + src/tpm_init.c | 1134 ++ src/tpm_init.h | 136 + src/tpm_io.h | 71 + src/tpm_key.c | 5526 +++++++++ src/tpm_key.h | 455 + src/tpm_library.c | 364 + src/tpm_library_conf.h | 172 + src/tpm_library_intern.h | 46 + src/tpm_libtpms_io.c | 70 + src/tpm_load.c | 307 + src/tpm_load.h | 78 + src/tpm_maint.c | 1304 ++ src/tpm_maint.h | 89 + src/tpm_memory.c | 131 + src/tpm_migration.c | 4287 +++++++ src/tpm_migration.h | 218 + src/tpm_nonce.c | 157 + src/tpm_nonce.h | 60 + src/tpm_nvfile.c | 385 + src/tpm_nvfile.h | 71 + src/tpm_nvram.c | 3740 ++++++ src/tpm_nvram.h | 201 + src/tpm_nvram_const.h | 138 + src/tpm_owner.c | 1968 +++ src/tpm_owner.h | 107 + src/tpm_pcr.c | 3791 ++++++ src/tpm_pcr.h | 361 + src/tpm_permanent.c | 1333 ++ src/tpm_permanent.h | 108 + src/tpm_platform.c | 175 + src/tpm_platform.h | 64 + src/tpm_process.c | 6051 +++++++++ src/tpm_process.h | 298 + src/tpm_secret.c | 166 + src/tpm_secret.h | 62 + src/tpm_session.c | 5540 +++++++++ src/tpm_session.h | 276 + src/tpm_sizedbuffer.c | 374 + src/tpm_sizedbuffer.h | 75 + src/tpm_startup.c | 1444 +++ src/tpm_startup.h | 134 + src/tpm_storage.c | 3591 ++++++ src/tpm_storage.h | 165 + src/tpm_store.c | 594 + src/tpm_store.h | 109 + src/tpm_structures.h | 2629 ++++ src/tpm_svnrevision.c | 1 + src/tpm_svnrevision.h | 46 + src/tpm_ticks.c | 913 ++ src/tpm_ticks.h | 97 + src/tpm_time.c | 80 + src/tpm_time.h | 49 + src/tpm_tis.c | 253 + src/tpm_transport.c | 2935 +++++ src/tpm_transport.h | 211 + src/tpm_ver.c | 271 + src/tpm_ver.h | 74 + tests/Makefile.am | 29 + tests/Makefile.in | 648 + tests/freebl_sha1flattensize.c | 50 + 156 files changed, 135982 insertions(+) create mode 100644 CHANGES create mode 100644 INSTALL create mode 100644 LICENSE create mode 100644 Makefile.am create mode 100644 Makefile.in create mode 100644 README create mode 100644 aclocal.m4 create mode 100755 config.guess create mode 100644 config.h.in create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100755 depcomp create mode 100644 dist/libtpms.spec.in create mode 100644 include/Makefile.am create mode 100644 include/Makefile.in create mode 100644 include/libtpms/Makefile.am create mode 100644 include/libtpms/Makefile.in create mode 100644 include/libtpms/tpm_error.h create mode 100644 include/libtpms/tpm_library.h create mode 100644 include/libtpms/tpm_library.h.in create mode 100644 include/libtpms/tpm_memory.h create mode 100644 include/libtpms/tpm_nvfilename.h create mode 100644 include/libtpms/tpm_tis.h create mode 100644 include/libtpms/tpm_types.h create mode 100755 install-sh create mode 100644 libtpms.pc.in create mode 100644 ltmain.sh create mode 100644 m4/Makefile.am create mode 100644 m4/Makefile.in create mode 100644 m4/libtool.m4 create mode 100644 m4/ltoptions.m4 create mode 100644 m4/ltsugar.m4 create mode 100644 m4/ltversion.m4 create mode 100644 m4/lt~obsolete.m4 create mode 100644 man/Makefile.am create mode 100644 man/Makefile.in create mode 100644 man/man3/Makefile.am create mode 100644 man/man3/Makefile.in create mode 100644 man/man3/TPMLIB_DecodeBlob.3 create mode 100644 man/man3/TPMLIB_DecodeBlob.pod create mode 100644 man/man3/TPMLIB_GetTPMProperty.3 create mode 100644 man/man3/TPMLIB_GetTPMProperty.pod create mode 100644 man/man3/TPMLIB_GetVersion.3 create mode 100644 man/man3/TPMLIB_GetVersion.pod create mode 100644 man/man3/TPMLIB_MainInit.3 create mode 100644 man/man3/TPMLIB_MainInit.pod create mode 100644 man/man3/TPMLIB_Process.3 create mode 100644 man/man3/TPMLIB_Process.pod create mode 100644 man/man3/TPMLIB_RegisterCallbacks.3 create mode 100644 man/man3/TPMLIB_RegisterCallbacks.pod create mode 100644 man/man3/TPMLIB_Terminate.3 create mode 100644 man/man3/TPMLIB_VolatileAll_Store.3 create mode 100644 man/man3/TPMLIB_VolatileAll_Store.pod create mode 100644 man/man3/TPM_Free.3 create mode 100644 man/man3/TPM_IO_Hash_Data.3 create mode 100644 man/man3/TPM_IO_Hash_End.3 create mode 100644 man/man3/TPM_IO_Hash_Start.3 create mode 100644 man/man3/TPM_IO_Hash_Start.pod create mode 100644 man/man3/TPM_IO_TpmEstablished_Get.3 create mode 100644 man/man3/TPM_IO_TpmEstablished_Get.pod create mode 100644 man/man3/TPM_Malloc.3 create mode 100644 man/man3/TPM_Malloc.pod create mode 100644 man/man3/TPM_Realloc.3 create mode 100755 missing create mode 100644 src/Makefile.am create mode 100644 src/Makefile.in create mode 100644 src/libtpms.syms create mode 100644 src/tpm_admin.c create mode 100644 src/tpm_admin.h create mode 100644 src/tpm_audit.c create mode 100644 src/tpm_audit.h create mode 100644 src/tpm_auth.c create mode 100644 src/tpm_auth.h create mode 100644 src/tpm_commands.h create mode 100644 src/tpm_constants.h create mode 100644 src/tpm_counter.c create mode 100644 src/tpm_counter.h create mode 100644 src/tpm_crypto.c create mode 100644 src/tpm_crypto.h create mode 100644 src/tpm_crypto_freebl.c create mode 100644 src/tpm_cryptoh.c create mode 100644 src/tpm_cryptoh.h create mode 100644 src/tpm_daa.c create mode 100644 src/tpm_daa.h create mode 100644 src/tpm_debug.c create mode 100644 src/tpm_debug.h create mode 100644 src/tpm_delegate.c create mode 100644 src/tpm_delegate.h create mode 100644 src/tpm_digest.c create mode 100644 src/tpm_digest.h create mode 100644 src/tpm_error.c create mode 100644 src/tpm_global.c create mode 100644 src/tpm_global.h create mode 100644 src/tpm_identity.c create mode 100644 src/tpm_identity.h create mode 100644 src/tpm_init.c create mode 100644 src/tpm_init.h create mode 100644 src/tpm_io.h create mode 100644 src/tpm_key.c create mode 100644 src/tpm_key.h create mode 100644 src/tpm_library.c create mode 100644 src/tpm_library_conf.h create mode 100644 src/tpm_library_intern.h create mode 100644 src/tpm_libtpms_io.c create mode 100644 src/tpm_load.c create mode 100644 src/tpm_load.h create mode 100644 src/tpm_maint.c create mode 100644 src/tpm_maint.h create mode 100644 src/tpm_memory.c create mode 100644 src/tpm_migration.c create mode 100644 src/tpm_migration.h create mode 100644 src/tpm_nonce.c create mode 100644 src/tpm_nonce.h create mode 100644 src/tpm_nvfile.c create mode 100644 src/tpm_nvfile.h create mode 100644 src/tpm_nvram.c create mode 100644 src/tpm_nvram.h create mode 100644 src/tpm_nvram_const.h create mode 100644 src/tpm_owner.c create mode 100644 src/tpm_owner.h create mode 100644 src/tpm_pcr.c create mode 100644 src/tpm_pcr.h create mode 100644 src/tpm_permanent.c create mode 100644 src/tpm_permanent.h create mode 100644 src/tpm_platform.c create mode 100644 src/tpm_platform.h create mode 100644 src/tpm_process.c create mode 100644 src/tpm_process.h create mode 100644 src/tpm_secret.c create mode 100644 src/tpm_secret.h create mode 100644 src/tpm_session.c create mode 100644 src/tpm_session.h create mode 100644 src/tpm_sizedbuffer.c create mode 100644 src/tpm_sizedbuffer.h create mode 100644 src/tpm_startup.c create mode 100644 src/tpm_startup.h create mode 100644 src/tpm_storage.c create mode 100644 src/tpm_storage.h create mode 100644 src/tpm_store.c create mode 100644 src/tpm_store.h create mode 100644 src/tpm_structures.h create mode 100644 src/tpm_svnrevision.c create mode 100644 src/tpm_svnrevision.h create mode 100644 src/tpm_ticks.c create mode 100644 src/tpm_ticks.h create mode 100644 src/tpm_time.c create mode 100644 src/tpm_time.h create mode 100644 src/tpm_tis.c create mode 100644 src/tpm_transport.c create mode 100644 src/tpm_transport.h create mode 100644 src/tpm_ver.c create mode 100644 src/tpm_ver.h create mode 100644 tests/Makefile.am create mode 100644 tests/Makefile.in create mode 100644 tests/freebl_sha1flattensize.c diff --git a/CHANGES b/CHANGES new file mode 100644 index 00000000..c844b2c5 --- /dev/null +++ b/CHANGES @@ -0,0 +1,11 @@ +CHANGES - changes for libtpms + +version 0.5.1 + first public release + + - release 7 increased NVRAM area for being able to store more data in + the TPM's NVRAM areas, i.e., X.509 certificates + + - release 9 added two more APIs: + - TPM_Free + - TPMLIB_DecodeBlob diff --git a/INSTALL b/INSTALL new file mode 100644 index 00000000..c8ec3bc4 --- /dev/null +++ b/INSTALL @@ -0,0 +1,140 @@ +This document contains the following sections: +============================================== + +- Building libtpms +- Installing libtpms, include files and manpages +- Uninstalling libtpms, include files and manpages +- Installation and uninstallation of libtpms manpages only + + +Building libtpms: +----------------- + +Building libtpms can be done using + +make -f makefile-libtpms clean all + +This generates the dynamic link library and symbolic links to the library +and places it in the same directory where the sources are. + +lrwxrwxrwx 1 root root 12 Feb 2 19:11 libtpms.so -> libtpms.so.0 +lrwxrwxrwx 1 root root 16 Feb 2 19:11 libtpms.so.0 -> libtpms.so.0.5.1 +-rwxrwxr-x 1 root root 1489596 Feb 2 19:11 libtpms.so.0.5.1 + +The library is known to build on Linux and Cygwin systems and possible +other Operating Systems that use .so as library extensions. + +On Linux systems, libtpms can be built with either one of the following +crypto backends: + +- openssl +- freebl + +On Cygwin only openssl is available and therefore can only be built with +openssl. + +To build for openssl, the following development packages must have been +installed: + +- glibc-headers +- openssl-devel + +To build for freebl, the following development packages must have been +installed prior to compilation: + +- glibc-headers +- nss-softokn-freebl-devel (preferably version 3.12.9-2 or newer) +- nss-softokn-devel (preferably version 3.12.9-2 or newer) +- gmp-devel + +By default, libtpms is built with the openssl crypto library, which was +shown above. To build with the freebl crypto library the following command +line can be used + +make -f makefile-libtpms CRYPTO_SUBSYSTEM=freebl clean all + +To verify that libtpms was built with freebl as the crypto backend, one +can run + +ldd libtpms.so + + linux-vdso.so.1 => (0x00007fff8d5ff000) + libgmp.so.3 => /usr/lib64/libgmp.so.3 (0x00007f5352a13000) + libnspr4.so => /lib64/libnspr4.so (0x00007f53527d6000) + libnssutil3.so => /usr/lib64/libnssutil3.so (0x00007f53525b6000) + libnss3.so => /usr/lib64/libnss3.so (0x00007f535227c000) + libc.so.6 => /lib64/libc.so.6 (0x00007f5351ed8000) + libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f5351cba000) + libdl.so.2 => /lib64/libdl.so.2 (0x00007f5351ab6000) + libplc4.so => /lib64/libplc4.so (0x00007f53518b2000) + libplds4.so => /lib64/libplds4.so (0x00007f53516ae000) + /lib64/ld-linux-x86-64.so.2 (0x0000003a1c000000) + +The fact that the libraries libgmp, libnspr4, libnssutil3, libnss3, +libpc4, and libplds4 are linked agaist is an indication that the freebl +library was used for linking. + +In case of openssl's libcrypto the output would be the following + + linux-vdso.so.1 => (0x00007fffcbdff000) + libcrypto.so.10 => /lib64/libcrypto.so.10 (0x00007fdb1d00e000) + libc.so.6 => /lib64/libc.so.6 (0x00007fdb1cc6a000) + libdl.so.2 => /lib64/libdl.so.2 (0x00007fdb1ca65000) + libz.so.1 => /lib64/libz.so.1 (0x00007fdb1c84e000) + /lib64/ld-linux-x86-64.so.2 (0x0000003a1c000000) + + +A debug build that prints out __lots__ of debugging information on the +TPM level can be built by invoking make as follows: + +make -f makefile-libtpms CRYPTO_SUBSYSTEM=freebl BUILD_TYPE=debug + + +Installing libtpms, include files and manpages: +----------------------------------------------- + +The installation of libtpms, the development include files (headers) and +man pages can be achieved through: + +make -f makefile-libtpms install + +This will copy libtpms into the standard library directory on your Linux +system such as /usr/lib or /usr/lib64, depending on whether you built for +a 32 bit or 64 bit machine. + +The public include files of libtpms will be copied to /usr/include/libtpms. + +The man pages explaining the libtpms API will be copied to /usr/share/man. + + + +Uninstalling libtpms, include files and manpages: +------------------------------------------------- + +The libtpms library, its development include files (headers) and man pages +can be uninstalled from their standard locations using + +make -f makefile-libtpms uninstall + + +Installation and uninstallation of libtpms man pages only: +---------------------------------------------------------- + +All API calls of libtpms have a man page. The man pages can be separately +installed using + +make -f makefile-libtpms manpages-install + +and uninstalled using + +make -f makefile-libtpms manpages-uninstall + + +If the man pages are not installed into the standard man pages directory +the can then be looked at using + +man -M ./man TPMLIB_MainInit + +from the TPM's source directory that contains the 'man' directory. + +The man pages contain explanations on how to use the API as well as examples. diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..b990ecb6 --- /dev/null +++ b/LICENSE @@ -0,0 +1,32 @@ +Libtpms license + +(c) Copyright IBM Corporation 2006 - 2011 + +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +Redistributions of source code must retain the above copyright notice, +this list of conditions and the following disclaimer. + +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. + +Neither the names of the IBM Corporation nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"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 COPYRIGHT +HOLDER OR CONTRIBUTORS 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. diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 00000000..0c47e5d5 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,42 @@ +# +# Makefile.am +# +# The Initial Developer of the Original Code is International +# Business Machines Corporation. Portions created by IBM +# Corporation are Copyright (C) 2005, 2011 International Business +# Machines Corporation. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the Common Public License as published by +# IBM Corporation; either version 1 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 +# Common Public License for more details. +# +# You should have received a copy of the Common Public License +# along with this program; if not, a copy can be viewed at +# http://www.opensource.org/licenses/cpl1.0.php. +# + +SUBDIRS = \ + include \ + m4 \ + man \ + src \ + tests + +ACLOCAL_AMFLAGS = -I m4 + +EXTRA_DIST = \ + CHANGES \ + INSTALL \ + LICENSE \ + README \ + libtpms.pc.in + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libtpms.pc + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 00000000..23c4ec90 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,869 @@ +# Makefile.in generated by automake 1.11.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Makefile.am +# +# The Initial Developer of the Original Code is International +# Business Machines Corporation. Portions created by IBM +# Corporation are Copyright (C) 2005, 2011 International Business +# Machines Corporation. All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the Common Public License as published by +# IBM Corporation; either version 1 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 +# Common Public License for more details. +# +# You should have received a copy of the Common Public License +# along with this program; if not, a copy can be viewed at +# http://www.opensource.org/licenses/cpl1.0.php. +# + +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/config.h.in \ + $(srcdir)/libtpms.pc.in $(top_srcdir)/configure \ + $(top_srcdir)/dist/libtpms.spec.in INSTALL config.guess \ + config.sub depcomp install-sh ltmain.sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = dist/libtpms.spec libtpms.pc +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(pkgconfigdir)" +DATA = $(pkgconfig_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + if test -d "$(distdir)"; then \ + find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -rf "$(distdir)" \ + || { sleep 5 && rm -rf "$(distdir)"; }; \ + else :; fi +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ + | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUG_DEFINES = @DEBUG_DEFINES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTPMS_VERSION = @LIBTPMS_VERSION@ +LIBTPMS_VERSION_INFO = @LIBTPMS_VERSION_INFO@ +LIBTPMS_VER_MAJOR = @LIBTPMS_VER_MAJOR@ +LIBTPMS_VER_MICRO = @LIBTPMS_VER_MICRO@ +LIBTPMS_VER_MINOR = @LIBTPMS_VER_MINOR@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = \ + include \ + m4 \ + man \ + src \ + tests + +ACLOCAL_AMFLAGS = -I m4 +EXTRA_DIST = \ + CHANGES \ + INSTALL \ + LICENSE \ + README \ + libtpms.pc.in + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libtpms.pc +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +am--refresh: Makefile + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @if test ! -f $@; then rm -f stamp-h1; else :; fi + @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.h.in: $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +dist/libtpms.spec: $(top_builddir)/config.status $(top_srcdir)/dist/libtpms.spec.in + cd $(top_builddir) && $(SHELL) ./config.status $@ +libtpms.pc: $(top_builddir)/config.status $(srcdir)/libtpms.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + -rm -f libtool config.lt +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzip: distdir + tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.lz*) \ + lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod u+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(AM_DISTCHECK_CONFIGURE_FLAGS) \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @test -n '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: trying to run $@ with an empty' \ + '$$(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + $(am__cd) '$(distuninstallcheck_dir)' || { \ + echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ + exit 1; \ + }; \ + test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(pkgconfigdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr \ + distclean-libtool distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-pkgconfigDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-pkgconfigDATA + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + clean-libtool ctags ctags-recursive dist dist-all dist-bzip2 \ + dist-gzip dist-lzip dist-lzma dist-shar dist-tarZ dist-xz \ + dist-zip distcheck distclean distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distcleancheck distdir \ + distuninstallcheck dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-pkgconfigDATA install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am uninstall-pkgconfigDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/README b/README new file mode 100644 index 00000000..95bc2dbd --- /dev/null +++ b/README @@ -0,0 +1,89 @@ +What is libtpms? +---------------- + +Libtpms is a library that targets the integration of TPM functionality +into hypervisors, primarily into Qemu. Libtpms provides a very narrow +public API for this purpose so that integration is possible. Only the +minimum of necessary APIs are made publicly available. + +It is assumed that the user of libtpms is familiar with the concepts +of the Trusted Platform Module (TPM). For the interaction with libtpms +it is necessary to know how to construct valid TPM commands and to +be able to parse their results. It is not within the scope of libtpms's +documentation to provide background on this. See the section on references +below. + + +What files does the libtpms package provide? +-------------------------------------------- + +The main libtpms package provides the following files: + +/usr/lib64/libtpms.so.0 +/usr/lib64/libtpms.so.0.5.1 +/usr/share/doc/libtpms-0.5.1 +/usr/share/doc/libtpms-0.5.1/CHANGES +/usr/share/doc/libtpms-0.5.1/LICENSE +/usr/share/doc/libtpms-0.5.1/README + +Applications can link with -ltpms. + + +What files does the libtpms development package provide? +-------------------------------------------------------- + +The libtpms development package (libtpms-devel) provides the following +include files for applications to use: + +tpm_error.h +tpm_library.h +tpm_memory.h +tpm_nvfilename.h +tpm_tis.h +tpm_types.h + +These files contain the data structures, data types and API calls supported +by libtpms. It is recommended to not use any other API calls than those +provided in these include files. + +All APIs are described in man pages. The man pages are part of the libtpms +development package as well: + +TPMLIB_DecodeBlob +TPMLIB_GetTPMProperty +TPMLIB_GetVersion +TPMLIB_MainInit +TPMLIB_Process +TPMLIB_RegisterCallbacks +TPMLIB_Terminate +TPMLIB_VolatileAll_Store +TPM_Free +TPM_IO_Hash_Data +TPM_IO_Hash_End +TPM_IO_Hash_Start +TPM_IO_TpmEstablished_Get +TPM_Malloc +TPM_Realloc + + +Where can I send bug reports to? +-------------------------------- + +There's a mailing list on the ibmswtpm project on sourceforge where you can +send bug reports to. + +http://sourceforge.net/projects/ibmswtpm/support + +Otherwise you may contact us directly. + +Stefan Berger, stefanb@us.ibm.com +Kenneth Goldman, kgoldman@us.ibm.com + + +References: +----------- + +Documentation about the Trusted Platform Module (TPM) can be downloaded +from the Trusted Computing Group's website at + +http://www.trustedcomputinggroup.org diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 00000000..52a05af7 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,988 @@ +# generated automatically by aclocal 1.11.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, +# Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, +[m4_warning([this file was generated for autoconf 2.69. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software +# Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.6], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.6])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, +# 2010, 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 12 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +AC_SUBST([am__nodep])dnl +_AM_SUBST_NOTMAKE([am__nodep])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation, +# Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation, +# Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software +# Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# -------------------- +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ------------------------ +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 1 + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# -------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AC_SUBST([AMTAR], ['$${TAR-tar}']) +m4_if([$1], [v7], + [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([m4/libtool.m4]) +m4_include([m4/ltoptions.m4]) +m4_include([m4/ltsugar.m4]) +m4_include([m4/ltversion.m4]) +m4_include([m4/lt~obsolete.m4]) diff --git a/config.guess b/config.guess new file mode 100755 index 00000000..d622a44e --- /dev/null +++ b/config.guess @@ -0,0 +1,1530 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file 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, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner. Please send patches (context +# diff format) to and include a ChangeLog +# entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + LIBC=gnu + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + i386) + eval $set_cc_for_build + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + UNAME_PROCESSOR="x86_64" + fi + fi ;; + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.h.in b/config.h.in new file mode 100644 index 00000000..d32aea7d --- /dev/null +++ b/config.h.in @@ -0,0 +1,80 @@ +/* config.h.in. Generated from configure.in by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `crypto' library (-lcrypto). */ +#undef HAVE_LIBCRYPTO + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_OPENSSL_AES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to the sub-directory in which libtool stores uninstalled libraries. + */ +#undef LT_OBJDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Version number of package */ +#undef VERSION + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/config.sub b/config.sub new file mode 100755 index 00000000..c894da45 --- /dev/null +++ b/config.sub @@ -0,0 +1,1773 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +timestamp='2012-02-10' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file 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, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted GNU ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, +2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | be32 | be64 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | epiphany \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 \ + | ns16k | ns32k \ + | open8 \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pyramid \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pyramid-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze) + basic_machine=microblaze-xilinx + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i386-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100755 index 00000000..13046c2c --- /dev/null +++ b/configure @@ -0,0 +1,14857 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.69 for libtpms 0.5.1. +# +# +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1 + + test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ + || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + +SHELL=${CONFIG_SHELL-/bin/sh} + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='libtpms' +PACKAGE_TARNAME='libtpms' +PACKAGE_VERSION='0.5.1' +PACKAGE_STRING='libtpms 0.5.1' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="Makefile.am" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +OTOOL64 +OTOOL +LIPO +NMEDIT +DSYMUTIL +MANIFEST_TOOL +RANLIB +ac_ct_AR +AR +DLLTOOL +OBJDUMP +LN_S +NM +ac_ct_DUMPBIN +DUMPBIN +LD +FGREP +SED +LIBTOOL +LIBTPMS_USE_OPENSSL_FALSE +LIBTPMS_USE_OPENSSL_TRUE +LIBTPMS_USE_FREEBL_FALSE +LIBTPMS_USE_FREEBL_TRUE +EGREP +GREP +CPP +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +am__nodep +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +DEBUG_DEFINES +LIBTPMS_VERSION_INFO +LIBTPMS_VERSION +LIBTPMS_VER_MICRO +LIBTPMS_VER_MINOR +LIBTPMS_VER_MAJOR +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_debug +with_openssl +enable_dependency_tracking +enable_shared +enable_static +with_pic +enable_fast_install +with_gnu_ld +with_sysroot +enable_libtool_lock +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *=) ac_optarg= ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error $? "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error $? "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information" + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error $? "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error $? "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error $? "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures libtpms 0.5.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking ...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/libtpms] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of libtpms 0.5.1:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-debug create a debug build + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-shared[=PKGS] build shared libraries [default=yes] + --enable-static[=PKGS] build static libraries [default=yes] + --enable-fast-install[=PKGS] + optimize for fast installation [default=yes] + --disable-libtool-lock avoid locking (might break parallel builds) + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-openssl build libtpms with openssl library + --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use + both] + --with-gnu-ld assume the C compiler uses GNU ld [default=no] + --with-sysroot=DIR Search for dependent libraries within DIR + (or the compiler's sysroot if not specified). + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +libtpms configure 0.5.1 +generated by GNU Autoconf 2.69 + +Copyright (C) 2012 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + test -x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } > conftest.i && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if eval \${$3+:} false; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.i conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_header_compile + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_func + +# ac_fn_c_check_type LINENO TYPE VAR INCLUDES +# ------------------------------------------- +# Tests whether TYPE exists after having included INCLUDES, setting cache +# variable VAR accordingly. +ac_fn_c_check_type () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if eval \${$3+:} false; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=no" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof ($2)) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +if (sizeof (($2))) + return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + eval "$3=yes" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno + +} # ac_fn_c_check_type +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by libtpms $as_me 0.5.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + $as_echo "## ---------------- ## +## Cache variables. ## +## ---------------- ##" + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + $as_echo "## ----------------- ## +## Output variables. ## +## ----------------- ##" + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + $as_echo "## ------------------- ## +## File substitutions. ## +## ------------------- ##" + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + $as_echo "## ----------- ## +## confdefs.h. ## +## ----------- ##" + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + # We do not want a PATH search for config.site. + case $CONFIG_SITE in #(( + -*) ac_site_file1=./$CONFIG_SITE;; + */*) ac_site_file1=$CONFIG_SITE;; + *) ac_site_file1=./$CONFIG_SITE;; + esac +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" \ + || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "failed to load site script $ac_site_file +See \`config.log' for more details" "$LINENO" 5; } + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +ac_config_headers="$ac_config_headers config.h" + + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if ${ac_cv_build+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if ${ac_cv_host+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if ${ac_cv_target+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if ${ac_cv_path_install+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error $? "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error $? "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if ${ac_cv_path_mkdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AWK+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering ...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='libtpms' + VERSION='0.5.1' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. Yes, it's still used +# in the wild :-( We should find a proper way to deprecate it ... +AMTAR='$${TAR-tar}' + +am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' + + + + + + +LIBTPMS_VER_MAJOR=`echo $PACKAGE_VERSION | awk -F. '{print $1}'` +LIBTPMS_VER_MINOR=`echo $PACKAGE_VERSION | awk -F. '{print $2}'` +LIBTPMS_VER_MICRO=`echo $PACKAGE_VERSION | awk -F. '{print $3}'` +LIBTPMS_VERSION=$PACKAGE_VERSION +LIBTPMS_VERSION_INFO=`expr $LIBTPMS_VER_MAJOR + $LIBTPMS_VER_MINOR`:$LIBTPMS_VER_MICRO:$LIBTPMS_VER_MINOR + + + + + + + +DEBUG="" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for debug-enabled build" >&5 +$as_echo_n "checking for debug-enabled build... " >&6; } +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then : + enableval=$enable_debug; if test "$enableval" = "yes"; then + DEBUG="yes" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + DEBUG="no" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi +else + DEBUG="no", + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +# If the user has not set CFLAGS, do something appropriate +test_CFLAGS=${CFLAGS+set} +if test "$test_CFLAGS" != set; then + if test "$DEBUG" == "yes"; then + CFLAGS="-O0 -g -DDEBUG" + else + CFLAGS="-g -O2" + fi +elif test "$DEBUG" == "yes"; then + CFLAGS="$CFLAGS -O0 -g -DDEBUG" +fi + +debug_defines= +if test "$DEBUG" == "yes"; then + debug_defines="-DTPM_DEBUG -DTPM_VOLATILE_STORE" +fi +DEBUG_DEFINES=$debug_defines + + +cryptolib=freebl + +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' + am__nodep='_no' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "C compiler cannot create executables +See \`config.log' for more details" "$LINENO" 5; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details" "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if ${ac_cv_objext+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "cannot compute suffix of object files: cannot compile +See \`config.log' for more details" "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if ${ac_cv_prog_CPP+:} false; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.i conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.i conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.i conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details" "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if ${ac_cv_path_GREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_GREP" || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if ${ac_cv_path_EGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_EGREP" || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + +# Check whether --with-openssl was given. +if test "${with_openssl+set}" = set; then : + withval=$with_openssl; { $as_echo "$as_me:${as_lineno-$LINENO}: checking for AES_set_encrypt_key in -lcrypto" >&5 +$as_echo_n "checking for AES_set_encrypt_key in -lcrypto... " >&6; } +if ${ac_cv_lib_crypto_AES_set_encrypt_key+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lcrypto $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char AES_set_encrypt_key (); +int +main () +{ +return AES_set_encrypt_key (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_crypto_AES_set_encrypt_key=yes +else + ac_cv_lib_crypto_AES_set_encrypt_key=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_crypto_AES_set_encrypt_key" >&5 +$as_echo "$ac_cv_lib_crypto_AES_set_encrypt_key" >&6; } +if test "x$ac_cv_lib_crypto_AES_set_encrypt_key" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBCRYPTO 1 +_ACEOF + + LIBS="-lcrypto $LIBS" + +else + as_fn_error $? "Faulty openssl crypto library" "$LINENO" 5 +fi + + for ac_header in openssl/aes.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "openssl/aes.h" "ac_cv_header_openssl_aes_h" "$ac_includes_default" +if test "x$ac_cv_header_openssl_aes_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_OPENSSL_AES_H 1 +_ACEOF + +fi + +done + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: Building with openssl crypto library" >&5 +$as_echo "Building with openssl crypto library" >&6; } + cryptolib=openssl + + +fi + + +case "$cryptolib" in +freebl) + if true; then + LIBTPMS_USE_FREEBL_TRUE= + LIBTPMS_USE_FREEBL_FALSE='#' +else + LIBTPMS_USE_FREEBL_TRUE='#' + LIBTPMS_USE_FREEBL_FALSE= +fi + + if false; then + LIBTPMS_USE_OPENSSL_TRUE= + LIBTPMS_USE_OPENSSL_FALSE='#' +else + LIBTPMS_USE_OPENSSL_TRUE='#' + LIBTPMS_USE_OPENSSL_FALSE= +fi + + ;; +openssl) + if false; then + LIBTPMS_USE_FREEBL_TRUE= + LIBTPMS_USE_FREEBL_FALSE='#' +else + LIBTPMS_USE_FREEBL_TRUE='#' + LIBTPMS_USE_FREEBL_FALSE= +fi + + if true; then + LIBTPMS_USE_OPENSSL_TRUE= + LIBTPMS_USE_OPENSSL_FALSE='#' +else + LIBTPMS_USE_OPENSSL_TRUE='#' + LIBTPMS_USE_OPENSSL_FALSE= +fi + + ;; +esac + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_CC+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "no acceptable C compiler found in \$PATH +See \`config.log' for more details" "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if ${ac_cv_c_compiler_gnu+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if ${ac_cv_prog_cc_g+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if ${ac_cv_prog_cc_c89+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if ${am_cv_CC_dependencies_compiler_type+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + rm -rf conftest.dir + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvc7 | msvc7msys | msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + + +case `pwd` in + *\ * | *\ *) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 +$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; +esac + + + +macro_version='2.4.2' +macro_revision='1.3337' + + + + + + + + + + + + + +ltmain="$ac_aux_dir/ltmain.sh" + +# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\(["`$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' + +ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 +$as_echo_n "checking how to print strings... " >&6; } +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "" +} + +case "$ECHO" in + printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 +$as_echo "printf" >&6; } ;; + print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 +$as_echo "print -r" >&6; } ;; + *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 +$as_echo "cat" >&6; } ;; +esac + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 +$as_echo_n "checking for a sed that does not truncate output... " >&6; } +if ${ac_cv_path_SED+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ + for ac_i in 1 2 3 4 5 6 7; do + ac_script="$ac_script$as_nl$ac_script" + done + echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed + { ac_script=; unset ac_script;} + if test -z "$SED"; then + ac_path_SED_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_SED" || continue +# Check for GNU ac_path_SED and select it if it is found. + # Check for GNU $ac_path_SED +case `"$ac_path_SED" --version 2>&1` in +*GNU*) + ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo '' >> "conftest.nl" + "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_SED_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_SED="$ac_path_SED" + ac_path_SED_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_SED_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_SED"; then + as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 + fi +else + ac_cv_path_SED=$SED +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 +$as_echo "$ac_cv_path_SED" >&6; } + SED="$ac_cv_path_SED" + rm -f conftest.sed + +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 +$as_echo_n "checking for fgrep... " >&6; } +if ${ac_cv_path_FGREP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 + then ac_cv_path_FGREP="$GREP -F" + else + if test -z "$FGREP"; then + ac_path_FGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in fgrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" + as_fn_executable_p "$ac_path_FGREP" || continue +# Check for GNU ac_path_FGREP and select it if it is found. + # Check for GNU $ac_path_FGREP +case `"$ac_path_FGREP" --version 2>&1` in +*GNU*) + ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'FGREP' >> "conftest.nl" + "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_FGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_FGREP="$ac_path_FGREP" + ac_path_FGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_FGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_FGREP"; then + as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_FGREP=$FGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 +$as_echo "$ac_cv_path_FGREP" >&6; } + FGREP="$ac_cv_path_FGREP" + + +test -z "$GREP" && GREP=grep + + + + + + + + + + + + + + + + + + + +# Check whether --with-gnu-ld was given. +if test "${with_gnu_ld+set}" = set; then : + withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes +else + with_gnu_ld=no +fi + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 +$as_echo_n "checking for ld used by $CC... " >&6; } + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [\\/]* | ?:[\\/]*) + re_direlt='/[^/][^/]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 +$as_echo_n "checking for GNU ld... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 +$as_echo_n "checking for non-GNU ld... " >&6; } +fi +if ${lt_cv_path_LD+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &5 +$as_echo "$LD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi +test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 +$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } +if ${lt_cv_prog_gnu_ld+:} false; then : + $as_echo_n "(cached) " >&6 +else + # I'd rather use --version here, but apparently some GNU lds only accept -v. +case `$LD -v 2>&1 &5 +$as_echo "$lt_cv_prog_gnu_ld" >&6; } +with_gnu_ld=$lt_cv_prog_gnu_ld + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 +$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } +if ${lt_cv_path_NM+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 +$as_echo "$lt_cv_path_NM" >&6; } +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + if test -n "$ac_tool_prefix"; then + for ac_prog in dumpbin "link -dump" + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DUMPBIN"; then + ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DUMPBIN=$ac_cv_prog_DUMPBIN +if test -n "$DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 +$as_echo "$DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$DUMPBIN" && break + done +fi +if test -z "$DUMPBIN"; then + ac_ct_DUMPBIN=$DUMPBIN + for ac_prog in dumpbin "link -dump" +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DUMPBIN"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN +if test -n "$ac_ct_DUMPBIN"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 +$as_echo "$ac_ct_DUMPBIN" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_DUMPBIN" && break +done + + if test "x$ac_ct_DUMPBIN" = x; then + DUMPBIN=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DUMPBIN=$ac_ct_DUMPBIN + fi +fi + + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 +$as_echo_n "checking the name lister ($NM) interface... " >&6; } +if ${lt_cv_nm_interface+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&5 + (eval echo "\"\$as_me:$LINENO: output\"" >&5) + cat conftest.out >&5 + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 +$as_echo "$lt_cv_nm_interface" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + +# find the maximum length of command line arguments +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 +$as_echo_n "checking the maximum length of command line arguments... " >&6; } +if ${lt_cv_sys_max_cmd_len+:} false; then : + $as_echo_n "(cached) " >&6 +else + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac + +fi + +if test -n $lt_cv_sys_max_cmd_len ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 +$as_echo "$lt_cv_sys_max_cmd_len" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 +$as_echo "none" >&6; } +fi +max_cmd_len=$lt_cv_sys_max_cmd_len + + + + + + +: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 +$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 +$as_echo "$xsi_shell" >&6; } + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 +$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } +lt_shell_append=no +( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 +$as_echo "$lt_shell_append" >&6; } + + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi + + + + + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 +$as_echo_n "checking how to convert $build file names to $host format... " >&6; } +if ${lt_cv_to_host_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac + +fi + +to_host_file_cmd=$lt_cv_to_host_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 +$as_echo "$lt_cv_to_host_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 +$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } +if ${lt_cv_to_tool_file_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + #assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac + +fi + +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 +$as_echo "$lt_cv_to_tool_file_cmd" >&6; } + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 +$as_echo_n "checking for $LD option to reload object files... " >&6; } +if ${lt_cv_ld_reload_flag+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_reload_flag='-r' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 +$as_echo "$lt_cv_ld_reload_flag" >&6; } +reload_flag=$lt_cv_ld_reload_flag +case $reload_flag in +"" | " "*) ;; +*) reload_flag=" $reload_flag" ;; +esac +reload_cmds='$LD$reload_flag -o $output$reload_objs' +case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + if test "$GCC" != yes; then + reload_cmds=false + fi + ;; + darwin*) + if test "$GCC" = yes; then + reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' + else + reload_cmds='$LD$reload_flag -o $output$reload_objs' + fi + ;; +esac + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. +set dummy ${ac_tool_prefix}objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OBJDUMP"; then + ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OBJDUMP=$ac_cv_prog_OBJDUMP +if test -n "$OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 +$as_echo "$OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OBJDUMP"; then + ac_ct_OBJDUMP=$OBJDUMP + # Extract the first word of "objdump", so it can be a program name with args. +set dummy objdump; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OBJDUMP"; then + ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OBJDUMP="objdump" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP +if test -n "$ac_ct_OBJDUMP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 +$as_echo "$ac_ct_OBJDUMP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OBJDUMP" = x; then + OBJDUMP="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OBJDUMP=$ac_ct_OBJDUMP + fi +else + OBJDUMP="$ac_cv_prog_OBJDUMP" +fi + +test -z "$OBJDUMP" && OBJDUMP=objdump + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 +$as_echo_n "checking how to recognize dependent libraries... " >&6; } +if ${lt_cv_deplibs_check_method+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_file_magic_cmd='$MAGIC_CMD' +lt_cv_file_magic_test_file= +lt_cv_deplibs_check_method='unknown' +# Need to set the preceding variable on all platforms that support +# interlibrary dependencies. +# 'none' -- dependencies not supported. +# `unknown' -- same as none, but documents that we really don't know. +# 'pass_all' -- all dependencies passed with no checks. +# 'test_compile' -- check by making test program. +# 'file_magic [[regex]]' -- check by looking for files in library path +# which responds to the $file_magic_cmd with a given extended regex. +# If you have `file' or equivalent on your system and you're not sure +# whether `pass_all' will *always* work, you probably want this one. + +case $host_os in +aix[4-9]*) + lt_cv_deplibs_check_method=pass_all + ;; + +beos*) + lt_cv_deplibs_check_method=pass_all + ;; + +bsdi[45]*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' + lt_cv_file_magic_cmd='/usr/bin/file -L' + lt_cv_file_magic_test_file=/shlib/libc.so + ;; + +cygwin*) + # func_win32_libid is a shell function defined in ltmain.sh + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + ;; + +mingw* | pw32*) + # Base MSYS/MinGW do not provide the 'file' command needed by + # func_win32_libid shell function, so use a weaker test based on 'objdump', + # unless we find 'file', for example because we are cross-compiling. + # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. + if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[3-9]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 +$as_echo "$lt_cv_deplibs_check_method" >&6; } + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + + + + + + + + + + + + + + + + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. +set dummy ${ac_tool_prefix}dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DLLTOOL"; then + ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DLLTOOL=$ac_cv_prog_DLLTOOL +if test -n "$DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 +$as_echo "$DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DLLTOOL"; then + ac_ct_DLLTOOL=$DLLTOOL + # Extract the first word of "dlltool", so it can be a program name with args. +set dummy dlltool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DLLTOOL"; then + ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DLLTOOL="dlltool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL +if test -n "$ac_ct_DLLTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 +$as_echo "$ac_ct_DLLTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DLLTOOL" = x; then + DLLTOOL="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DLLTOOL=$ac_ct_DLLTOOL + fi +else + DLLTOOL="$ac_cv_prog_DLLTOOL" +fi + +test -z "$DLLTOOL" && DLLTOOL=dlltool + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 +$as_echo_n "checking how to associate runtime and link libraries... " >&6; } +if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 +$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + + + + + + + +if test -n "$ac_tool_prefix"; then + for ac_prog in ar + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_AR="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 +$as_echo "$AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AR" && break + done +fi +if test -z "$AR"; then + ac_ct_AR=$AR + for ac_prog in ar +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_AR+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_AR"; then + ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_AR="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_AR=$ac_cv_prog_ac_ct_AR +if test -n "$ac_ct_AR"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 +$as_echo "$ac_ct_AR" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_AR" && break +done + + if test "x$ac_ct_AR" = x; then + AR="false" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + AR=$ac_ct_AR + fi +fi + +: ${AR=ar} +: ${AR_FLAGS=cru} + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 +$as_echo_n "checking for archiver @FILE support... " >&6; } +if ${lt_cv_ar_at_file+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ar_at_file=no + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 + (eval $lt_ar_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 +$as_echo "$lt_cv_ar_at_file" >&6; } + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi + + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_STRIP+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +test -z "$STRIP" && STRIP=: + + + + + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +test -z "$RANLIB" && RANLIB=: + + + + + + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + + +# Check for command to grab the raw symbol name followed by C symbol from nm. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 +$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } +if ${lt_cv_sys_global_symbol_pipe+:} false; then : + $as_echo_n "(cached) " >&6 +else + +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[BCDEGRST]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([_A-Za-z][_A-Za-z0-9]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[BCDT]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[ABCDGISTW]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[ABCDEGRST]' + fi + ;; +irix* | nonstopux*) + symcode='[BCDEGRST]' + ;; +osf*) + symcode='[BCDEGQRST]' + ;; +solaris*) + symcode='[BDRT]' + ;; +sco3.2v5*) + symcode='[DT]' + ;; +sysv4.2uw2*) + symcode='[DT]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[ABDT]' + ;; +sysv4) + symcode='[DFNSTU]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[ABCDGIRSTW]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK '"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + # Now try to grab the symbols. + nlist=conftest.nm + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 + (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&5 + fi + else + echo "cannot find nm_test_var in $nlist" >&5 + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 + fi + else + echo "$progname: failed program was:" >&5 + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done + +fi + +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 +$as_echo "failed" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 +$as_echo "ok" >&6; } +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 +$as_echo_n "checking for sysroot... " >&6; } + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; +else + with_sysroot=no +fi + + +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 +$as_echo "${with_sysroot}" >&6; } + as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 + ;; +esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 +$as_echo "${lt_sysroot:-no}" >&6; } + + + + + +# Check whether --enable-libtool-lock was given. +if test "${enable_libtool_lock+set}" = set; then : + enableval=$enable_libtool_lock; +fi + +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '#line '$LINENO' "configure"' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 +$as_echo_n "checking whether the C compiler needs -belf... " >&6; } +if ${lt_cv_cc_needs_belf+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_cc_needs_belf=yes +else + lt_cv_cc_needs_belf=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 +$as_echo "$lt_cv_cc_needs_belf" >&6; } + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. +set dummy ${ac_tool_prefix}mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$MANIFEST_TOOL"; then + ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL +if test -n "$MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 +$as_echo "$MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_MANIFEST_TOOL"; then + ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL + # Extract the first word of "mt", so it can be a program name with args. +set dummy mt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_MANIFEST_TOOL"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL +if test -n "$ac_ct_MANIFEST_TOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 +$as_echo "$ac_ct_MANIFEST_TOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_MANIFEST_TOOL" = x; then + MANIFEST_TOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL + fi +else + MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" +fi + +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 +$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } +if ${lt_cv_path_mainfest_tool+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&5 + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 +$as_echo "$lt_cv_path_mainfest_tool" >&6; } +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi + + + + + + + case $host_os in + rhapsody* | darwin*) + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. +set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$DSYMUTIL"; then + ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +DSYMUTIL=$ac_cv_prog_DSYMUTIL +if test -n "$DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 +$as_echo "$DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_DSYMUTIL"; then + ac_ct_DSYMUTIL=$DSYMUTIL + # Extract the first word of "dsymutil", so it can be a program name with args. +set dummy dsymutil; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_DSYMUTIL"; then + ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL +if test -n "$ac_ct_DSYMUTIL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 +$as_echo "$ac_ct_DSYMUTIL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_DSYMUTIL" = x; then + DSYMUTIL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + DSYMUTIL=$ac_ct_DSYMUTIL + fi +else + DSYMUTIL="$ac_cv_prog_DSYMUTIL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. +set dummy ${ac_tool_prefix}nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NMEDIT"; then + ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NMEDIT=$ac_cv_prog_NMEDIT +if test -n "$NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 +$as_echo "$NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NMEDIT"; then + ac_ct_NMEDIT=$NMEDIT + # Extract the first word of "nmedit", so it can be a program name with args. +set dummy nmedit; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NMEDIT"; then + ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_NMEDIT="nmedit" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT +if test -n "$ac_ct_NMEDIT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 +$as_echo "$ac_ct_NMEDIT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NMEDIT" = x; then + NMEDIT=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NMEDIT=$ac_ct_NMEDIT + fi +else + NMEDIT="$ac_cv_prog_NMEDIT" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. +set dummy ${ac_tool_prefix}lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$LIPO"; then + ac_cv_prog_LIPO="$LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_LIPO="${ac_tool_prefix}lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +LIPO=$ac_cv_prog_LIPO +if test -n "$LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 +$as_echo "$LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_LIPO"; then + ac_ct_LIPO=$LIPO + # Extract the first word of "lipo", so it can be a program name with args. +set dummy lipo; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_LIPO+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_LIPO"; then + ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_LIPO="lipo" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO +if test -n "$ac_ct_LIPO"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 +$as_echo "$ac_ct_LIPO" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_LIPO" = x; then + LIPO=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + LIPO=$ac_ct_LIPO + fi +else + LIPO="$ac_cv_prog_LIPO" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL"; then + ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL="${ac_tool_prefix}otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL=$ac_cv_prog_OTOOL +if test -n "$OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 +$as_echo "$OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL"; then + ac_ct_OTOOL=$OTOOL + # Extract the first word of "otool", so it can be a program name with args. +set dummy otool; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL"; then + ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL="otool" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL +if test -n "$ac_ct_OTOOL"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 +$as_echo "$ac_ct_OTOOL" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL" = x; then + OTOOL=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL=$ac_ct_OTOOL + fi +else + OTOOL="$ac_cv_prog_OTOOL" +fi + + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. +set dummy ${ac_tool_prefix}otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$OTOOL64"; then + ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +OTOOL64=$ac_cv_prog_OTOOL64 +if test -n "$OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 +$as_echo "$OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_OTOOL64"; then + ac_ct_OTOOL64=$OTOOL64 + # Extract the first word of "otool64", so it can be a program name with args. +set dummy otool64; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_OTOOL64"; then + ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_OTOOL64="otool64" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 +if test -n "$ac_ct_OTOOL64"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 +$as_echo "$ac_ct_OTOOL64" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_OTOOL64" = x; then + OTOOL64=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + OTOOL64=$ac_ct_OTOOL64 + fi +else + OTOOL64="$ac_cv_prog_OTOOL64" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 +$as_echo_n "checking for -single_module linker flag... " >&6; } +if ${lt_cv_apple_cc_single_mod+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&5 + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&5 + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 +$as_echo "$lt_cv_apple_cc_single_mod" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 +$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } +if ${lt_cv_ld_exported_symbols_list+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_ld_exported_symbols_list=yes +else + lt_cv_ld_exported_symbols_list=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 +$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 +$as_echo_n "checking for -force_load linker flag... " >&6; } +if ${lt_cv_ld_force_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 + echo "$AR cru libconftest.a conftest.o" >&5 + $AR cru libconftest.a conftest.o 2>&5 + echo "$RANLIB libconftest.a" >&5 + $RANLIB libconftest.a 2>&5 + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&5 + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&5 + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 +$as_echo "$lt_cv_ld_force_load" >&6; } + case $host_os in + rhapsody* | darwin1.[012]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[91]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[012]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac + +for ac_header in dlfcn.h +do : + ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default +" +if test "x$ac_cv_header_dlfcn_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + +fi + +done + + + + + +# Set options + + + + enable_dlopen=no + + + enable_win32_dll=no + + + # Check whether --enable-shared was given. +if test "${enable_shared+set}" = set; then : + enableval=$enable_shared; p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_shared=yes +fi + + + + + + + + + + # Check whether --enable-static was given. +if test "${enable_static+set}" = set; then : + enableval=$enable_static; p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_static=yes +fi + + + + + + + + + + +# Check whether --with-pic was given. +if test "${with_pic+set}" = set; then : + withval=$with_pic; lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + pic_mode=default +fi + + +test -z "$pic_mode" && pic_mode=default + + + + + + + + # Check whether --enable-fast-install was given. +if test "${enable_fast_install+set}" = set; then : + enableval=$enable_fast_install; p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac +else + enable_fast_install=yes +fi + + + + + + + + + + + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +test -z "$LN_S" && LN_S="ln -s" + + + + + + + + + + + + + + +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 +$as_echo_n "checking for objdir... " >&6; } +if ${lt_cv_objdir+:} false; then : + $as_echo_n "(cached) " >&6 +else + rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 +$as_echo "$lt_cv_objdir" >&6; } +objdir=$lt_cv_objdir + + + + + +cat >>confdefs.h <<_ACEOF +#define LT_OBJDIR "$lt_cv_objdir/" +_ACEOF + + + + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +for cc_temp in $compiler""; do + case $cc_temp in + compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; + distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` + + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 +$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/${ac_tool_prefix}file; then + lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + + +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 +$as_echo_n "checking for file... " >&6; } +if ${lt_cv_path_MAGIC_CMD+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $MAGIC_CMD in +[\\/*] | ?:[\\/]*) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/file; then + lt_cv_path_MAGIC_CMD="$ac_dir/file" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac +fi + +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 +$as_echo "$MAGIC_CMD" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + else + MAGIC_CMD=: + fi +fi + + fi + ;; +esac + +# Use C for the default configuration in the libtool script + +lt_save_CC="$CC" +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +objext=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + + + + + + + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC + +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* + +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* + + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + +lt_prog_compiler_no_builtin_flag= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; + *) + lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; + esac + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 +$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } +if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_rtti_exceptions=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="-fno-rtti -fno-exceptions" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_rtti_exceptions=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 +$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } + +if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then + lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" +else + : +fi + +fi + + + + + + + lt_prog_compiler_wl= +lt_prog_compiler_pic= +lt_prog_compiler_static= + + + if test "$GCC" = yes; then + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_static='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + lt_prog_compiler_pic='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + lt_prog_compiler_pic='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + lt_prog_compiler_static= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + ;; + + interix[3-9]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + lt_prog_compiler_can_build_shared=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + lt_prog_compiler_pic=-Kconform_pic + fi + ;; + + *) + lt_prog_compiler_pic='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + lt_prog_compiler_wl='-Xlinker ' + if test -n "$lt_prog_compiler_pic"; then + lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + lt_prog_compiler_wl='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + lt_prog_compiler_static='-Bstatic' + else + lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + lt_prog_compiler_pic='-DDLL_EXPORT' + ;; + + hpux9* | hpux10* | hpux11*) + lt_prog_compiler_wl='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + lt_prog_compiler_pic='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + lt_prog_compiler_static='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + lt_prog_compiler_wl='-Wl,' + # PIC (with -KPIC) is the default. + lt_prog_compiler_static='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='--shared' + lt_prog_compiler_static='--static' + ;; + nagfor*) + # NAG Fortran compiler + lt_prog_compiler_wl='-Wl,-Wl,,' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + ccc*) + lt_prog_compiler_wl='-Wl,' + # All Alpha code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-qpic' + lt_prog_compiler_static='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='' + ;; + *Sun\ F* | *Sun*Fortran*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + lt_prog_compiler_wl='-Wl,' + ;; + *Intel*\ [CF]*Compiler*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fPIC' + lt_prog_compiler_static='-static' + ;; + *Portland\ Group*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-fpic' + lt_prog_compiler_static='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + lt_prog_compiler_pic='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + lt_prog_compiler_wl='-Wl,' + # All OSF/1 code is PIC. + lt_prog_compiler_static='-non_shared' + ;; + + rdos*) + lt_prog_compiler_static='-non_shared' + ;; + + solaris*) + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + lt_prog_compiler_wl='-Qoption ld ';; + *) + lt_prog_compiler_wl='-Wl,';; + esac + ;; + + sunos4*) + lt_prog_compiler_wl='-Qoption ld ' + lt_prog_compiler_pic='-PIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + lt_prog_compiler_pic='-Kconform_pic' + lt_prog_compiler_static='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_pic='-KPIC' + lt_prog_compiler_static='-Bstatic' + ;; + + unicos*) + lt_prog_compiler_wl='-Wl,' + lt_prog_compiler_can_build_shared=no + ;; + + uts4*) + lt_prog_compiler_pic='-pic' + lt_prog_compiler_static='-Bstatic' + ;; + + *) + lt_prog_compiler_can_build_shared=no + ;; + esac + fi + +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + lt_prog_compiler_pic= + ;; + *) + lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" + ;; +esac + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 +$as_echo_n "checking for $compiler option to produce PIC... " >&6; } +if ${lt_cv_prog_compiler_pic+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic=$lt_prog_compiler_pic +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 +$as_echo "$lt_cv_prog_compiler_pic" >&6; } +lt_prog_compiler_pic=$lt_cv_prog_compiler_pic + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$lt_prog_compiler_pic"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 +$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } +if ${lt_cv_prog_compiler_pic_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_pic_works=no + ac_outfile=conftest.$ac_objext + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$lt_prog_compiler_pic -DPIC" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_pic_works=yes + fi + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 +$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } + +if test x"$lt_cv_prog_compiler_pic_works" = xyes; then + case $lt_prog_compiler_pic in + "" | " "*) ;; + *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; + esac +else + lt_prog_compiler_pic= + lt_prog_compiler_can_build_shared=no +fi + +fi + + + + + + + + + + + +# +# Check to make sure the static flag actually works. +# +wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 +$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } +if ${lt_cv_prog_compiler_static_works+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_static_works=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $lt_tmp_static_flag" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler_static_works=yes + fi + else + lt_cv_prog_compiler_static_works=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 +$as_echo "$lt_cv_prog_compiler_static_works" >&6; } + +if test x"$lt_cv_prog_compiler_static_works" = xyes; then + : +else + lt_prog_compiler_static= +fi + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 +$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } +if ${lt_cv_prog_compiler_c_o+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler_c_o=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + lt_cv_prog_compiler_c_o=yes + fi + fi + chmod u+w . 2>&5 + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 +$as_echo "$lt_cv_prog_compiler_c_o" >&6; } + + + + +hard_links="nottested" +if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 +$as_echo_n "checking if we can lock with hard links... " >&6; } + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 +$as_echo "$hard_links" >&6; } + if test "$hard_links" = no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 +$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} + need_locks=warn + fi +else + need_locks=no +fi + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 +$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } + + runpath_var= + allow_undefined_flag= + always_export_symbols=no + archive_cmds= + archive_expsym_cmds= + compiler_needs_object=no + enable_shared_with_static_runtimes=no + export_dynamic_flag_spec= + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + hardcode_automatic=no + hardcode_direct=no + hardcode_direct_absolute=no + hardcode_libdir_flag_spec= + hardcode_libdir_separator= + hardcode_minus_L=no + hardcode_shlibpath_var=unsupported + inherit_rpath=no + link_all_deplibs=unknown + module_cmds= + module_expsym_cmds= + old_archive_from_new_cmds= + old_archive_from_expsyms_cmds= + thread_safe_flag_spec= + whole_archive_flag_spec= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + include_expsyms= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + ld_shlibs=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; + *\ \(GNU\ Binutils\)\ [3-9]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + export_dynamic_flag_spec='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + whole_archive_flag_spec= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[3-9]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + allow_undefined_flag=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + ld_shlibs=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, + # as there is no search path for DLLs. + hardcode_libdir_flag_spec='-L$libdir' + export_dynamic_flag_spec='${wl}--export-all-symbols' + allow_undefined_flag=unsupported + always_export_symbols=no + enable_shared_with_static_runtimes=yes + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' + exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + ld_shlibs=no + fi + ;; + + haiku*) + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + link_all_deplibs=yes + ;; + + interix[3-9]*) + hardcode_direct=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + whole_archive_flag_spec= + tmp_sharedflag='--shared' ;; + xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + compiler_needs_object=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + ld_shlibs=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) + ld_shlibs=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + ;; + + sunos4*) + archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + ld_shlibs=no + fi + ;; + esac + + if test "$ld_shlibs" = no; then + runpath_var= + hardcode_libdir_flag_spec= + export_dynamic_flag_spec= + whole_archive_flag_spec= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + allow_undefined_flag=unsupported + always_export_symbols=yes + archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + hardcode_minus_L=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + hardcode_direct=unsupported + fi + ;; + + aix[4-9]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + archive_cmds='' + hardcode_direct=yes + hardcode_direct_absolute=yes + hardcode_libdir_separator=':' + link_all_deplibs=yes + file_list_spec='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[012]|aix4.[012].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + hardcode_direct=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + hardcode_minus_L=yes + hardcode_libdir_flag_spec='-L$libdir' + hardcode_libdir_separator= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + export_dynamic_flag_spec='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + always_export_symbols=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + allow_undefined_flag='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' + allow_undefined_flag="-z nodefs" + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + if ${lt_cv_aix_libpath_+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + + lt_aix_libpath_sed=' + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }' + lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + if test -z "$lt_cv_aix_libpath_"; then + lt_cv_aix_libpath_="/usr/lib:/lib" + fi + +fi + + aix_libpath=$lt_cv_aix_libpath_ +fi + + hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + no_undefined_flag=' ${wl}-bernotok' + allow_undefined_flag=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + whole_archive_flag_spec='$convenience' + fi + archive_cmds_need_lc=yes + # This is similar to how AIX traditionally builds its shared libraries. + archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + archive_expsym_cmds='' + ;; + m68k) + archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + ;; + esac + ;; + + bsdi[45]*) + export_dynamic_flag_spec=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + always_export_symbols=yes + file_list_spec='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, )='true' + enable_shared_with_static_runtimes=yes + exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + old_postinstall_cmds='chmod 644 $oldlib' + postlink_cmds='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + hardcode_libdir_flag_spec=' ' + allow_undefined_flag=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + old_archive_from_new_cmds='true' + # FIXME: Should let the user specify the lib program. + old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' + enable_shared_with_static_runtimes=yes + ;; + esac + ;; + + darwin* | rhapsody*) + + + archive_cmds_need_lc=no + hardcode_direct=no + hardcode_automatic=yes + hardcode_shlibpath_var=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + + else + whole_archive_flag_spec='' + fi + link_all_deplibs=yes + allow_undefined_flag="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + + else + ld_shlibs=no + fi + + ;; + + dgux*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + hpux9*) + if test "$GCC" = yes; then + archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + export_dynamic_flag_spec='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 +$as_echo_n "checking if $CC understands -b... " >&6; } +if ${lt_cv_prog_compiler__b+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_prog_compiler__b=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -b" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&5 + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + lt_cv_prog_compiler__b=yes + fi + else + lt_cv_prog_compiler__b=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 +$as_echo "$lt_cv_prog_compiler__b" >&6; } + +if test x"$lt_cv_prog_compiler__b" = xyes; then + archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' +else + archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' +fi + + ;; + esac + fi + if test "$with_gnu_ld" = no; then + hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' + hardcode_libdir_separator=: + + case $host_cpu in + hppa*64*|ia64*) + hardcode_direct=no + hardcode_shlibpath_var=no + ;; + *) + hardcode_direct=yes + hardcode_direct_absolute=yes + export_dynamic_flag_spec='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + hardcode_minus_L=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 +$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } +if ${lt_cv_irix_exported_symbol+:} false; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int foo (void) { return 0; } +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + lt_cv_irix_exported_symbol=yes +else + lt_cv_irix_exported_symbol=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS="$save_LDFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 +$as_echo "$lt_cv_irix_exported_symbol" >&6; } + if test "$lt_cv_irix_exported_symbol" = yes; then + archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + inherit_rpath=yes + link_all_deplibs=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_direct=yes + hardcode_shlibpath_var=no + ;; + + newsos6) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + hardcode_shlibpath_var=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + hardcode_direct=yes + hardcode_shlibpath_var=no + hardcode_direct_absolute=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + export_dynamic_flag_spec='${wl}-E' + else + case $host_os in + openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) + archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-R$libdir' + ;; + *) + archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + hardcode_libdir_flag_spec='${wl}-rpath,$libdir' + ;; + esac + fi + else + ld_shlibs=no + fi + ;; + + os2*) + hardcode_libdir_flag_spec='-L$libdir' + hardcode_minus_L=yes + allow_undefined_flag=unsupported + archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + archive_cmds_need_lc='no' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + hardcode_libdir_separator=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' + archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' + else + allow_undefined_flag=' -expect_unresolved \*' + archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + hardcode_libdir_flag_spec='-rpath $libdir' + fi + archive_cmds_need_lc='no' + hardcode_libdir_separator=: + ;; + + solaris*) + no_undefined_flag=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + hardcode_libdir_flag_spec='-R$libdir' + hardcode_shlibpath_var=no + case $host_os in + solaris2.[0-5] | solaris2.[0-5].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + whole_archive_flag_spec='-z allextract$convenience -z defaultextract' + fi + ;; + esac + link_all_deplibs=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + hardcode_libdir_flag_spec='-L$libdir' + hardcode_direct=yes + hardcode_minus_L=yes + hardcode_shlibpath_var=no + ;; + + sysv4) + case $host_vendor in + sni) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' + reload_cmds='$CC -r -o $output$reload_objs' + hardcode_direct=no + ;; + motorola) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_direct=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + hardcode_shlibpath_var=no + ;; + + sysv4.3*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + export_dynamic_flag_spec='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_shlibpath_var=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + ld_shlibs=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) + no_undefined_flag='${wl}-z,text' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + no_undefined_flag='${wl}-z,text' + allow_undefined_flag='${wl}-z,nodefs' + archive_cmds_need_lc=no + hardcode_shlibpath_var=no + hardcode_libdir_flag_spec='${wl}-R,$libdir' + hardcode_libdir_separator=':' + link_all_deplibs=yes + export_dynamic_flag_spec='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + hardcode_libdir_flag_spec='-L$libdir' + hardcode_shlibpath_var=no + ;; + + *) + ld_shlibs=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + export_dynamic_flag_spec='${wl}-Blargedynsym' + ;; + esac + fi + fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 +$as_echo "$ld_shlibs" >&6; } +test "$ld_shlibs" = no && can_build_shared=no + +with_gnu_ld=$with_gnu_ld + + + + + + + + + + + + + + + +# +# Do we need to explicitly link libc? +# +case "x$archive_cmds_need_lc" in +x|xyes) + # Assume -lc should be added + archive_cmds_need_lc=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $archive_cmds in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 +$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } +if ${lt_cv_archive_cmds_need_lc+:} false; then : + $as_echo_n "(cached) " >&6 +else + $RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$lt_prog_compiler_wl + pic_flag=$lt_prog_compiler_pic + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$allow_undefined_flag + allow_undefined_flag= + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 + (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + then + lt_cv_archive_cmds_need_lc=no + else + lt_cv_archive_cmds_need_lc=yes + fi + allow_undefined_flag=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 +$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } + archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc + ;; + esac + fi + ;; +esac + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 +$as_echo_n "checking dynamic linker characteristics... " >&6; } + +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[lt_foo]++; } + if (lt_freq[lt_foo] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([A-Za-z]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[4-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[01] | aix4.[01].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[45]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' + + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[23].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[01]* | freebsdelf3.[01]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ + freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[3-9]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + if ${lt_cv_shlibpath_overrides_runpath+:} false; then : + $as_echo_n "(cached) " >&6 +else + lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ + LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : + lt_cv_shlibpath_overrides_runpath=yes +fi +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + +fi + + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[89] | openbsd2.[89].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 +$as_echo "$dynamic_linker" >&6; } +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 +$as_echo_n "checking how to hardcode library paths into programs... " >&6; } +hardcode_action= +if test -n "$hardcode_libdir_flag_spec" || + test -n "$runpath_var" || + test "X$hardcode_automatic" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$hardcode_direct" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && + test "$hardcode_minus_L" != no; then + # Linking always hardcodes the temporary library directory. + hardcode_action=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + hardcode_action=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + hardcode_action=unsupported +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 +$as_echo "$hardcode_action" >&6; } + +if test "$hardcode_action" = relink || + test "$inherit_rpath" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi + + + + + + + if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + +fi + + ;; + + *) + ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" +if test "x$ac_cv_func_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 +$as_echo_n "checking for shl_load in -ldld... " >&6; } +if ${ac_cv_lib_dld_shl_load+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char shl_load (); +int +main () +{ +return shl_load (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_shl_load=yes +else + ac_cv_lib_dld_shl_load=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 +$as_echo "$ac_cv_lib_dld_shl_load" >&6; } +if test "x$ac_cv_lib_dld_shl_load" = xyes; then : + lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" +else + ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" +if test "x$ac_cv_func_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 +$as_echo_n "checking for dlopen in -ldl... " >&6; } +if ${ac_cv_lib_dl_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldl $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dl_dlopen=yes +else + ac_cv_lib_dl_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 +$as_echo "$ac_cv_lib_dl_dlopen" >&6; } +if test "x$ac_cv_lib_dl_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 +$as_echo_n "checking for dlopen in -lsvld... " >&6; } +if ${ac_cv_lib_svld_dlopen+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsvld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dlopen (); +int +main () +{ +return dlopen (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_svld_dlopen=yes +else + ac_cv_lib_svld_dlopen=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 +$as_echo "$ac_cv_lib_svld_dlopen" >&6; } +if test "x$ac_cv_lib_svld_dlopen" = xyes; then : + lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 +$as_echo_n "checking for dld_link in -ldld... " >&6; } +if ${ac_cv_lib_dld_dld_link+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-ldld $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char dld_link (); +int +main () +{ +return dld_link (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_dld_dld_link=yes +else + ac_cv_lib_dld_dld_link=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 +$as_echo "$ac_cv_lib_dld_dld_link" >&6; } +if test "x$ac_cv_lib_dld_dld_link" = xyes; then : + lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" +fi + + +fi + + +fi + + +fi + + +fi + + +fi + + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 +$as_echo_n "checking whether a program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 +$as_echo "$lt_cv_dlopen_self" >&6; } + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 +$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } +if ${lt_cv_dlopen_self_static+:} false; then : + $as_echo_n "(cached) " >&6 +else + if test "$cross_compiling" = yes; then : + lt_cv_dlopen_self_static=cross +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +} +_LT_EOF + if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 + (eval $ac_link) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&5 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; + x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; + esac + else : + # compilation failed + lt_cv_dlopen_self_static=no + fi +fi +rm -fr conftest* + + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 +$as_echo "$lt_cv_dlopen_self_static" >&6; } + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi + + + + + + + + + + + + + + + + + +striplib= +old_striplib= +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 +$as_echo_n "checking whether stripping libraries is possible... " >&6; } +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + fi + ;; + *) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + ;; + esac +fi + + + + + + + + + + + + + # Report which library types will actually be built + { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 +$as_echo_n "checking if libtool supports shared libraries... " >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 +$as_echo "$can_build_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 +$as_echo_n "checking whether to build shared libraries... " >&6; } + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[4-9]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 +$as_echo "$enable_shared" >&6; } + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 +$as_echo_n "checking whether to build static libraries... " >&6; } + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 +$as_echo "$enable_static" >&6; } + + + + +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +CC="$lt_save_CC" + + + + + + + + + + + + + + + + ac_config_commands="$ac_config_commands libtool" + + + + +# Only expand once: + + + +#AM_GNU_GETTEXT_VERSION([0.15]) +#AM_GNU_GETTEXT([external]) + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if ${ac_cv_header_stdc+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for an ANSI C-conforming const" >&5 +$as_echo_n "checking for an ANSI C-conforming const... " >&6; } +if ${ac_cv_c_const+:} false; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + +#ifndef __cplusplus + /* Ultrix mips cc rejects this sort of thing. */ + typedef int charset[2]; + const charset cs = { 0, 0 }; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this sort of thing. */ + char tx; + char *t = &tx; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this sort of thing, saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; } bx; + struct s *b = &bx; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_const=yes +else + ac_cv_c_const=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_const" >&5 +$as_echo "$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +$as_echo "#define const /**/" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for inline" >&5 +$as_echo_n "checking for inline... " >&6; } +if ${ac_cv_c_inline+:} false; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_inline=$ac_kw +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_inline" >&5 +$as_echo "$ac_cv_c_inline" >&6; } + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + + +ac_fn_c_check_type "$LINENO" "size_t" "ac_cv_type_size_t" "$ac_includes_default" +if test "x$ac_cv_type_size_t" = xyes; then : + +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + + + +CFLAGS="$CFLAGS -Wall -Werror -Wreturn-type -Wsign-compare" + +ac_config_files="$ac_config_files Makefile dist/libtpms.spec include/Makefile include/libtpms/Makefile include/libtpms/tpm_library.h m4/Makefile man/Makefile man/man3/Makefile src/Makefile libtpms.pc tests/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + if test "x$cache_file" != "x/dev/null"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + if test ! -f "$cache_file" || test -h "$cache_file"; then + cat confcache >"$cache_file" + else + case $cache_file in #( + */* | ?:*) + mv -f confcache "$cache_file"$$ && + mv -f "$cache_file"$$ "$cache_file" ;; #( + *) + mv -f confcache "$cache_file" ;; + esac + fi + fi + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +U= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error $? "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LIBTPMS_USE_FREEBL_TRUE}" && test -z "${LIBTPMS_USE_FREEBL_FALSE}"; then + as_fn_error $? "conditional \"LIBTPMS_USE_FREEBL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LIBTPMS_USE_OPENSSL_TRUE}" && test -z "${LIBTPMS_USE_OPENSSL_FALSE}"; then + as_fn_error $? "conditional \"LIBTPMS_USE_OPENSSL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LIBTPMS_USE_FREEBL_TRUE}" && test -z "${LIBTPMS_USE_FREEBL_FALSE}"; then + as_fn_error $? "conditional \"LIBTPMS_USE_FREEBL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${LIBTPMS_USE_OPENSSL_TRUE}" && test -z "${LIBTPMS_USE_OPENSSL_FALSE}"; then + as_fn_error $? "conditional \"LIBTPMS_USE_OPENSSL\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error $? "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: "${CONFIG_STATUS=./config.status}" +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +as_myself= +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error STATUS ERROR [LINENO LOG_FD] +# ---------------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with STATUS, using 1 if that was 0. +as_fn_error () +{ + as_status=$1; test $as_status -eq 0 && as_status=1 + if test "$4"; then + as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + fi + $as_echo "$as_me: error: $2" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -pR'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -pR' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -pR' + fi +else + as_ln_s='cp -pR' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by libtpms $as_me 0.5.1, which was +generated by GNU Autoconf 2.69. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +libtpms config.status 0.5.1 +configured by $0, generated by GNU Autoconf 2.69, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2012 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=?*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + --*=) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg= + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + '') as_fn_error $? "missing file argument" ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error $? "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error $? "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' +macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' +enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' +enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' +pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' +enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' +SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' +ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' +PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' +host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' +host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' +host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' +build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' +build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' +build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' +SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' +Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' +GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' +EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' +FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' +LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' +NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' +LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' +max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' +ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' +exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' +lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' +lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' +lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' +lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' +lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' +reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' +reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' +OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' +deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' +file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' +file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' +want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' +DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' +sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' +AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' +AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' +archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' +STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' +RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' +old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' +old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' +lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' +CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' +CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' +compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' +GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' +nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' +lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' +objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' +MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' +lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' +lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' +need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' +MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' +DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' +NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' +LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' +OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' +OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' +libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' +shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' +extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' +enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' +export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' +whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' +compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' +old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' +old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' +archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' +archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' +module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' +module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' +with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' +allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' +no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' +hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' +hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' +hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' +hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' +hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' +hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' +inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' +link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' +always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' +export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' +exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' +include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' +prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' +postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' +file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' +variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' +need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' +need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' +version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' +runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' +shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' +libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' +library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' +soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' +install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' +postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' +postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' +finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' +finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' +hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' +sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' +sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' +hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' +enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' +enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' +old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' +striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' + +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in SHELL \ +ECHO \ +PATH_SEPARATOR \ +SED \ +GREP \ +EGREP \ +FGREP \ +LD \ +NM \ +LN_S \ +lt_SP2NL \ +lt_NL2SP \ +reload_flag \ +OBJDUMP \ +deplibs_check_method \ +file_magic_cmd \ +file_magic_glob \ +want_nocaseglob \ +DLLTOOL \ +sharedlib_from_linklib_cmd \ +AR \ +AR_FLAGS \ +archiver_list_spec \ +STRIP \ +RANLIB \ +CC \ +CFLAGS \ +compiler \ +lt_cv_sys_global_symbol_pipe \ +lt_cv_sys_global_symbol_to_cdecl \ +lt_cv_sys_global_symbol_to_c_name_address \ +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ +nm_file_list_spec \ +lt_prog_compiler_no_builtin_flag \ +lt_prog_compiler_pic \ +lt_prog_compiler_wl \ +lt_prog_compiler_static \ +lt_cv_prog_compiler_c_o \ +need_locks \ +MANIFEST_TOOL \ +DSYMUTIL \ +NMEDIT \ +LIPO \ +OTOOL \ +OTOOL64 \ +shrext_cmds \ +export_dynamic_flag_spec \ +whole_archive_flag_spec \ +compiler_needs_object \ +with_gnu_ld \ +allow_undefined_flag \ +no_undefined_flag \ +hardcode_libdir_flag_spec \ +hardcode_libdir_separator \ +exclude_expsyms \ +include_expsyms \ +file_list_spec \ +variables_saved_for_relink \ +libname_spec \ +library_names_spec \ +soname_spec \ +install_override_mode \ +finish_eval \ +old_striplib \ +striplib; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in reload_cmds \ +old_postinstall_cmds \ +old_postuninstall_cmds \ +old_archive_cmds \ +extract_expsyms_cmds \ +old_archive_from_new_cmds \ +old_archive_from_expsyms_cmds \ +archive_cmds \ +archive_expsym_cmds \ +module_cmds \ +module_expsym_cmds \ +export_symbols_cmds \ +prelink_cmds \ +postlink_cmds \ +postinstall_cmds \ +postuninstall_cmds \ +finish_cmds \ +sys_lib_search_path_spec \ +sys_lib_dlsearch_path_spec; do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[\\\\\\\`\\"\\\$]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +ac_aux_dir='$ac_aux_dir' +xsi_shell='$xsi_shell' +lt_shell_append='$lt_shell_append' + +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + + + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile' + + + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "dist/libtpms.spec") CONFIG_FILES="$CONFIG_FILES dist/libtpms.spec" ;; + "include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;; + "include/libtpms/Makefile") CONFIG_FILES="$CONFIG_FILES include/libtpms/Makefile" ;; + "include/libtpms/tpm_library.h") CONFIG_FILES="$CONFIG_FILES include/libtpms/tpm_library.h" ;; + "m4/Makefile") CONFIG_FILES="$CONFIG_FILES m4/Makefile" ;; + "man/Makefile") CONFIG_FILES="$CONFIG_FILES man/Makefile" ;; + "man/man3/Makefile") CONFIG_FILES="$CONFIG_FILES man/man3/Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + "libtpms.pc") CONFIG_FILES="$CONFIG_FILES libtpms.pc" ;; + "tests/Makefile") CONFIG_FILES="$CONFIG_FILES tests/Makefile" ;; + + *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= ac_tmp= + trap 'exit_status=$? + : "${ac_tmp:=$tmp}" + { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +ac_tmp=$tmp + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$ac_tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ + || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove sole $(srcdir), +# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ +h +s/// +s/^/:/ +s/[ ]*$/:/ +s/:\$(srcdir):/:/g +s/:\${srcdir}:/:/g +s/:@srcdir@:/:/g +s/^:*// +s/:*$// +x +s/\(=[ ]*\).*/\1/ +G +s/\n// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$ac_tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_tt=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_tt"; then + break + elif $ac_last_try; then + as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$ac_tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$ac_tmp/stdin" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ + >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ + "$ac_tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined" >&2;} + + rm -f "$ac_tmp/stdin" + case $ac_file in + -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; + *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; + esac \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" + } >"$ac_tmp/config.h" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$ac_tmp/config.h" "$ac_file" \ + || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error $? "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "libtool":C) + + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool 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. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# The names of the tagged configurations supported by this script. +available_tags="" + +# ### BEGIN LIBTOOL CONFIG + +# Which release of libtool.m4 was used? +macro_version=$macro_version +macro_revision=$macro_revision + +# Whether or not to build shared libraries. +build_libtool_libs=$enable_shared + +# Whether or not to build static libraries. +build_old_libs=$enable_static + +# What type of objects to build. +pic_mode=$pic_mode + +# Whether or not to optimize for fast installation. +fast_install=$enable_fast_install + +# Shell to use when invoking shell scripts. +SHELL=$lt_SHELL + +# An echo program that protects backslashes. +ECHO=$lt_ECHO + +# The PATH separator for the build system. +PATH_SEPARATOR=$lt_PATH_SEPARATOR + +# The host system. +host_alias=$host_alias +host=$host +host_os=$host_os + +# The build system. +build_alias=$build_alias +build=$build +build_os=$build_os + +# A sed program that does not truncate output. +SED=$lt_SED + +# Sed that helps us avoid accidentally triggering echo(1) options like -n. +Xsed="\$SED -e 1s/^X//" + +# A grep program that handles long lines. +GREP=$lt_GREP + +# An ERE matcher. +EGREP=$lt_EGREP + +# A literal string matcher. +FGREP=$lt_FGREP + +# A BSD- or MS-compatible name lister. +NM=$lt_NM + +# Whether we need soft or hard links. +LN_S=$lt_LN_S + +# What is the maximum length of a command? +max_cmd_len=$max_cmd_len + +# Object file suffix (normally "o"). +objext=$ac_objext + +# Executable file suffix (normally ""). +exeext=$exeext + +# whether the shell understands "unset". +lt_unset=$lt_unset + +# turn spaces into newlines. +SP2NL=$lt_lt_SP2NL + +# turn newlines into spaces. +NL2SP=$lt_lt_NL2SP + +# convert \$build file names to \$host format. +to_host_file_cmd=$lt_cv_to_host_file_cmd + +# convert \$build files to toolchain format. +to_tool_file_cmd=$lt_cv_to_tool_file_cmd + +# An object symbol dumper. +OBJDUMP=$lt_OBJDUMP + +# Method to check whether dependent libraries are shared objects. +deplibs_check_method=$lt_deplibs_check_method + +# Command to use when deplibs_check_method = "file_magic". +file_magic_cmd=$lt_file_magic_cmd + +# How to find potential files when deplibs_check_method = "file_magic". +file_magic_glob=$lt_file_magic_glob + +# Find potential files using nocaseglob when deplibs_check_method = "file_magic". +want_nocaseglob=$lt_want_nocaseglob + +# DLL creation program. +DLLTOOL=$lt_DLLTOOL + +# Command to associate shared and link libraries. +sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd + +# The archiver. +AR=$lt_AR + +# Flags to create an archive. +AR_FLAGS=$lt_AR_FLAGS + +# How to feed a file listing to the archiver. +archiver_list_spec=$lt_archiver_list_spec + +# A symbol stripping program. +STRIP=$lt_STRIP + +# Commands used to install an old-style archive. +RANLIB=$lt_RANLIB +old_postinstall_cmds=$lt_old_postinstall_cmds +old_postuninstall_cmds=$lt_old_postuninstall_cmds + +# Whether to use a lock for old archive extraction. +lock_old_archive_extraction=$lock_old_archive_extraction + +# A C compiler. +LTCC=$lt_CC + +# LTCC compiler flags. +LTCFLAGS=$lt_CFLAGS + +# Take the output of nm and produce a listing of raw symbols and C names. +global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe + +# Transform the output of nm in a proper C declaration. +global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl + +# Transform the output of nm in a C name address pair. +global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address + +# Transform the output of nm in a C name address pair when lib prefix is needed. +global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix + +# Specify filename containing input files for \$NM. +nm_file_list_spec=$lt_nm_file_list_spec + +# The root where to search for dependent libraries,and in which our libraries should be installed. +lt_sysroot=$lt_sysroot + +# The name of the directory that contains temporary libtool files. +objdir=$objdir + +# Used to examine libraries when file_magic_cmd begins with "file". +MAGIC_CMD=$MAGIC_CMD + +# Must we lock files when doing compilation? +need_locks=$lt_need_locks + +# Manifest tool. +MANIFEST_TOOL=$lt_MANIFEST_TOOL + +# Tool to manipulate archived DWARF debug symbol files on Mac OS X. +DSYMUTIL=$lt_DSYMUTIL + +# Tool to change global to local symbols on Mac OS X. +NMEDIT=$lt_NMEDIT + +# Tool to manipulate fat objects and archives on Mac OS X. +LIPO=$lt_LIPO + +# ldd/readelf like tool for Mach-O binaries on Mac OS X. +OTOOL=$lt_OTOOL + +# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. +OTOOL64=$lt_OTOOL64 + +# Old archive suffix (normally "a"). +libext=$libext + +# Shared library suffix (normally ".so"). +shrext_cmds=$lt_shrext_cmds + +# The commands to extract the exported symbol list from a shared archive. +extract_expsyms_cmds=$lt_extract_expsyms_cmds + +# Variables whose values should be saved in libtool wrapper scripts and +# restored at link time. +variables_saved_for_relink=$lt_variables_saved_for_relink + +# Do we need the "lib" prefix for modules? +need_lib_prefix=$need_lib_prefix + +# Do we need a version for libraries? +need_version=$need_version + +# Library versioning type. +version_type=$version_type + +# Shared library runtime path variable. +runpath_var=$runpath_var + +# Shared library path variable. +shlibpath_var=$shlibpath_var + +# Is shlibpath searched before the hard-coded library search path? +shlibpath_overrides_runpath=$shlibpath_overrides_runpath + +# Format of library name prefix. +libname_spec=$lt_libname_spec + +# List of archive names. First name is the real one, the rest are links. +# The last name is the one that the linker finds with -lNAME +library_names_spec=$lt_library_names_spec + +# The coded name of the library, if different from the real name. +soname_spec=$lt_soname_spec + +# Permission mode override for installation of shared libraries. +install_override_mode=$lt_install_override_mode + +# Command to use after installation of a shared archive. +postinstall_cmds=$lt_postinstall_cmds + +# Command to use after uninstallation of a shared archive. +postuninstall_cmds=$lt_postuninstall_cmds + +# Commands used to finish a libtool library installation in a directory. +finish_cmds=$lt_finish_cmds + +# As "finish_cmds", except a single script fragment to be evaled but +# not shown. +finish_eval=$lt_finish_eval + +# Whether we should hardcode library paths into libraries. +hardcode_into_libs=$hardcode_into_libs + +# Compile-time system search path for libraries. +sys_lib_search_path_spec=$lt_sys_lib_search_path_spec + +# Run-time system search path for libraries. +sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec + +# Whether dlopen is supported. +dlopen_support=$enable_dlopen + +# Whether dlopen of programs is supported. +dlopen_self=$enable_dlopen_self + +# Whether dlopen of statically linked programs is supported. +dlopen_self_static=$enable_dlopen_self_static + +# Commands to strip libraries. +old_striplib=$lt_old_striplib +striplib=$lt_striplib + + +# The linker used to build libraries. +LD=$lt_LD + +# How to create reloadable object files. +reload_flag=$lt_reload_flag +reload_cmds=$lt_reload_cmds + +# Commands used to build an old-style archive. +old_archive_cmds=$lt_old_archive_cmds + +# A language specific compiler. +CC=$lt_compiler + +# Is the compiler the GNU compiler? +with_gcc=$GCC + +# Compiler flag to turn off builtin functions. +no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag + +# Additional compiler flags for building library objects. +pic_flag=$lt_lt_prog_compiler_pic + +# How to pass a linker flag through the compiler. +wl=$lt_lt_prog_compiler_wl + +# Compiler flag to prevent dynamic linking. +link_static_flag=$lt_lt_prog_compiler_static + +# Does compiler simultaneously support -c and -o options? +compiler_c_o=$lt_lt_cv_prog_compiler_c_o + +# Whether or not to add -lc for building shared libraries. +build_libtool_need_lc=$archive_cmds_need_lc + +# Whether or not to disallow shared libs when runtime libs are static. +allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes + +# Compiler flag to allow reflexive dlopens. +export_dynamic_flag_spec=$lt_export_dynamic_flag_spec + +# Compiler flag to generate shared objects directly from archives. +whole_archive_flag_spec=$lt_whole_archive_flag_spec + +# Whether the compiler copes with passing no objects directly. +compiler_needs_object=$lt_compiler_needs_object + +# Create an old-style archive from a shared archive. +old_archive_from_new_cmds=$lt_old_archive_from_new_cmds + +# Create a temporary old-style archive to link instead of a shared archive. +old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds + +# Commands used to build a shared archive. +archive_cmds=$lt_archive_cmds +archive_expsym_cmds=$lt_archive_expsym_cmds + +# Commands used to build a loadable module if different from building +# a shared archive. +module_cmds=$lt_module_cmds +module_expsym_cmds=$lt_module_expsym_cmds + +# Whether we are building with GNU ld or not. +with_gnu_ld=$lt_with_gnu_ld + +# Flag that allows shared libraries with undefined symbols to be built. +allow_undefined_flag=$lt_allow_undefined_flag + +# Flag that enforces no undefined symbols. +no_undefined_flag=$lt_no_undefined_flag + +# Flag to hardcode \$libdir into a binary during linking. +# This must work even if \$libdir does not exist +hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec + +# Whether we need a single "-rpath" flag with a separated argument. +hardcode_libdir_separator=$lt_hardcode_libdir_separator + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary. +hardcode_direct=$hardcode_direct + +# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes +# DIR into the resulting binary and the resulting library dependency is +# "absolute",i.e impossible to change by setting \${shlibpath_var} if the +# library is relocated. +hardcode_direct_absolute=$hardcode_direct_absolute + +# Set to "yes" if using the -LDIR flag during linking hardcodes DIR +# into the resulting binary. +hardcode_minus_L=$hardcode_minus_L + +# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR +# into the resulting binary. +hardcode_shlibpath_var=$hardcode_shlibpath_var + +# Set to "yes" if building a shared library automatically hardcodes DIR +# into the library and all subsequent libraries and executables linked +# against it. +hardcode_automatic=$hardcode_automatic + +# Set to yes if linker adds runtime paths of dependent libraries +# to runtime path list. +inherit_rpath=$inherit_rpath + +# Whether libtool must link a program against all its dependency libraries. +link_all_deplibs=$link_all_deplibs + +# Set to "yes" if exported symbols are required. +always_export_symbols=$always_export_symbols + +# The commands to list exported symbols. +export_symbols_cmds=$lt_export_symbols_cmds + +# Symbols that should not be listed in the preloaded symbols. +exclude_expsyms=$lt_exclude_expsyms + +# Symbols that must always be exported. +include_expsyms=$lt_include_expsyms + +# Commands necessary for linking programs (against libraries) with templates. +prelink_cmds=$lt_prelink_cmds + +# Commands necessary for finishing linking programs. +postlink_cmds=$lt_postlink_cmds + +# Specify filename containing input files. +file_list_spec=$lt_file_list_spec + +# How to hardcode a shared library path into an executable. +hardcode_action=$hardcode_action + +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + +ltmain="$ac_aux_dir/ltmain.sh" + + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + if test x"$xsi_shell" = xyes; then + sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ +func_dirname ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_basename ()$/,/^} # func_basename /c\ +func_basename ()\ +{\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ +func_dirname_and_basename ()\ +{\ +\ case ${1} in\ +\ */*) func_dirname_result="${1%/*}${2}" ;;\ +\ * ) func_dirname_result="${3}" ;;\ +\ esac\ +\ func_basename_result="${1##*/}"\ +} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ +func_stripname ()\ +{\ +\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ +\ # positional parameters, so assign one to ordinary parameter first.\ +\ func_stripname_result=${3}\ +\ func_stripname_result=${func_stripname_result#"${1}"}\ +\ func_stripname_result=${func_stripname_result%"${2}"}\ +} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ +func_split_long_opt ()\ +{\ +\ func_split_long_opt_name=${1%%=*}\ +\ func_split_long_opt_arg=${1#*=}\ +} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ +func_split_short_opt ()\ +{\ +\ func_split_short_opt_arg=${1#??}\ +\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ +} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ +func_lo2o ()\ +{\ +\ case ${1} in\ +\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ +\ *) func_lo2o_result=${1} ;;\ +\ esac\ +} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_xform ()$/,/^} # func_xform /c\ +func_xform ()\ +{\ + func_xform_result=${1%.*}.lo\ +} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_arith ()$/,/^} # func_arith /c\ +func_arith ()\ +{\ + func_arith_result=$(( $* ))\ +} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_len ()$/,/^} # func_len /c\ +func_len ()\ +{\ + func_len_result=${#1}\ +} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + +fi + +if test x"$lt_shell_append" = xyes; then + sed -e '/^func_append ()$/,/^} # func_append /c\ +func_append ()\ +{\ + eval "${1}+=\\${2}"\ +} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ +func_append_quoted ()\ +{\ +\ func_quote_for_eval "${2}"\ +\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ +} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: + + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 +$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} +fi + + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" + + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit 1 +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + + +echo "CFLAGS=$CFLAGS" +echo "LDFLAGS=$LDFLAGS" diff --git a/configure.in b/configure.in new file mode 100644 index 00000000..1ae1584d --- /dev/null +++ b/configure.in @@ -0,0 +1,114 @@ +# +# configure.in +# +# See the LICENSE file for the license associated with this file. + +AC_INIT([libtpms], [0.5.1]) +AC_PREREQ(2.12) +AC_CONFIG_SRCDIR(Makefile.am) +AM_CONFIG_HEADER(config.h) + +AC_CONFIG_MACRO_DIR([m4]) +AC_CANONICAL_TARGET +AM_INIT_AUTOMAKE([foreign 1.6]) + +LIBTPMS_VER_MAJOR=`echo $PACKAGE_VERSION | awk -F. '{print $1}'` +LIBTPMS_VER_MINOR=`echo $PACKAGE_VERSION | awk -F. '{print $2}'` +LIBTPMS_VER_MICRO=`echo $PACKAGE_VERSION | awk -F. '{print $3}'` +LIBTPMS_VERSION=$PACKAGE_VERSION +LIBTPMS_VERSION_INFO=`expr $LIBTPMS_VER_MAJOR + $LIBTPMS_VER_MINOR`:$LIBTPMS_VER_MICRO:$LIBTPMS_VER_MINOR + +AC_SUBST([LIBTPMS_VER_MAJOR]) +AC_SUBST([LIBTPMS_VER_MINOR]) +AC_SUBST([LIBTPMS_VER_MICRO]) +AC_SUBST([LIBTPMS_VERSION]) +AC_SUBST([LIBTPMS_VERSION_INFO]) + +DEBUG="" +AC_MSG_CHECKING([for debug-enabled build]) +AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [create a debug build]), + [if test "$enableval" = "yes"; then + DEBUG="yes" + AC_MSG_RESULT([yes]) + else + DEBUG="no" + AC_MSG_RESULT([no]) + fi], + [DEBUG="no", + AC_MSG_RESULT([no])]) + +# If the user has not set CFLAGS, do something appropriate +test_CFLAGS=${CFLAGS+set} +if test "$test_CFLAGS" != set; then + if test "$DEBUG" == "yes"; then + CFLAGS="-O0 -g -DDEBUG" + else + CFLAGS="-g -O2" + fi +elif test "$DEBUG" == "yes"; then + CFLAGS="$CFLAGS -O0 -g -DDEBUG" +fi + +debug_defines= +if test "$DEBUG" == "yes"; then + debug_defines="-DTPM_DEBUG -DTPM_VOLATILE_STORE" +fi +AC_SUBST(DEBUG_DEFINES, $debug_defines) + +cryptolib=freebl + +AC_ARG_WITH([openssl], + AC_HELP_STRING([--with-openssl], + [build libtpms with openssl library]), + [AC_CHECK_LIB(crypto, + [AES_set_encrypt_key], + [], + AC_MSG_ERROR(Faulty openssl crypto library)) + AC_CHECK_HEADERS([openssl/aes.h]) + AC_MSG_RESULT([Building with openssl crypto library]) + cryptolib=openssl + ] +) + +case "$cryptolib" in +freebl) + AM_CONDITIONAL(LIBTPMS_USE_FREEBL, true) + AM_CONDITIONAL(LIBTPMS_USE_OPENSSL, false) + ;; +openssl) + AM_CONDITIONAL(LIBTPMS_USE_FREEBL, false) + AM_CONDITIONAL(LIBTPMS_USE_OPENSSL, true) + ;; +esac + +AC_PROG_CC +AC_PROG_INSTALL +AC_PROG_LIBTOOL + +#AM_GNU_GETTEXT_VERSION([0.15]) +#AM_GNU_GETTEXT([external]) + +AC_HEADER_STDC +AC_C_CONST +AC_C_INLINE + +AC_TYPE_SIZE_T + + +CFLAGS="$CFLAGS -Wall -Werror -Wreturn-type -Wsign-compare" + +AC_CONFIG_FILES(Makefile \ + dist/libtpms.spec \ + include/Makefile \ + include/libtpms/Makefile \ + include/libtpms/tpm_library.h \ + m4/Makefile \ + man/Makefile \ + man/man3/Makefile \ + src/Makefile \ + libtpms.pc \ + tests/Makefile) +AC_OUTPUT + +echo "CFLAGS=$CFLAGS" +echo "LDFLAGS=$LDFLAGS" diff --git a/depcomp b/depcomp new file mode 100755 index 00000000..25a39e6c --- /dev/null +++ b/depcomp @@ -0,0 +1,708 @@ +#! /bin/sh +# depcomp - compile a program generating dependencies as side-effects + +scriptversion=2012-03-27.16; # UTC + +# Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, +# 2011, 2012 Free Software Foundation, Inc. + +# 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, 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, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +# Originally written by Alexandre Oliva . + +case $1 in + '') + echo "$0: No command. Try '$0 --help' for more information." 1>&2 + exit 1; + ;; + -h | --h*) + cat <<\EOF +Usage: depcomp [--help] [--version] PROGRAM [ARGS] + +Run PROGRAMS ARGS to compile a file, generating dependencies +as side-effects. + +Environment variables: + depmode Dependency tracking mode. + source Source file read by 'PROGRAMS ARGS'. + object Object file output by 'PROGRAMS ARGS'. + DEPDIR directory where to store dependencies. + depfile Dependency file to output. + tmpdepfile Temporary file to use when outputting dependencies. + libtool Whether libtool is used (yes/no). + +Report bugs to . +EOF + exit $? + ;; + -v | --v*) + echo "depcomp $scriptversion" + exit $? + ;; +esac + +# A tabulation character. +tab=' ' +# A newline character. +nl=' +' + +if test -z "$depmode" || test -z "$source" || test -z "$object"; then + echo "depcomp: Variables source, object and depmode must be set" 1>&2 + exit 1 +fi + +# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. +depfile=${depfile-`echo "$object" | + sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} +tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} + +rm -f "$tmpdepfile" + +# Some modes work just like other modes, but use different flags. We +# parameterize here, but still list the modes in the big case below, +# to make depend.m4 easier to write. Note that we *cannot* use a case +# here, because this file can only contain one case statement. +if test "$depmode" = hp; then + # HP compiler uses -M and no extra arg. + gccflag=-M + depmode=gcc +fi + +if test "$depmode" = dashXmstdout; then + # This is just like dashmstdout with a different argument. + dashmflag=-xM + depmode=dashmstdout +fi + +cygpath_u="cygpath -u -f -" +if test "$depmode" = msvcmsys; then + # This is just like msvisualcpp but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvisualcpp +fi + +if test "$depmode" = msvc7msys; then + # This is just like msvc7 but w/o cygpath translation. + # Just convert the backslash-escaped backslashes to single forward + # slashes to satisfy depend.m4 + cygpath_u='sed s,\\\\,/,g' + depmode=msvc7 +fi + +if test "$depmode" = xlc; then + # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations. + gccflag=-qmakedep=gcc,-MF + depmode=gcc +fi + +case "$depmode" in +gcc3) +## gcc 3 implements dependency tracking that does exactly what +## we want. Yay! Note: for some reason libtool 1.4 doesn't like +## it if -MD -MP comes after the -MF stuff. Hmm. +## Unfortunately, FreeBSD c89 acceptance of flags depends upon +## the command line argument order; so add the flags where they +## appear in depend2.am. Note that the slowdown incurred here +## affects only configure: in makefiles, %FASTDEP% shortcuts this. + for arg + do + case $arg in + -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; + *) set fnord "$@" "$arg" ;; + esac + shift # fnord + shift # $arg + done + "$@" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + mv "$tmpdepfile" "$depfile" + ;; + +gcc) +## There are various ways to get dependency output from gcc. Here's +## why we pick this rather obscure method: +## - Don't want to use -MD because we'd like the dependencies to end +## up in a subdir. Having to rename by hand is ugly. +## (We might end up doing this anyway to support other compilers.) +## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like +## -MM, not -M (despite what the docs say). +## - Using -M directly means running the compiler twice (even worse +## than renaming). + if test -z "$gccflag"; then + gccflag=-MD, + fi + "$@" -Wp,"$gccflag$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +## The second -e expression handles DOS-style file names with drive letters. + sed -e 's/^[^:]*: / /' \ + -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" +## This next piece of magic avoids the "deleted header file" problem. +## The problem is that when a header file which appears in a .P file +## is deleted, the dependency causes make to die (because there is +## typically no way to rebuild the header). We avoid this by adding +## dummy dependencies for each header file. Too bad gcc doesn't do +## this for us directly. + tr ' ' "$nl" < "$tmpdepfile" | +## Some versions of gcc put a space before the ':'. On the theory +## that the space means something, we add a space to the output as +## well. hp depmode also adds that space, but also prefixes the VPATH +## to the object. Take care to not repeat it in the output. +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ + | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +sgi) + if test "$libtool" = yes; then + "$@" "-Wp,-MDupdate,$tmpdepfile" + else + "$@" -MDupdate "$tmpdepfile" + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + + if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files + echo "$object : \\" > "$depfile" + + # Clip off the initial element (the dependent). Don't try to be + # clever and replace this with sed code, as IRIX sed won't handle + # lines with more than a fixed number of characters (4096 in + # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; + # the IRIX cc adds comments like '#:fec' to the end of the + # dependency line. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ + tr "$nl" ' ' >> "$depfile" + echo >> "$depfile" + + # The second pass generates a dummy entry for each header file. + tr ' ' "$nl" < "$tmpdepfile" \ + | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ + >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +xlc) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +aix) + # The C for AIX Compiler uses -M and outputs the dependencies + # in a .u file. In older versions, this file always lives in the + # current directory. Also, the AIX compiler puts '$object:' at the + # start of each line; $object doesn't have directory information. + # Version 6 uses the directory in both cases. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.u + tmpdepfile2=$base.u + tmpdepfile3=$dir.libs/$base.u + "$@" -Wc,-M + else + tmpdepfile1=$dir$base.u + tmpdepfile2=$dir$base.u + tmpdepfile3=$dir$base.u + "$@" -M + fi + stat=$? + + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + # Each line is of the form 'foo.o: dependent.h'. + # Do two passes, one to just change these to + # '$object: dependent.h' and one to simply 'dependent.h:'. + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + # The sourcefile does not contain any dependencies, so just + # store a dummy comment line, to avoid errors with the Makefile + # "include basename.Plo" scheme. + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +icc) + # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'. + # However on + # $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c + # ICC 7.0 will fill foo.d with something like + # foo.o: sub/foo.c + # foo.o: sub/foo.h + # which is wrong. We want + # sub/foo.o: sub/foo.c + # sub/foo.o: sub/foo.h + # sub/foo.c: + # sub/foo.h: + # ICC 7.1 will output + # foo.o: sub/foo.c sub/foo.h + # and will wrap long lines using '\': + # foo.o: sub/foo.c ... \ + # sub/foo.h ... \ + # ... + # tcc 0.9.26 (FIXME still under development at the moment of writing) + # will emit a similar output, but also prepend the continuation lines + # with horizontal tabulation characters. + "$@" -MD -MF "$tmpdepfile" + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + # Each line is of the form 'foo.o: dependent.h', + # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'. + # Do two passes, one to just change these to + # '$object: dependent.h' and one to simply 'dependent.h:'. + sed -e "s/^[ $tab][ $tab]*/ /" -e "s,^[^:]*:,$object :," \ + < "$tmpdepfile" > "$depfile" + sed ' + s/[ '"$tab"'][ '"$tab"']*/ /g + s/^ *// + s/ *\\*$// + s/^[^:]*: *// + /^$/d + /:$/d + s/$/ :/ + ' < "$tmpdepfile" >> "$depfile" + rm -f "$tmpdepfile" + ;; + +hp2) + # The "hp" stanza above does not work with aCC (C++) and HP's ia64 + # compilers, which have integrated preprocessors. The correct option + # to use with these is +Maked; it writes dependencies to a file named + # 'foo.d', which lands next to the object file, wherever that + # happens to be. + # Much of this is similar to the tru64 case; see comments there. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + if test "$libtool" = yes; then + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir.libs/$base.d + "$@" -Wc,+Maked + else + tmpdepfile1=$dir$base.d + tmpdepfile2=$dir$base.d + "$@" +Maked + fi + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" + # Add 'dependent.h:' lines. + sed -ne '2,${ + s/^ *// + s/ \\*$// + s/$/:/ + p + }' "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" "$tmpdepfile2" + ;; + +tru64) + # The Tru64 compiler uses -MD to generate dependencies as a side + # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. + # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put + # dependencies in 'foo.d' instead, so we check for that too. + # Subdirectories are respected. + dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` + test "x$dir" = "x$object" && dir= + base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` + + if test "$libtool" = yes; then + # With Tru64 cc, shared objects can also be used to make a + # static library. This mechanism is used in libtool 1.4 series to + # handle both shared and static libraries in a single compilation. + # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. + # + # With libtool 1.5 this exception was removed, and libtool now + # generates 2 separate objects for the 2 libraries. These two + # compilations output dependencies in $dir.libs/$base.o.d and + # in $dir$base.o.d. We have to check for both files, because + # one of the two compilations can be disabled. We should prefer + # $dir$base.o.d over $dir.libs/$base.o.d because the latter is + # automatically cleaned when .libs/ is deleted, while ignoring + # the former would cause a distcleancheck panic. + tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 + tmpdepfile2=$dir$base.o.d # libtool 1.5 + tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 + tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 + "$@" -Wc,-MD + else + tmpdepfile1=$dir$base.o.d + tmpdepfile2=$dir$base.d + tmpdepfile3=$dir$base.d + tmpdepfile4=$dir$base.d + "$@" -MD + fi + + stat=$? + if test $stat -eq 0; then : + else + rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + exit $stat + fi + + for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" + do + test -f "$tmpdepfile" && break + done + if test -f "$tmpdepfile"; then + sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" + sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" + else + echo "#dummy" > "$depfile" + fi + rm -f "$tmpdepfile" + ;; + +msvc7) + if test "$libtool" = yes; then + showIncludes=-Wc,-showIncludes + else + showIncludes=-showIncludes + fi + "$@" $showIncludes > "$tmpdepfile" + stat=$? + grep -v '^Note: including file: ' "$tmpdepfile" + if test "$stat" = 0; then : + else + rm -f "$tmpdepfile" + exit $stat + fi + rm -f "$depfile" + echo "$object : \\" > "$depfile" + # The first sed program below extracts the file names and escapes + # backslashes for cygpath. The second sed program outputs the file + # name when reading, but also accumulates all include files in the + # hold buffer in order to output them again at the end. This only + # works with sed implementations that can handle large buffers. + sed < "$tmpdepfile" -n ' +/^Note: including file: *\(.*\)/ { + s//\1/ + s/\\/\\\\/g + p +}' | $cygpath_u | sort -u | sed -n ' +s/ /\\ /g +s/\(.*\)/'"$tab"'\1 \\/p +s/.\(.*\) \\/\1:/ +H +$ { + s/.*/'"$tab"'/ + G + p +}' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvc7msys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +#nosideeffect) + # This comment above is used by automake to tell side-effect + # dependency tracking mechanisms from slower ones. + +dashmstdout) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout, regardless of -o. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + test -z "$dashmflag" && dashmflag=-M + # Require at least two characters before searching for ':' + # in the target name. This is to cope with DOS-style filenames: + # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. + "$@" $dashmflag | + sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile" + rm -f "$depfile" + cat < "$tmpdepfile" > "$depfile" + tr ' ' "$nl" < "$tmpdepfile" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +dashXmstdout) + # This case only exists to satisfy depend.m4. It is never actually + # run, as this mode is specially recognized in the preamble. + exit 1 + ;; + +makedepend) + "$@" || exit $? + # Remove any Libtool call + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + # X makedepend + shift + cleared=no eat=no + for arg + do + case $cleared in + no) + set ""; shift + cleared=yes ;; + esac + if test $eat = yes; then + eat=no + continue + fi + case "$arg" in + -D*|-I*) + set fnord "$@" "$arg"; shift ;; + # Strip any option that makedepend may not understand. Remove + # the object too, otherwise makedepend will parse it as a source file. + -arch) + eat=yes ;; + -*|$object) + ;; + *) + set fnord "$@" "$arg"; shift ;; + esac + done + obj_suffix=`echo "$object" | sed 's/^.*\././'` + touch "$tmpdepfile" + ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" + rm -f "$depfile" + # makedepend may prepend the VPATH from the source file name to the object. + # No need to regex-escape $object, excess matching of '.' is harmless. + sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" + sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \ +## Some versions of the HPUX 10.20 sed can't process this invocation +## correctly. Breaking it into two sed invocations is a workaround. + sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" "$tmpdepfile".bak + ;; + +cpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + # Remove '-o $object'. + IFS=" " + for arg + do + case $arg in + -o) + shift + ;; + $object) + shift + ;; + *) + set fnord "$@" "$arg" + shift # fnord + shift # $arg + ;; + esac + done + + "$@" -E | + sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ + -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | + sed '$ s: \\$::' > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + cat < "$tmpdepfile" >> "$depfile" + sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvisualcpp) + # Important note: in order to support this mode, a compiler *must* + # always write the preprocessed file to stdout. + "$@" || exit $? + + # Remove the call to Libtool. + if test "$libtool" = yes; then + while test "X$1" != 'X--mode=compile'; do + shift + done + shift + fi + + IFS=" " + for arg + do + case "$arg" in + -o) + shift + ;; + $object) + shift + ;; + "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") + set fnord "$@" + shift + shift + ;; + *) + set fnord "$@" "$arg" + shift + shift + ;; + esac + done + "$@" -E 2>/dev/null | + sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" + rm -f "$depfile" + echo "$object : \\" > "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" + echo "$tab" >> "$depfile" + sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" + rm -f "$tmpdepfile" + ;; + +msvcmsys) + # This case exists only to let depend.m4 do its work. It works by + # looking at the text of this script. This case will never be run, + # since it is checked for above. + exit 1 + ;; + +none) + exec "$@" + ;; + +*) + echo "Unknown depmode $depmode" 1>&2 + exit 1 + ;; +esac + +exit 0 + +# Local Variables: +# mode: shell-script +# sh-indentation: 2 +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/dist/libtpms.spec.in b/dist/libtpms.spec.in new file mode 100644 index 00000000..e743a96b --- /dev/null +++ b/dist/libtpms.spec.in @@ -0,0 +1,166 @@ +# --- libtpm rpm-spec --- + +%define name @PACKAGE@ +%define version @VERSION@ +%define release 14 + +# Valid crypto subsystems are 'freebl' and 'openssl' +%define crypto_subsystem freebl + +# Valid build types are 'production' or 'debug' +%define build_type production + +Summary: Library providing Trusted Platform Module (TPM) functionality +Name: %{name} +Version: %{version} +Release: %{release} +License: BSD +Group: Development/Libraries +Url: http://sourceforge.net/projects/ibmswtpm +Source: http://bergerstefan.users.sourceforge.net/libtpms/%{name}-%{version}.tar.gz +BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root +%if %{crypto_subsystem} == openssl +BuildRequires: openssl-devel +%else +BuildRequires: nss-devel >= 3.12.9-2 +BuildRequires: nss-softokn-freebl-devel >= 3.12.9-2 +BuildRequires: nss-softokn-freebl-static >= 3.12.9-2 +BuildRequires: nss-softokn-devel >= 3.12.9-2, gmp-devel +BuildRequires: pkgconfig gawk +Requires: nss-softokn-freebl >= 3.12.9-2, nss-softokn >= 3.12.9-2 +%endif + +%description +A library providing TPM functionality for VMs. Targeted for integration +into Qemu. + +%package devel +Summary: Include files for libtpms +Group: Development/Libraries +Requires: %{name}%{?_isa} = %{version}-%{release} + +%description devel +Libtpms header files and documentation. + +%files +%defattr(-, root, root, -) +%{_libdir}/%{name}.la +%{_libdir}/%{name}.so.%{version} +%{_libdir}/%{name}.so.0 +%doc LICENSE README CHANGES + +%files devel +%defattr(-, root, root, -) + +%{_libdir}/%{name}.so +%dir %{_includedir}/%{name} +%attr(644, root, root) %{_libdir}/pkgconfig/*.pc +%attr(644, root, root) %{_includedir}/%{name}/*.h +%attr(644, root, root) %{_mandir}/man3/* + +%prep +%setup -q + +%build + +%if %{crypto_subsystem} == openssl +%define _with_openssl --with-openssl +%endif + +%if %{build_type} == debug +%define _enable_debug --enable-debug +%endif + +%configure \ + --disable-static \ + --prefix=/usr \ + --libdir=%{_libdir} \ + %{?_with_openssl} \ + %{?_enable_debug} + +make %{?_smp_mflags} +make check + +%install +install -d -m 0755 $RPM_BUILD_ROOT%{_libdir} +install -d -m 0755 $RPM_BUILD_ROOT%{_includedir}/libtpms +install -d -m 0755 $RPM_BUILD_ROOT%{_mandir}/man3 + +make %{?_smp_mflags} install DESTDIR=${RPM_BUILD_ROOT} + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%changelog +* Fri Jan 27 2012 Stefan Berger - 0.5.1-14 +- fix gcc-4.7 compilation problem + +* Fri Jan 13 2012 Fedora Release Engineering - 0.5.1-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Tue Dec 20 2011 Dan Horák - 0.5.1-12 +- fix build on secondary arches + +* Wed Nov 2 2011 Stefan Berger - 0.5.1-11 +- added (lib)gmp as runtime dependency + +* Tue Oct 8 2011 Stefan Berger - 0.5.1-10 +- internal fixes; callback fixes + +* Tue Aug 30 2011 Stefan Berger - 0.5.1-9 +- new directory structure and build process + +* Tue Jul 12 2011 Stefan Berger - 0.5.1-8 +- added pkgconfig as build dependency +- enabling __powerpc__ build following Bz 728220 + +* Wed May 25 2011 Stefan Berger - 0.5.1-7 +- increasing NVRAM area space to have enough room for certificates + +* Wed May 25 2011 Stefan Berger - 0.5.1-6 +- adding libtpms.pc pkg-config file + +* Wed Apr 13 2011 Stefan Berger - 0.5.1-5 +- adding BuildRequires for nss-softokn-freebl-static +- several libtpms-internal changes around state serialization and + deserialization +- fixes to libtpms makefile (makefile-libtpms) +- adding build_type to generate a debug or production build +- need nss-devel to have nss-config + +* Tue Mar 08 2011 Stefan Berger - 0.5.1-4 +- small fixes to libtpms makefile + +* Fri Feb 25 2011 Stefan Berger - 0.5.1-3 +- removing release from tar ball name +- Use {?_smp_mflags} for make rather than hardcoding it +- Fixing post and postun scripts; removing the scripts for devel package +- Fixing usage of defattr +- Adding version information into the changelog headers and spaces between the changelog entries +- Adding LICENSE, README and CHANGELOG file into tar ball and main rpm +- Removing clean section +- removed command to clean the build root +- adding library version to the libries required for building and during + runtime +- Extended Requires in devel package with {?_isa} + +* Fri Feb 18 2011 Stefan Berger - 0.5.1-2 +- make rpmlint happy by replacing tabs with spaces +- providing a valid URL for the tgz file +- release is now 2 -> 0.5.1-2 + +* Mon Jan 17 2011 Stefan Berger - 0.5.1-1 +- Update version to 0.5.1 + +* Fri Jan 14 2011 Stefan Berger - 0.5.0-1 +- Changes following Fedora review comments + +* Tue Dec 02 2010 Stefan Berger +- Small tweaks after reading the FedoreCore packaging requirements + +* Tue Nov 16 2010 Stefan Berger +- Created initial version of rpm spec files +- Version of library is now 0.5.0 +- Debuginfo rpm is built but empty -- seems to be a known problem + Check https://bugzilla.redhat.com/show_bug.cgi?id=209316 diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 00000000..6d968647 --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,7 @@ +# +# include/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# + +SUBDIRS = libtpms diff --git a/include/Makefile.in b/include/Makefile.in new file mode 100644 index 00000000..ddb787c4 --- /dev/null +++ b/include/Makefile.in @@ -0,0 +1,596 @@ +# Makefile.in generated by automake 1.11.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# include/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = include +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUG_DEFINES = @DEBUG_DEFINES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTPMS_VERSION = @LIBTPMS_VERSION@ +LIBTPMS_VERSION_INFO = @LIBTPMS_VERSION_INFO@ +LIBTPMS_VER_MAJOR = @LIBTPMS_VER_MAJOR@ +LIBTPMS_VER_MICRO = @LIBTPMS_VER_MICRO@ +LIBTPMS_VER_MINOR = @LIBTPMS_VER_MINOR@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = libtpms +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign include/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/include/libtpms/Makefile.am b/include/libtpms/Makefile.am new file mode 100644 index 00000000..eb14c36b --- /dev/null +++ b/include/libtpms/Makefile.am @@ -0,0 +1,15 @@ +# +# include/libtpms/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# + +libtpmsincludedir = $(includedir)/libtpms + +libtpmsinclude_HEADERS = \ + tpm_error.h \ + tpm_library.h \ + tpm_memory.h \ + tpm_nvfilename.h \ + tpm_tis.h \ + tpm_types.h diff --git a/include/libtpms/Makefile.in b/include/libtpms/Makefile.in new file mode 100644 index 00000000..290017e9 --- /dev/null +++ b/include/libtpms/Makefile.in @@ -0,0 +1,512 @@ +# Makefile.in generated by automake 1.11.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# include/libtpms/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# + +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = include/libtpms +DIST_COMMON = $(libtpmsinclude_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(srcdir)/tpm_library.h.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = tpm_library.h +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libtpmsincludedir)" +HEADERS = $(libtpmsinclude_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUG_DEFINES = @DEBUG_DEFINES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTPMS_VERSION = @LIBTPMS_VERSION@ +LIBTPMS_VERSION_INFO = @LIBTPMS_VERSION_INFO@ +LIBTPMS_VER_MAJOR = @LIBTPMS_VER_MAJOR@ +LIBTPMS_VER_MICRO = @LIBTPMS_VER_MICRO@ +LIBTPMS_VER_MINOR = @LIBTPMS_VER_MINOR@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +libtpmsincludedir = $(includedir)/libtpms +libtpmsinclude_HEADERS = \ + tpm_error.h \ + tpm_library.h \ + tpm_memory.h \ + tpm_nvfilename.h \ + tpm_tis.h \ + tpm_types.h + +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/libtpms/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign include/libtpms/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +tpm_library.h: $(top_builddir)/config.status $(srcdir)/tpm_library.h.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-libtpmsincludeHEADERS: $(libtpmsinclude_HEADERS) + @$(NORMAL_INSTALL) + @list='$(libtpmsinclude_HEADERS)'; test -n "$(libtpmsincludedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(libtpmsincludedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libtpmsincludedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libtpmsincludedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(libtpmsincludedir)" || exit $$?; \ + done + +uninstall-libtpmsincludeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(libtpmsinclude_HEADERS)'; test -n "$(libtpmsincludedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(libtpmsincludedir)'; $(am__uninstall_files_from_dir) + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libtpmsincludedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-libtpmsincludeHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libtpmsincludeHEADERS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libtool ctags distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libtpmsincludeHEADERS install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libtpmsincludeHEADERS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/include/libtpms/tpm_error.h b/include/libtpms/tpm_error.h new file mode 100644 index 00000000..dafff4db --- /dev/null +++ b/include/libtpms/tpm_error.h @@ -0,0 +1,249 @@ +/********************************************************************************/ +/* */ +/* Error Response */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_error.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_ERROR_H +#define TPM_ERROR_H + +/* 16. Return codes rev 99 + + The TPM has five types of return code. One indicates successful operation and four indicate + failure. TPM_SUCCESS (00000000) indicates successful execution. The failure reports are: + TPM defined fatal errors (00000001 to 000003FF), vendor defined fatal errors (00000400 to + 000007FF), TPM defined non-fatal errors (00000800 to 00000BFF), and vendor defined + non-fatal errors (00000C00 to 00000FFF). + + The range of vendor defined non-fatal errors was determined by the TSS-WG, which defined + XXXX YCCC with XXXX as OS specific and Y defining the TSS SW stack layer (0: TPM layer) + + All failure cases return only a non-authenticated fixed set of information. This is because + the failure may have been due to authentication or other factors, and there is no possibility + of producing an authenticated response. + + Fatal errors also terminate any authorization sessions. This is a result of returning only the + error code, as there is no way to return the nonces necessary to maintain an authorization + session. Non-fatal errors do not terminate authorization sessions. + + The return code MUST use the following base. The return code MAY be TCG defined or vendor + defined. */ + +#define TPM_BASE 0x0 /* The start of TPM return codes */ +#define TPM_SUCCESS TPM_BASE /* Successful completion of the operation */ +#define TPM_VENDOR_ERROR TPM_Vendor_Specific32 /* Mask to indicate that the error code is + vendor specific for vendor specific + commands. */ +#define TPM_NON_FATAL 0x00000800 /* Mask to indicate that the error code is a non-fatal + failure. */ + +/* TPM-defined fatal error codes */ + +#define TPM_AUTHFAIL TPM_BASE + 1 /* Authentication failed */ +#define TPM_BADINDEX TPM_BASE + 2 /* The index to a PCR, DIR or other register is + incorrect */ +#define TPM_BAD_PARAMETER TPM_BASE + 3 /* One or more parameter is bad */ +#define TPM_AUDITFAILURE TPM_BASE + 4 /* An operation completed successfully but the auditing + of that operation failed. */ +#define TPM_CLEAR_DISABLED TPM_BASE + 5 /* The clear disable flag is set and all clear + operations now require physical access */ +#define TPM_DEACTIVATED TPM_BASE + 6 /* The TPM is deactivated */ +#define TPM_DISABLED TPM_BASE + 7 /* The TPM is disabled */ +#define TPM_DISABLED_CMD TPM_BASE + 8 /* The target command has been disabled */ +#define TPM_FAIL TPM_BASE + 9 /* The operation failed */ +#define TPM_BAD_ORDINAL TPM_BASE + 10 /* The ordinal was unknown or inconsistent */ +#define TPM_INSTALL_DISABLED TPM_BASE + 11 /* The ability to install an owner is disabled */ +#define TPM_INVALID_KEYHANDLE TPM_BASE + 12 /* The key handle presented was invalid */ +#define TPM_KEYNOTFOUND TPM_BASE + 13 /* The target key was not found */ +#define TPM_INAPPROPRIATE_ENC TPM_BASE + 14 /* Unacceptable encryption scheme */ +#define TPM_MIGRATEFAIL TPM_BASE + 15 /* Migration authorization failed */ +#define TPM_INVALID_PCR_INFO TPM_BASE + 16 /* PCR information could not be interpreted */ +#define TPM_NOSPACE TPM_BASE + 17 /* No room to load key. */ +#define TPM_NOSRK TPM_BASE + 18 /* There is no SRK set */ +#define TPM_NOTSEALED_BLOB TPM_BASE + 19 /* An encrypted blob is invalid or was not created by + this TPM */ +#define TPM_OWNER_SET TPM_BASE + 20 /* There is already an Owner */ +#define TPM_RESOURCES TPM_BASE + 21 /* The TPM has insufficient internal resources to + perform the requested action. */ +#define TPM_SHORTRANDOM TPM_BASE + 22 /* A random string was too short */ +#define TPM_SIZE TPM_BASE + 23 /* The TPM does not have the space to perform the + operation. */ +#define TPM_WRONGPCRVAL TPM_BASE + 24 /* The named PCR value does not match the current PCR + value. */ +#define TPM_BAD_PARAM_SIZE TPM_BASE + 25 /* The paramSize argument to the command has the + incorrect value */ +#define TPM_SHA_THREAD TPM_BASE + 26 /* There is no existing SHA-1 thread. */ +#define TPM_SHA_ERROR TPM_BASE + 27 /* The calculation is unable to proceed because the + existing SHA-1 thread has already encountered an + error. */ +#define TPM_FAILEDSELFTEST TPM_BASE + 28 /* Self-test has failed and the TPM has shutdown. */ +#define TPM_AUTH2FAIL TPM_BASE + 29 /* The authorization for the second key in a 2 key + function failed authorization */ +#define TPM_BADTAG TPM_BASE + 30 /* The tag value sent to for a command is invalid */ +#define TPM_IOERROR TPM_BASE + 31 /* An IO error occurred transmitting information to + the TPM */ +#define TPM_ENCRYPT_ERROR TPM_BASE + 32 /* The encryption process had a problem. */ +#define TPM_DECRYPT_ERROR TPM_BASE + 33 /* The decryption process did not complete. */ +#define TPM_INVALID_AUTHHANDLE TPM_BASE + 34 /* An invalid handle was used. */ +#define TPM_NO_ENDORSEMENT TPM_BASE + 35 /* The TPM does not a EK installed */ +#define TPM_INVALID_KEYUSAGE TPM_BASE + 36 /* The usage of a key is not allowed */ +#define TPM_WRONG_ENTITYTYPE TPM_BASE + 37 /* The submitted entity type is not allowed */ +#define TPM_INVALID_POSTINIT TPM_BASE + 38 /* The command was received in the wrong sequence + relative to TPM_Init and a subsequent TPM_Startup + */ +#define TPM_INAPPROPRIATE_SIG TPM_BASE + 39 /* Signed data cannot include additional DER + information */ +#define TPM_BAD_KEY_PROPERTY TPM_BASE + 40 /* The key properties in TPM_KEY_PARMs are not + supported by this TPM */ +#define TPM_BAD_MIGRATION TPM_BASE + 41 /* The migration properties of this key are incorrect. + */ +#define TPM_BAD_SCHEME TPM_BASE + 42 /* The signature or encryption scheme for this key is + incorrect or not permitted in this situation. */ +#define TPM_BAD_DATASIZE TPM_BASE + 43 /* The size of the data (or blob) parameter is bad or + inconsistent with the referenced key */ +#define TPM_BAD_MODE TPM_BASE + 44 /* A mode parameter is bad, such as capArea or + subCapArea for TPM_GetCapability, physicalPresence + parameter for TPM_PhysicalPresence, or + migrationType for TPM_CreateMigrationBlob. */ +#define TPM_BAD_PRESENCE TPM_BASE + 45 /* Either the physicalPresence or physicalPresenceLock + bits have the wrong value */ +#define TPM_BAD_VERSION TPM_BASE + 46 /* The TPM cannot perform this version of the + capability */ +#define TPM_NO_WRAP_TRANSPORT TPM_BASE + 47 /* The TPM does not allow for wrapped transport + sessions */ +#define TPM_AUDITFAIL_UNSUCCESSFUL TPM_BASE + 48 /* TPM audit construction failed and the + underlying command was returning a failure + code also */ +#define TPM_AUDITFAIL_SUCCESSFUL TPM_BASE + 49 /* TPM audit construction failed and the underlying + command was returning success */ +#define TPM_NOTRESETABLE TPM_BASE + 50 /* Attempt to reset a PCR register that does not have + the resettable attribute */ +#define TPM_NOTLOCAL TPM_BASE + 51 /* Attempt to reset a PCR register that requires + locality and locality modifier not part of command + transport */ +#define TPM_BAD_TYPE TPM_BASE + 52 /* Make identity blob not properly typed */ +#define TPM_INVALID_RESOURCE TPM_BASE + 53 /* When saving context identified resource type does + not match actual resource */ +#define TPM_NOTFIPS TPM_BASE + 54 /* The TPM is attempting to execute a command only + available when in FIPS mode */ +#define TPM_INVALID_FAMILY TPM_BASE + 55 /* The command is attempting to use an invalid family + ID */ +#define TPM_NO_NV_PERMISSION TPM_BASE + 56 /* The permission to manipulate the NV storage is not + available */ +#define TPM_REQUIRES_SIGN TPM_BASE + 57 /* The operation requires a signed command */ +#define TPM_KEY_NOTSUPPORTED TPM_BASE + 58 /* Wrong operation to load an NV key */ +#define TPM_AUTH_CONFLICT TPM_BASE + 59 /* NV_LoadKey blob requires both owner and blob + authorization */ +#define TPM_AREA_LOCKED TPM_BASE + 60 /* The NV area is locked and not writable */ +#define TPM_BAD_LOCALITY TPM_BASE + 61 /* The locality is incorrect for the attempted + operation */ +#define TPM_READ_ONLY TPM_BASE + 62 /* The NV area is read only and can't be written to + */ +#define TPM_PER_NOWRITE TPM_BASE + 63 /* There is no protection on the write to the NV area + */ +#define TPM_FAMILYCOUNT TPM_BASE + 64 /* The family count value does not match */ +#define TPM_WRITE_LOCKED TPM_BASE + 65 /* The NV area has already been written to */ +#define TPM_BAD_ATTRIBUTES TPM_BASE + 66 /* The NV area attributes conflict */ +#define TPM_INVALID_STRUCTURE TPM_BASE + 67 /* The structure tag and version are invalid or + inconsistent */ +#define TPM_KEY_OWNER_CONTROL TPM_BASE + 68 /* The key is under control of the TPM Owner and can + only be evicted by the TPM Owner. */ +#define TPM_BAD_COUNTER TPM_BASE + 69 /* The counter handle is incorrect */ +#define TPM_NOT_FULLWRITE TPM_BASE + 70 /* The write is not a complete write of the area */ +#define TPM_CONTEXT_GAP TPM_BASE + 71 /* The gap between saved context counts is too large + */ +#define TPM_MAXNVWRITES TPM_BASE + 72 /* The maximum number of NV writes without an owner + has been exceeded */ +#define TPM_NOOPERATOR TPM_BASE + 73 /* No operator authorization value is set */ +#define TPM_RESOURCEMISSING TPM_BASE + 74 /* The resource pointed to by context is not loaded + */ +#define TPM_DELEGATE_LOCK TPM_BASE + 75 /* The delegate administration is locked */ +#define TPM_DELEGATE_FAMILY TPM_BASE + 76 /* Attempt to manage a family other then the delegated + family */ +#define TPM_DELEGATE_ADMIN TPM_BASE + 77 /* Delegation table management not enabled */ +#define TPM_TRANSPORT_NOTEXCLUSIVE TPM_BASE + 78 /* There was a command executed outside of an + exclusive transport session */ +#define TPM_OWNER_CONTROL TPM_BASE + 79 /* Attempt to context save a owner evict controlled + key */ +#define TPM_DAA_RESOURCES TPM_BASE + 80 /* The DAA command has no resources available to + execute the command */ +#define TPM_DAA_INPUT_DATA0 TPM_BASE + 81 /* The consistency check on DAA parameter inputData0 + has failed. */ +#define TPM_DAA_INPUT_DATA1 TPM_BASE + 82 /* The consistency check on DAA parameter inputData1 + has failed. */ +#define TPM_DAA_ISSUER_SETTINGS TPM_BASE + 83 /* The consistency check on DAA_issuerSettings has + failed. */ +#define TPM_DAA_TPM_SETTINGS TPM_BASE + 84 /* The consistency check on DAA_tpmSpecific has + failed. */ +#define TPM_DAA_STAGE TPM_BASE + 85 /* The atomic process indicated by the submitted DAA + command is not the expected process. */ +#define TPM_DAA_ISSUER_VALIDITY TPM_BASE + 86 /* The issuer's validity check has detected an + inconsistency */ +#define TPM_DAA_WRONG_W TPM_BASE + 87 /* The consistency check on w has failed. */ +#define TPM_BAD_HANDLE TPM_BASE + 88 /* The handle is incorrect */ +#define TPM_BAD_DELEGATE TPM_BASE + 89 /* Delegation is not correct */ +#define TPM_BADCONTEXT TPM_BASE + 90 /* The context blob is invalid */ +#define TPM_TOOMANYCONTEXTS TPM_BASE + 91 /* Too many contexts held by the TPM */ +#define TPM_MA_TICKET_SIGNATURE TPM_BASE + 92 /* Migration authority signature validation failure + */ +#define TPM_MA_DESTINATION TPM_BASE + 93 /* Migration destination not authenticated */ +#define TPM_MA_SOURCE TPM_BASE + 94 /* Migration source incorrect */ +#define TPM_MA_AUTHORITY TPM_BASE + 95 /* Incorrect migration authority */ +#define TPM_PERMANENTEK TPM_BASE + 97 /* Attempt to revoke the EK and the EK is not revocable */ +#define TPM_BAD_SIGNATURE TPM_BASE + 98 /* Bad signature of CMK ticket */ +#define TPM_NOCONTEXTSPACE TPM_BASE + 99 /* There is no room in the context list for additional + contexts */ + +/* As error codes are added here, they should also be added to lib/miscfunc.c */ + +/* TPM-defined non-fatal errors */ + +#define TPM_RETRY TPM_BASE + TPM_NON_FATAL /* The TPM is too busy to respond to the + command immediately, but the command + could be submitted at a later time */ +#define TPM_NEEDS_SELFTEST TPM_BASE + TPM_NON_FATAL + 1 /* TPM_ContinueSelfTest has has not + been run*/ +#define TPM_DOING_SELFTEST TPM_BASE + TPM_NON_FATAL + 2 /* The TPM is currently executing the + actions of TPM_ContinueSelfTest + because the ordinal required + resources that have not been + tested. */ +#define TPM_DEFEND_LOCK_RUNNING TPM_BASE + TPM_NON_FATAL + 3 + /* The TPM is defending against dictionary + attacks and is in some time-out + period. */ + +#endif diff --git a/include/libtpms/tpm_library.h b/include/libtpms/tpm_library.h new file mode 100644 index 00000000..1fb2bc1d --- /dev/null +++ b/include/libtpms/tpm_library.h @@ -0,0 +1,128 @@ +/********************************************************************************/ +/* */ +/* LibTPM interface functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_library.h 4623 2011-09-28 15:15:09Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ +#ifndef TPM_LIBRARY_H +#define TPM_LIBRARY_H + +#include +#include + +#include "tpm_types.h" + +#define TPM_LIBRARY_VER_MAJOR 0 +#define TPM_LIBRARY_VER_MINOR 5 +#define TPM_LIBRARY_VER_MICRO 1 + +#define TPM_LIBRARY_VERSION_GEN(MAJ, MIN, MICRO) \ + (( MAJ << 16 ) | ( MIN << 8 ) | ( MICRO )) + +#define TPM_LIBRARY_VERSION \ + TPM_LIBRARY_VERSION_GEN(TPM_LIBRARY_VER_MAJOR, \ + TPM_LIBRARY_VER_MINOR, \ + TPM_LIBRARY_VER_MICRO) + + +uint32_t TPMLIB_GetVersion(void); + +TPM_RESULT TPMLIB_MainInit(void); + +void TPMLIB_Terminate(void); + +TPM_RESULT TPMLIB_Process(unsigned char **respbuffer, uint32_t *resp_size, + uint32_t *respbufsize, + unsigned char *command, uint32_t command_size); + +TPM_RESULT TPMLIB_VolatileAll_Store(unsigned char **buffer, uint32_t *buflen); + +enum TPMLIB_TPMProperty { + TPMPROP_TPM_RSA_KEY_LENGTH_MAX = 1, + TPMPROP_TPM_BUFFER_MAX, + TPMPROP_TPM_KEY_HANDLES, + TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES, + TPMPROP_TPM_MIN_AUTH_SESSIONS, + TPMPROP_TPM_MIN_TRANS_SESSIONS, + TPMPROP_TPM_MIN_DAA_SESSIONS, + TPMPROP_TPM_MIN_SESSION_LIST, + TPMPROP_TPM_MIN_COUNTERS, + TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN, + TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN, + TPMPROP_TPM_SPACE_SAFETY_MARGIN, + TPMPROP_TPM_MAX_NV_SPACE, + TPMPROP_TPM_MAX_SAVESTATE_SPACE, + TPMPROP_TPM_MAX_VOLATILESTATE_SPACE, +}; + +TPM_RESULT TPMLIB_GetTPMProperty(enum TPMLIB_TPMProperty prop, int *result); + +struct libtpms_callbacks { + int sizeOfStruct; + TPM_RESULT (*tpm_nvram_init)(void); + TPM_RESULT (*tpm_nvram_loaddata)(unsigned char **data, + uint32_t *length, + uint32_t tpm_number, + const char *name); + TPM_RESULT (*tpm_nvram_storedata)(const unsigned char *data, + uint32_t length, + uint32_t tpm_number, + const char *name); + TPM_RESULT (*tpm_nvram_deletename)(uint32_t tpm_number, + const char *name, + TPM_BOOL mustExist); + TPM_RESULT (*tpm_io_init)(void); + TPM_RESULT (*tpm_io_getlocality)(TPM_MODIFIER_INDICATOR *localityModifer, + uint32_t tpm_number); + TPM_RESULT (*tpm_io_getphysicalpresence)(TPM_BOOL *physicalPresence, + uint32_t tpm_number); +}; + +TPM_RESULT TPMLIB_RegisterCallbacks(struct libtpms_callbacks *); + +enum TPMLIB_BlobType { + TPMLIB_BLOB_TYPE_INITSTATE, + + TPMLIB_BLOB_TYPE_LAST, +}; + +#define TPMLIB_INITSTATE_START_TAG "-----BEGIN INITSTATE-----" +#define TPMLIB_INITSTATE_END_TAG "-----END INITSTATE-----" + +TPM_RESULT TPMLIB_DecodeBlob(const char *data, enum TPMLIB_BlobType type, + unsigned char **result, size_t *result_len); + + +#endif /* TPM_LIBRARY_H */ diff --git a/include/libtpms/tpm_library.h.in b/include/libtpms/tpm_library.h.in new file mode 100644 index 00000000..3e5ddba3 --- /dev/null +++ b/include/libtpms/tpm_library.h.in @@ -0,0 +1,128 @@ +/********************************************************************************/ +/* */ +/* LibTPM interface functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_library.h 4623 2011-09-28 15:15:09Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ +#ifndef TPM_LIBRARY_H +#define TPM_LIBRARY_H + +#include +#include + +#include "tpm_types.h" + +#define TPM_LIBRARY_VER_MAJOR @LIBTPMS_VER_MAJOR@ +#define TPM_LIBRARY_VER_MINOR @LIBTPMS_VER_MINOR@ +#define TPM_LIBRARY_VER_MICRO @LIBTPMS_VER_MICRO@ + +#define TPM_LIBRARY_VERSION_GEN(MAJ, MIN, MICRO) \ + (( MAJ << 16 ) | ( MIN << 8 ) | ( MICRO )) + +#define TPM_LIBRARY_VERSION \ + TPM_LIBRARY_VERSION_GEN(TPM_LIBRARY_VER_MAJOR, \ + TPM_LIBRARY_VER_MINOR, \ + TPM_LIBRARY_VER_MICRO) + + +uint32_t TPMLIB_GetVersion(void); + +TPM_RESULT TPMLIB_MainInit(void); + +void TPMLIB_Terminate(void); + +TPM_RESULT TPMLIB_Process(unsigned char **respbuffer, uint32_t *resp_size, + uint32_t *respbufsize, + unsigned char *command, uint32_t command_size); + +TPM_RESULT TPMLIB_VolatileAll_Store(unsigned char **buffer, uint32_t *buflen); + +enum TPMLIB_TPMProperty { + TPMPROP_TPM_RSA_KEY_LENGTH_MAX = 1, + TPMPROP_TPM_BUFFER_MAX, + TPMPROP_TPM_KEY_HANDLES, + TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES, + TPMPROP_TPM_MIN_AUTH_SESSIONS, + TPMPROP_TPM_MIN_TRANS_SESSIONS, + TPMPROP_TPM_MIN_DAA_SESSIONS, + TPMPROP_TPM_MIN_SESSION_LIST, + TPMPROP_TPM_MIN_COUNTERS, + TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN, + TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN, + TPMPROP_TPM_SPACE_SAFETY_MARGIN, + TPMPROP_TPM_MAX_NV_SPACE, + TPMPROP_TPM_MAX_SAVESTATE_SPACE, + TPMPROP_TPM_MAX_VOLATILESTATE_SPACE, +}; + +TPM_RESULT TPMLIB_GetTPMProperty(enum TPMLIB_TPMProperty prop, int *result); + +struct libtpms_callbacks { + int sizeOfStruct; + TPM_RESULT (*tpm_nvram_init)(void); + TPM_RESULT (*tpm_nvram_loaddata)(unsigned char **data, + uint32_t *length, + uint32_t tpm_number, + const char *name); + TPM_RESULT (*tpm_nvram_storedata)(const unsigned char *data, + uint32_t length, + uint32_t tpm_number, + const char *name); + TPM_RESULT (*tpm_nvram_deletename)(uint32_t tpm_number, + const char *name, + TPM_BOOL mustExist); + TPM_RESULT (*tpm_io_init)(void); + TPM_RESULT (*tpm_io_getlocality)(TPM_MODIFIER_INDICATOR *localityModifer, + uint32_t tpm_number); + TPM_RESULT (*tpm_io_getphysicalpresence)(TPM_BOOL *physicalPresence, + uint32_t tpm_number); +}; + +TPM_RESULT TPMLIB_RegisterCallbacks(struct libtpms_callbacks *); + +enum TPMLIB_BlobType { + TPMLIB_BLOB_TYPE_INITSTATE, + + TPMLIB_BLOB_TYPE_LAST, +}; + +#define TPMLIB_INITSTATE_START_TAG "-----BEGIN INITSTATE-----" +#define TPMLIB_INITSTATE_END_TAG "-----END INITSTATE-----" + +TPM_RESULT TPMLIB_DecodeBlob(const char *data, enum TPMLIB_BlobType type, + unsigned char **result, size_t *result_len); + + +#endif /* TPM_LIBRARY_H */ diff --git a/include/libtpms/tpm_memory.h b/include/libtpms/tpm_memory.h new file mode 100644 index 00000000..9317ef65 --- /dev/null +++ b/include/libtpms/tpm_memory.h @@ -0,0 +1,49 @@ +/********************************************************************************/ +/* */ +/* TPM Memory Allocation */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_memory.h 4609 2011-08-26 19:27:38Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_MEMORY_H +#define TPM_MEMORY_H + +#include "tpm_types.h" + +TPM_RESULT TPM_Malloc(unsigned char **buffer, uint32_t size); +TPM_RESULT TPM_Realloc(unsigned char **buffer, uint32_t size); +void TPM_Free(unsigned char *buffer); + +#endif diff --git a/include/libtpms/tpm_nvfilename.h b/include/libtpms/tpm_nvfilename.h new file mode 100644 index 00000000..44464198 --- /dev/null +++ b/include/libtpms/tpm_nvfilename.h @@ -0,0 +1,56 @@ +/********************************************************************************/ +/* */ +/* NVRAM File Names */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nvfilename.h 4438 2011-02-13 23:03:56Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +/* Contains the base names used to construct NV storage file names. */ + +#ifndef TPM_NVFILENAME_H +#define TPM_NVFILENAME_H + +/* + Constants for NVRAM names +*/ + +#define TPM_PERMANENT_ALL_NAME "permall" + +#define TPM_SAVESTATE_NAME "savestate" + +#define TPM_VOLATILESTATE_NAME "volatilestate" + + +#endif diff --git a/include/libtpms/tpm_tis.h b/include/libtpms/tpm_tis.h new file mode 100644 index 00000000..6d4cf313 --- /dev/null +++ b/include/libtpms/tpm_tis.h @@ -0,0 +1,53 @@ +/********************************************************************************/ +/* */ +/* TPM TIS I/O */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_tis.h 4285 2011-01-17 21:27:05Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2011. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_TIS_H +#define TPM_TIS_H + +#include "tpm_types.h" + +TPM_RESULT TPM_IO_Hash_Start(void); +TPM_RESULT TPM_IO_Hash_Data(const unsigned char *data, + uint32_t data_length); +TPM_RESULT TPM_IO_Hash_End(void); + +TPM_RESULT TPM_IO_TpmEstablished_Get(TPM_BOOL *tpmEstablished); + + +#endif diff --git a/include/libtpms/tpm_types.h b/include/libtpms/tpm_types.h new file mode 100644 index 00000000..ecb109c8 --- /dev/null +++ b/include/libtpms/tpm_types.h @@ -0,0 +1,138 @@ +/********************************************************************************/ +/* */ +/* TPM Types */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_types.h 4202 2010-11-17 16:26:06Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_TYPES_H +#define TPM_TYPES_H + +#include + +#if defined (TPM_POSIX) || defined (TPM_SYSTEM_P) +#include /* for byte order conversions */ +#endif + +/* 2.2.1 Basic data types rev 87 */ +typedef unsigned char BYTE; /* Basic byte used to transmit all character fields. */ +typedef unsigned char TPM_BOOL; /* TRUE/FALSE field. TRUE = 0x01, FALSE = 0x00 Use TPM_BOOL + because MS VC++ defines BOOL on Windows */ + +/* 2.2.2 Boolean types rev 107 */ + +#undef TRUE +#define TRUE 0x01 /* Assertion */ +#undef FALSE +#define FALSE 0x00 /* Contradiction */ + +/* 2.2.3 Helper redefinitions rev 101 + + The following definitions are to make the definitions more explicit and easier to read. + + NOTE: They cannot be changed without breaking the serialization. +*/ + +typedef BYTE TPM_AUTH_DATA_USAGE; /* Indicates the conditions where it is required that + authorization be presented. */ +typedef BYTE TPM_PAYLOAD_TYPE; /* The information as to what the payload is in an encrypted + structure */ +typedef BYTE TPM_VERSION_BYTE; /* The version info breakdown */ +typedef BYTE TPM_DA_STATE; /* The state of the dictionary attack mitigation logic */ + +/* added kgold */ +typedef BYTE TPM_ENT_TYPE; /* LSB of TPM_ENTITY_TYPE */ +typedef BYTE TPM_ADIP_ENC_SCHEME; /* MSB of TPM_ENTITY_TYPE */ + +typedef uint16_t TPM_PROTOCOL_ID; /* The protocol in use. */ +typedef uint16_t TPM_STARTUP_TYPE; /* Indicates the start state. */ +typedef uint16_t TPM_ENC_SCHEME; /* The definition of the encryption scheme. */ +typedef uint16_t TPM_SIG_SCHEME; /* The definition of the signature scheme. */ +typedef uint16_t TPM_MIGRATE_SCHEME; /* The definition of the migration scheme */ +typedef uint16_t TPM_PHYSICAL_PRESENCE; /* Sets the state of the physical presence mechanism. */ +typedef uint16_t TPM_ENTITY_TYPE; /* Indicates the types of entity that are supported by the + TPM. */ +typedef uint16_t TPM_KEY_USAGE; /* Indicates the permitted usage of the key. */ +typedef uint16_t TPM_EK_TYPE; /* The type of asymmetric encrypted structure in use by the + endorsement key */ +typedef uint16_t TPM_STRUCTURE_TAG; /* The tag for the structure */ +typedef uint16_t TPM_PLATFORM_SPECIFIC; /* The platform specific spec to which the information + relates to */ +typedef uint32_t TPM_COMMAND_CODE; /* The command ordinal. */ +typedef uint32_t TPM_CAPABILITY_AREA; /* Identifies a TPM capability area. */ +typedef uint32_t TPM_KEY_FLAGS; /* Indicates information regarding a key. */ +typedef uint32_t TPM_ALGORITHM_ID; /* Indicates the type of algorithm. */ +typedef uint32_t TPM_MODIFIER_INDICATOR; /* The locality modifier */ +typedef uint32_t TPM_ACTUAL_COUNT; /* The actual number of a counter. */ +typedef uint32_t TPM_TRANSPORT_ATTRIBUTES; /* Attributes that define what options are in use + for a transport session */ +typedef uint32_t TPM_AUTHHANDLE; /* Handle to an authorization session */ +typedef uint32_t TPM_DIRINDEX; /* Index to a DIR register */ +typedef uint32_t TPM_KEY_HANDLE; /* The area where a key is held assigned by the TPM. */ +typedef uint32_t TPM_PCRINDEX; /* Index to a PCR register */ +typedef uint32_t TPM_RESULT; /* The return code from a function */ +typedef uint32_t TPM_RESOURCE_TYPE; /* The types of resources that a TPM may have using internal + resources */ +typedef uint32_t TPM_KEY_CONTROL; /* Allows for controlling of the key when loaded and how to + handle TPM_Startup issues */ +typedef uint32_t TPM_NV_INDEX; /* The index into the NV storage area */ +typedef uint32_t TPM_FAMILY_ID; /* The family ID. Families ID's are automatically assigned a + sequence number by the TPM. A trusted process can set the + FamilyID value in an individual row to zero, which + invalidates that row. The family ID resets to zero on + each change of TPM Owner. */ +typedef uint32_t TPM_FAMILY_VERIFICATION; /* A value used as a label for the most recent + verification of this family. Set to zero when not + in use. */ +typedef uint32_t TPM_STARTUP_EFFECTS; /* How the TPM handles var */ +typedef uint32_t TPM_SYM_MODE; /* The mode of a symmetric encryption */ +typedef uint32_t TPM_FAMILY_FLAGS; /* The family flags */ +typedef uint32_t TPM_DELEGATE_INDEX; /* The index value for the delegate NV table */ +typedef uint32_t TPM_CMK_DELEGATE; /* The restrictions placed on delegation of CMK + commands */ +typedef uint32_t TPM_COUNT_ID; /* The ID value of a monotonic counter */ +typedef uint32_t TPM_REDIT_COMMAND; /* A command to execute */ +typedef uint32_t TPM_TRANSHANDLE; /* A transport session handle */ +typedef uint32_t TPM_HANDLE; /* A generic handle could be key, transport etc. */ +typedef uint32_t TPM_FAMILY_OPERATION; /* What operation is happening */ + +/* Not in specification */ + +typedef uint16_t TPM_TAG; /* The command and response tags */ + +typedef unsigned char * TPM_SYMMETRIC_KEY_TOKEN; /* abstract symmetric key token */ +typedef unsigned char * TPM_BIGNUM; /* abstract bignum */ + +#endif diff --git a/install-sh b/install-sh new file mode 100755 index 00000000..a9244eb0 --- /dev/null +++ b/install-sh @@ -0,0 +1,527 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2011-01-19.21; # UTC + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + # Protect names problematic for `test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + # Protect names problematic for `test' and other utilities. + case $dst_arg in + -* | [=\(\)!]) dst_arg=./$dst_arg;; + esac + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + do_exit='(exit $ret); exit $ret' + trap "ret=129; $do_exit" 1 + trap "ret=130; $do_exit" 2 + trap "ret=141; $do_exit" 13 + trap "ret=143; $do_exit" 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names problematic for `test' and other utilities. + case $src in + -* | [=\(\)!]) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + dst=$dst_arg + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + [-=\(\)!]*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test X"$d" = X && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/libtpms.pc.in b/libtpms.pc.in new file mode 100644 index 00000000..b051ea92 --- /dev/null +++ b/libtpms.pc.in @@ -0,0 +1,8 @@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libtpms +Version: @VERSION@ +Description: libtpms +Libs: -L${libdir} -ltpms +Cflags: -I${includedir} diff --git a/ltmain.sh b/ltmain.sh new file mode 100644 index 00000000..63ae69dc --- /dev/null +++ b/ltmain.sh @@ -0,0 +1,9655 @@ + +# libtool (GNU libtool) 2.4.2 +# Written by Gordon Matzigkeit , 1996 + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, +# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +# This is free software; see the source for copying conditions. There is NO +# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +# GNU Libtool 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. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, +# or obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Usage: $progname [OPTION]... [MODE-ARG]... +# +# Provide generalized library-building support services. +# +# --config show all configuration variables +# --debug enable verbose shell tracing +# -n, --dry-run display commands without modifying any files +# --features display basic configuration information and exit +# --mode=MODE use operation mode MODE +# --preserve-dup-deps don't remove duplicate dependency libraries +# --quiet, --silent don't print informational messages +# --no-quiet, --no-silent +# print informational messages (default) +# --no-warn don't display warning messages +# --tag=TAG use configuration variables from tag TAG +# -v, --verbose print more informational messages than default +# --no-verbose don't print the extra informational messages +# --version print version information +# -h, --help, --help-all print short, long, or detailed help message +# +# MODE must be one of the following: +# +# clean remove files from the build directory +# compile compile a source file into a libtool object +# execute automatically set library path, then run a program +# finish complete the installation of libtool libraries +# install install libraries or executables +# link create a library or an executable +# uninstall remove libraries from an installed directory +# +# MODE-ARGS vary depending on the MODE. When passed as first option, +# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. +# Try `$progname --help --mode=MODE' for a more detailed description of MODE. +# +# When reporting a bug, please describe a test case to reproduce it and +# include the following information: +# +# host-triplet: $host +# shell: $SHELL +# compiler: $LTCC +# compiler flags: $LTCFLAGS +# linker: $LD (gnu? $with_gnu_ld) +# $progname: (GNU libtool) 2.4.2 +# automake: $automake_version +# autoconf: $autoconf_version +# +# Report bugs to . +# GNU libtool home page: . +# General help using GNU software: . + +PROGRAM=libtool +PACKAGE=libtool +VERSION=2.4.2 +TIMESTAMP="" +package_revision=1.3337 + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +$1 +_LTECHO_EOF' +} + +# NLS nuisances: We save the old values to restore during execute mode. +lt_user_locale= +lt_safe_locale= +for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES +do + eval "if test \"\${$lt_var+set}\" = set; then + save_$lt_var=\$$lt_var + $lt_var=C + export $lt_var + lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" + lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" + fi" +done +LC_ALL=C +LANGUAGE=C +export LANGUAGE LC_ALL + +$lt_unset CDPATH + + +# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh +# is ksh but when the shell is invoked as "sh" and the current value of +# the _XPG environment variable is not equal to 1 (one), the special +# positional parameter $0, within a function call, is the name of the +# function. +progpath="$0" + + + +: ${CP="cp -f"} +test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'} +: ${MAKE="make"} +: ${MKDIR="mkdir"} +: ${MV="mv -f"} +: ${RM="rm -f"} +: ${SHELL="${CONFIG_SHELL-/bin/sh}"} +: ${Xsed="$SED -e 1s/^X//"} + +# Global variables: +EXIT_SUCCESS=0 +EXIT_FAILURE=1 +EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. +EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. + +exit_status=$EXIT_SUCCESS + +# Make sure IFS has a sensible default +lt_nl=' +' +IFS=" $lt_nl" + +dirname="s,/[^/]*$,," +basename="s,^.*/,," + +# func_dirname file append nondir_replacement +# Compute the dirname of FILE. If nonempty, add APPEND to the result, +# otherwise set result to NONDIR_REPLACEMENT. +func_dirname () +{ + func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi +} # func_dirname may be replaced by extended shell implementation + + +# func_basename file +func_basename () +{ + func_basename_result=`$ECHO "${1}" | $SED "$basename"` +} # func_basename may be replaced by extended shell implementation + + +# func_dirname_and_basename file append nondir_replacement +# perform func_basename and func_dirname in a single function +# call: +# dirname: Compute the dirname of FILE. If nonempty, +# add APPEND to the result, otherwise set result +# to NONDIR_REPLACEMENT. +# value returned in "$func_dirname_result" +# basename: Compute filename of FILE. +# value retuned in "$func_basename_result" +# Implementation must be kept synchronized with func_dirname +# and func_basename. For efficiency, we do not delegate to +# those functions but instead duplicate the functionality here. +func_dirname_and_basename () +{ + # Extract subdirectory from the argument. + func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` + if test "X$func_dirname_result" = "X${1}"; then + func_dirname_result="${3}" + else + func_dirname_result="$func_dirname_result${2}" + fi + func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` +} # func_dirname_and_basename may be replaced by extended shell implementation + + +# func_stripname prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# func_strip_suffix prefix name +func_stripname () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname may be replaced by extended shell implementation + + +# These SED scripts presuppose an absolute path with a trailing slash. +pathcar='s,^/\([^/]*\).*$,\1,' +pathcdr='s,^/[^/]*,,' +removedotparts=':dotsl + s@/\./@/@g + t dotsl + s,/\.$,/,' +collapseslashes='s@/\{1,\}@/@g' +finalslash='s,/*$,/,' + +# func_normal_abspath PATH +# Remove doubled-up and trailing slashes, "." path components, +# and cancel out any ".." path components in PATH after making +# it an absolute path. +# value returned in "$func_normal_abspath_result" +func_normal_abspath () +{ + # Start from root dir and reassemble the path. + func_normal_abspath_result= + func_normal_abspath_tpath=$1 + func_normal_abspath_altnamespace= + case $func_normal_abspath_tpath in + "") + # Empty path, that just means $cwd. + func_stripname '' '/' "`pwd`" + func_normal_abspath_result=$func_stripname_result + return + ;; + # The next three entries are used to spot a run of precisely + # two leading slashes without using negated character classes; + # we take advantage of case's first-match behaviour. + ///*) + # Unusual form of absolute path, do nothing. + ;; + //*) + # Not necessarily an ordinary path; POSIX reserves leading '//' + # and for example Cygwin uses it to access remote file shares + # over CIFS/SMB, so we conserve a leading double slash if found. + func_normal_abspath_altnamespace=/ + ;; + /*) + # Absolute path, do nothing. + ;; + *) + # Relative path, prepend $cwd. + func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath + ;; + esac + # Cancel out all the simple stuff to save iterations. We also want + # the path to end with a slash for ease of parsing, so make sure + # there is one (and only one) here. + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` + while :; do + # Processed it all yet? + if test "$func_normal_abspath_tpath" = / ; then + # If we ascended to the root using ".." the result may be empty now. + if test -z "$func_normal_abspath_result" ; then + func_normal_abspath_result=/ + fi + break + fi + func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcar"` + func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ + -e "$pathcdr"` + # Figure out what to do with it + case $func_normal_abspath_tcomponent in + "") + # Trailing empty path component, ignore it. + ;; + ..) + # Parent dir; strip last assembled component from result. + func_dirname "$func_normal_abspath_result" + func_normal_abspath_result=$func_dirname_result + ;; + *) + # Actual path component, append it. + func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent + ;; + esac + done + # Restore leading double-slash if one was found on entry. + func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result +} + +# func_relative_path SRCDIR DSTDIR +# generates a relative path from SRCDIR to DSTDIR, with a trailing +# slash if non-empty, suitable for immediately appending a filename +# without needing to append a separator. +# value returned in "$func_relative_path_result" +func_relative_path () +{ + func_relative_path_result= + func_normal_abspath "$1" + func_relative_path_tlibdir=$func_normal_abspath_result + func_normal_abspath "$2" + func_relative_path_tbindir=$func_normal_abspath_result + + # Ascend the tree starting from libdir + while :; do + # check if we have found a prefix of bindir + case $func_relative_path_tbindir in + $func_relative_path_tlibdir) + # found an exact match + func_relative_path_tcancelled= + break + ;; + $func_relative_path_tlibdir*) + # found a matching prefix + func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" + func_relative_path_tcancelled=$func_stripname_result + if test -z "$func_relative_path_result"; then + func_relative_path_result=. + fi + break + ;; + *) + func_dirname $func_relative_path_tlibdir + func_relative_path_tlibdir=${func_dirname_result} + if test "x$func_relative_path_tlibdir" = x ; then + # Have to descend all the way to the root! + func_relative_path_result=../$func_relative_path_result + func_relative_path_tcancelled=$func_relative_path_tbindir + break + fi + func_relative_path_result=../$func_relative_path_result + ;; + esac + done + + # Now calculate path; take care to avoid doubling-up slashes. + func_stripname '' '/' "$func_relative_path_result" + func_relative_path_result=$func_stripname_result + func_stripname '/' '/' "$func_relative_path_tcancelled" + if test "x$func_stripname_result" != x ; then + func_relative_path_result=${func_relative_path_result}/${func_stripname_result} + fi + + # Normalisation. If bindir is libdir, return empty string, + # else relative path ending with a slash; either way, target + # file name can be directly appended. + if test ! -z "$func_relative_path_result"; then + func_stripname './' '' "$func_relative_path_result/" + func_relative_path_result=$func_stripname_result + fi +} + +# The name of this program: +func_dirname_and_basename "$progpath" +progname=$func_basename_result + +# Make sure we have an absolute path for reexecution: +case $progpath in + [\\/]*|[A-Za-z]:\\*) ;; + *[\\/]*) + progdir=$func_dirname_result + progdir=`cd "$progdir" && pwd` + progpath="$progdir/$progname" + ;; + *) + save_IFS="$IFS" + IFS=${PATH_SEPARATOR-:} + for progdir in $PATH; do + IFS="$save_IFS" + test -x "$progdir/$progname" && break + done + IFS="$save_IFS" + test -n "$progdir" || progdir=`pwd` + progpath="$progdir/$progname" + ;; +esac + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +Xsed="${SED}"' -e 1s/^X//' +sed_quote_subst='s/\([`"$\\]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\(["`\\]\)/\\\1/g' + +# Sed substitution that turns a string into a regex matching for the +# string literally. +sed_make_literal_regex='s,[].[^$\\*\/],\\&,g' + +# Sed substitution that converts a w32 file name or path +# which contains forward slashes, into one that contains +# (escaped) backslashes. A very naive implementation. +lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' + +# Re-`\' parameter expansions in output of double_quote_subst that were +# `\'-ed in input to the same. If an odd number of `\' preceded a '$' +# in input to double_quote_subst, that '$' was protected from expansion. +# Since each input `\' is now two `\'s, look for any number of runs of +# four `\'s followed by two `\'s and then a '$'. `\' that '$'. +bs='\\' +bs2='\\\\' +bs4='\\\\\\\\' +dollar='\$' +sed_double_backslash="\ + s/$bs4/&\\ +/g + s/^$bs2$dollar/$bs&/ + s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g + s/\n//g" + +# Standard options: +opt_dry_run=false +opt_help=false +opt_quiet=false +opt_verbose=false +opt_warning=: + +# func_echo arg... +# Echo program name prefixed message, along with the current mode +# name if it has been set yet. +func_echo () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }$*" +} + +# func_verbose arg... +# Echo program name prefixed message in verbose mode only. +func_verbose () +{ + $opt_verbose && func_echo ${1+"$@"} + + # A bug in bash halts the script if the last line of a function + # fails when set -e is in force, so we need another command to + # work around that: + : +} + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +# func_error arg... +# Echo program name prefixed message to standard error. +func_error () +{ + $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2 +} + +# func_warning arg... +# Echo program name prefixed warning message to standard error. +func_warning () +{ + $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2 + + # bash bug again: + : +} + +# func_fatal_error arg... +# Echo program name prefixed message to standard error, and exit. +func_fatal_error () +{ + func_error ${1+"$@"} + exit $EXIT_FAILURE +} + +# func_fatal_help arg... +# Echo program name prefixed message to standard error, followed by +# a help hint, and exit. +func_fatal_help () +{ + func_error ${1+"$@"} + func_fatal_error "$help" +} +help="Try \`$progname --help' for more information." ## default + + +# func_grep expression filename +# Check whether EXPRESSION matches any line of FILENAME, without output. +func_grep () +{ + $GREP "$1" "$2" >/dev/null 2>&1 +} + + +# func_mkdir_p directory-path +# Make sure the entire path to DIRECTORY-PATH is available. +func_mkdir_p () +{ + my_directory_path="$1" + my_dir_list= + + if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then + + # Protect directory names starting with `-' + case $my_directory_path in + -*) my_directory_path="./$my_directory_path" ;; + esac + + # While some portion of DIR does not yet exist... + while test ! -d "$my_directory_path"; do + # ...make a list in topmost first order. Use a colon delimited + # list incase some portion of path contains whitespace. + my_dir_list="$my_directory_path:$my_dir_list" + + # If the last portion added has no slash in it, the list is done + case $my_directory_path in */*) ;; *) break ;; esac + + # ...otherwise throw away the child directory and loop + my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` + done + my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` + + save_mkdir_p_IFS="$IFS"; IFS=':' + for my_dir in $my_dir_list; do + IFS="$save_mkdir_p_IFS" + # mkdir can fail with a `File exist' error if two processes + # try to create one of the directories concurrently. Don't + # stop in that case! + $MKDIR "$my_dir" 2>/dev/null || : + done + IFS="$save_mkdir_p_IFS" + + # Bail out if we (or some other process) failed to create a directory. + test -d "$my_directory_path" || \ + func_fatal_error "Failed to create \`$1'" + fi +} + + +# func_mktempdir [string] +# Make a temporary directory that won't clash with other running +# libtool processes, and avoids race conditions if possible. If +# given, STRING is the basename for that directory. +func_mktempdir () +{ + my_template="${TMPDIR-/tmp}/${1-$progname}" + + if test "$opt_dry_run" = ":"; then + # Return a directory name, but don't create it in dry-run mode + my_tmpdir="${my_template}-$$" + else + + # If mktemp works, use that first and foremost + my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` + + if test ! -d "$my_tmpdir"; then + # Failing that, at least try and use $RANDOM to avoid a race + my_tmpdir="${my_template}-${RANDOM-0}$$" + + save_mktempdir_umask=`umask` + umask 0077 + $MKDIR "$my_tmpdir" + umask $save_mktempdir_umask + fi + + # If we're not in dry-run mode, bomb out on failure + test -d "$my_tmpdir" || \ + func_fatal_error "cannot create temporary directory \`$my_tmpdir'" + fi + + $ECHO "$my_tmpdir" +} + + +# func_quote_for_eval arg +# Aesthetically quote ARG to be evaled later. +# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT +# is double-quoted, suitable for a subsequent eval, whereas +# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters +# which are still active within double quotes backslashified. +func_quote_for_eval () +{ + case $1 in + *[\\\`\"\$]*) + func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; + *) + func_quote_for_eval_unquoted_result="$1" ;; + esac + + case $func_quote_for_eval_unquoted_result in + # Double-quote args containing shell metacharacters to delay + # word splitting, command substitution and and variable + # expansion for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" + ;; + *) + func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" + esac +} + + +# func_quote_for_expand arg +# Aesthetically quote ARG to be evaled later; same as above, +# but do not quote variable references. +func_quote_for_expand () +{ + case $1 in + *[\\\`\"]*) + my_arg=`$ECHO "$1" | $SED \ + -e "$double_quote_subst" -e "$sed_double_backslash"` ;; + *) + my_arg="$1" ;; + esac + + case $my_arg in + # Double-quote args containing shell metacharacters to delay + # word splitting and command substitution for a subsequent eval. + # Many Bourne shells cannot handle close brackets correctly + # in scan sets, so we specify it separately. + *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") + my_arg="\"$my_arg\"" + ;; + esac + + func_quote_for_expand_result="$my_arg" +} + + +# func_show_eval cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. +func_show_eval () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$my_cmd" + my_status=$? + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + + +# func_show_eval_locale cmd [fail_exp] +# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is +# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP +# is given, then evaluate it. Use the saved locale for evaluation. +func_show_eval_locale () +{ + my_cmd="$1" + my_fail_exp="${2-:}" + + ${opt_silent-false} || { + func_quote_for_expand "$my_cmd" + eval "func_echo $func_quote_for_expand_result" + } + + if ${opt_dry_run-false}; then :; else + eval "$lt_user_locale + $my_cmd" + my_status=$? + eval "$lt_safe_locale" + if test "$my_status" -eq 0; then :; else + eval "(exit $my_status); $my_fail_exp" + fi + fi +} + +# func_tr_sh +# Turn $1 into a string suitable for a shell variable name. +# Result is stored in $func_tr_sh_result. All characters +# not in the set a-zA-Z0-9_ are replaced with '_'. Further, +# if $1 begins with a digit, a '_' is prepended as well. +func_tr_sh () +{ + case $1 in + [0-9]* | *[!a-zA-Z0-9_]*) + func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'` + ;; + * ) + func_tr_sh_result=$1 + ;; + esac +} + + +# func_version +# Echo version message to standard output and exit. +func_version () +{ + $opt_debug + + $SED -n '/(C)/!b go + :more + /\./!{ + N + s/\n# / / + b more + } + :go + /^# '$PROGRAM' (GNU /,/# warranty; / { + s/^# // + s/^# *$// + s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ + p + }' < "$progpath" + exit $? +} + +# func_usage +# Echo short help message to standard output and exit. +func_usage () +{ + $opt_debug + + $SED -n '/^# Usage:/,/^# *.*--help/ { + s/^# // + s/^# *$// + s/\$progname/'$progname'/ + p + }' < "$progpath" + echo + $ECHO "run \`$progname --help | more' for full usage" + exit $? +} + +# func_help [NOEXIT] +# Echo long help message to standard output and exit, +# unless 'noexit' is passed as argument. +func_help () +{ + $opt_debug + + $SED -n '/^# Usage:/,/# Report bugs to/ { + :print + s/^# // + s/^# *$// + s*\$progname*'$progname'* + s*\$host*'"$host"'* + s*\$SHELL*'"$SHELL"'* + s*\$LTCC*'"$LTCC"'* + s*\$LTCFLAGS*'"$LTCFLAGS"'* + s*\$LD*'"$LD"'* + s/\$with_gnu_ld/'"$with_gnu_ld"'/ + s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/ + s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/ + p + d + } + /^# .* home page:/b print + /^# General help using/b print + ' < "$progpath" + ret=$? + if test -z "$1"; then + exit $ret + fi +} + +# func_missing_arg argname +# Echo program name prefixed message to standard error and set global +# exit_cmd. +func_missing_arg () +{ + $opt_debug + + func_error "missing argument for $1." + exit_cmd=exit +} + + +# func_split_short_opt shortopt +# Set func_split_short_opt_name and func_split_short_opt_arg shell +# variables after splitting SHORTOPT after the 2nd character. +func_split_short_opt () +{ + my_sed_short_opt='1s/^\(..\).*$/\1/;q' + my_sed_short_rest='1s/^..\(.*\)$/\1/;q' + + func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"` + func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"` +} # func_split_short_opt may be replaced by extended shell implementation + + +# func_split_long_opt longopt +# Set func_split_long_opt_name and func_split_long_opt_arg shell +# variables after splitting LONGOPT at the `=' sign. +func_split_long_opt () +{ + my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q' + my_sed_long_arg='1s/^--[^=]*=//' + + func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"` + func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"` +} # func_split_long_opt may be replaced by extended shell implementation + +exit_cmd=: + + + + + +magic="%%%MAGIC variable%%%" +magic_exe="%%%MAGIC EXE variable%%%" + +# Global variables. +nonopt= +preserve_args= +lo2o="s/\\.lo\$/.${objext}/" +o2lo="s/\\.${objext}\$/.lo/" +extracted_archives= +extracted_serial=0 + +# If this variable is set in any of the actions, the command in it +# will be execed at the end. This prevents here-documents from being +# left over by shells. +exec_cmd= + +# func_append var value +# Append VALUE to the end of shell variable VAR. +func_append () +{ + eval "${1}=\$${1}\${2}" +} # func_append may be replaced by extended shell implementation + +# func_append_quoted var value +# Quote VALUE and append to the end of shell variable VAR, separated +# by a space. +func_append_quoted () +{ + func_quote_for_eval "${2}" + eval "${1}=\$${1}\\ \$func_quote_for_eval_result" +} # func_append_quoted may be replaced by extended shell implementation + + +# func_arith arithmetic-term... +func_arith () +{ + func_arith_result=`expr "${@}"` +} # func_arith may be replaced by extended shell implementation + + +# func_len string +# STRING may not start with a hyphen. +func_len () +{ + func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len` +} # func_len may be replaced by extended shell implementation + + +# func_lo2o object +func_lo2o () +{ + func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` +} # func_lo2o may be replaced by extended shell implementation + + +# func_xform libobj-or-source +func_xform () +{ + func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` +} # func_xform may be replaced by extended shell implementation + + +# func_fatal_configuration arg... +# Echo program name prefixed message to standard error, followed by +# a configuration failure hint, and exit. +func_fatal_configuration () +{ + func_error ${1+"$@"} + func_error "See the $PACKAGE documentation for more information." + func_fatal_error "Fatal configuration error." +} + + +# func_config +# Display the configuration for all the tags in this script. +func_config () +{ + re_begincf='^# ### BEGIN LIBTOOL' + re_endcf='^# ### END LIBTOOL' + + # Default configuration. + $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" + + # Now print the configurations for the tags. + for tagname in $taglist; do + $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" + done + + exit $? +} + +# func_features +# Display the features supported by this script. +func_features () +{ + echo "host: $host" + if test "$build_libtool_libs" = yes; then + echo "enable shared libraries" + else + echo "disable shared libraries" + fi + if test "$build_old_libs" = yes; then + echo "enable static libraries" + else + echo "disable static libraries" + fi + + exit $? +} + +# func_enable_tag tagname +# Verify that TAGNAME is valid, and either flag an error and exit, or +# enable the TAGNAME tag. We also add TAGNAME to the global $taglist +# variable here. +func_enable_tag () +{ + # Global variable: + tagname="$1" + + re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" + re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" + sed_extractcf="/$re_begincf/,/$re_endcf/p" + + # Validate tagname. + case $tagname in + *[!-_A-Za-z0-9,/]*) + func_fatal_error "invalid tag name: $tagname" + ;; + esac + + # Don't test for the "default" C tag, as we know it's + # there but not specially marked. + case $tagname in + CC) ;; + *) + if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then + taglist="$taglist $tagname" + + # Evaluate the configuration. Be careful to quote the path + # and the sed script, to avoid splitting on whitespace, but + # also don't use non-portable quotes within backquotes within + # quotes we have to do it in 2 steps: + extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` + eval "$extractedcf" + else + func_error "ignoring unknown tag $tagname" + fi + ;; + esac +} + +# func_check_version_match +# Ensure that we are using m4 macros, and libtool script from the same +# release of libtool. +func_check_version_match () +{ + if test "$package_revision" != "$macro_revision"; then + if test "$VERSION" != "$macro_version"; then + if test -z "$macro_version"; then + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from an older release. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, but the +$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. +$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION +$progname: and run autoconf again. +_LT_EOF + fi + else + cat >&2 <<_LT_EOF +$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, +$progname: but the definition of this LT_INIT comes from revision $macro_revision. +$progname: You should recreate aclocal.m4 with macros from revision $package_revision +$progname: of $PACKAGE $VERSION and run autoconf again. +_LT_EOF + fi + + exit $EXIT_MISMATCH + fi +} + + +# Shorthand for --mode=foo, only valid as the first argument +case $1 in +clean|clea|cle|cl) + shift; set dummy --mode clean ${1+"$@"}; shift + ;; +compile|compil|compi|comp|com|co|c) + shift; set dummy --mode compile ${1+"$@"}; shift + ;; +execute|execut|execu|exec|exe|ex|e) + shift; set dummy --mode execute ${1+"$@"}; shift + ;; +finish|finis|fini|fin|fi|f) + shift; set dummy --mode finish ${1+"$@"}; shift + ;; +install|instal|insta|inst|ins|in|i) + shift; set dummy --mode install ${1+"$@"}; shift + ;; +link|lin|li|l) + shift; set dummy --mode link ${1+"$@"}; shift + ;; +uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) + shift; set dummy --mode uninstall ${1+"$@"}; shift + ;; +esac + + + +# Option defaults: +opt_debug=: +opt_dry_run=false +opt_config=false +opt_preserve_dup_deps=false +opt_features=false +opt_finish=false +opt_help=false +opt_help_all=false +opt_silent=: +opt_warning=: +opt_verbose=: +opt_silent=false +opt_verbose=false + + +# Parse options once, thoroughly. This comes as soon as possible in the +# script to make things like `--version' happen as quickly as we can. +{ + # this just eases exit handling + while test $# -gt 0; do + opt="$1" + shift + case $opt in + --debug|-x) opt_debug='set -x' + func_echo "enabling shell trace mode" + $opt_debug + ;; + --dry-run|--dryrun|-n) + opt_dry_run=: + ;; + --config) + opt_config=: +func_config + ;; + --dlopen|-dlopen) + optarg="$1" + opt_dlopen="${opt_dlopen+$opt_dlopen +}$optarg" + shift + ;; + --preserve-dup-deps) + opt_preserve_dup_deps=: + ;; + --features) + opt_features=: +func_features + ;; + --finish) + opt_finish=: +set dummy --mode finish ${1+"$@"}; shift + ;; + --help) + opt_help=: + ;; + --help-all) + opt_help_all=: +opt_help=': help-all' + ;; + --mode) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_mode="$optarg" +case $optarg in + # Valid mode arguments: + clean|compile|execute|finish|install|link|relink|uninstall) ;; + + # Catch anything else as an error + *) func_error "invalid argument for $opt" + exit_cmd=exit + break + ;; +esac + shift + ;; + --no-silent|--no-quiet) + opt_silent=false +func_append preserve_args " $opt" + ;; + --no-warning|--no-warn) + opt_warning=false +func_append preserve_args " $opt" + ;; + --no-verbose) + opt_verbose=false +func_append preserve_args " $opt" + ;; + --silent|--quiet) + opt_silent=: +func_append preserve_args " $opt" + opt_verbose=false + ;; + --verbose|-v) + opt_verbose=: +func_append preserve_args " $opt" +opt_silent=false + ;; + --tag) + test $# = 0 && func_missing_arg $opt && break + optarg="$1" + opt_tag="$optarg" +func_append preserve_args " $opt $optarg" +func_enable_tag "$optarg" + shift + ;; + + -\?|-h) func_usage ;; + --help) func_help ;; + --version) func_version ;; + + # Separate optargs to long options: + --*=*) + func_split_long_opt "$opt" + set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"} + shift + ;; + + # Separate non-argument short options: + -\?*|-h*|-n*|-v*) + func_split_short_opt "$opt" + set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"} + shift + ;; + + --) break ;; + -*) func_fatal_help "unrecognized option \`$opt'" ;; + *) set dummy "$opt" ${1+"$@"}; shift; break ;; + esac + done + + # Validate options: + + # save first non-option argument + if test "$#" -gt 0; then + nonopt="$opt" + shift + fi + + # preserve --debug + test "$opt_debug" = : || func_append preserve_args " --debug" + + case $host in + *cygwin* | *mingw* | *pw32* | *cegcc*) + # don't eliminate duplications in $postdeps and $predeps + opt_duplicate_compiler_generated_deps=: + ;; + *) + opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps + ;; + esac + + $opt_help || { + # Sanity checks first: + func_check_version_match + + if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then + func_fatal_configuration "not configured to build any kind of library" + fi + + # Darwin sucks + eval std_shrext=\"$shrext_cmds\" + + # Only execute mode is allowed to have -dlopen flags. + if test -n "$opt_dlopen" && test "$opt_mode" != execute; then + func_error "unrecognized option \`-dlopen'" + $ECHO "$help" 1>&2 + exit $EXIT_FAILURE + fi + + # Change the help message to a mode-specific one. + generic_help="$help" + help="Try \`$progname --help --mode=$opt_mode' for more information." + } + + + # Bail if the options were screwed + $exit_cmd $EXIT_FAILURE +} + + + + +## ----------- ## +## Main. ## +## ----------- ## + +# func_lalib_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_lalib_p () +{ + test -f "$1" && + $SED -e 4q "$1" 2>/dev/null \ + | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 +} + +# func_lalib_unsafe_p file +# True iff FILE is a libtool `.la' library or `.lo' object file. +# This function implements the same check as func_lalib_p without +# resorting to external programs. To this end, it redirects stdin and +# closes it afterwards, without saving the original file descriptor. +# As a safety measure, use it only where a negative result would be +# fatal anyway. Works if `file' does not exist. +func_lalib_unsafe_p () +{ + lalib_p=no + if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then + for lalib_p_l in 1 2 3 4 + do + read lalib_p_line + case "$lalib_p_line" in + \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; + esac + done + exec 0<&5 5<&- + fi + test "$lalib_p" = yes +} + +# func_ltwrapper_script_p file +# True iff FILE is a libtool wrapper script +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_script_p () +{ + func_lalib_p "$1" +} + +# func_ltwrapper_executable_p file +# True iff FILE is a libtool wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_executable_p () +{ + func_ltwrapper_exec_suffix= + case $1 in + *.exe) ;; + *) func_ltwrapper_exec_suffix=.exe ;; + esac + $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 +} + +# func_ltwrapper_scriptname file +# Assumes file is an ltwrapper_executable +# uses $file to determine the appropriate filename for a +# temporary ltwrapper_script. +func_ltwrapper_scriptname () +{ + func_dirname_and_basename "$1" "" "." + func_stripname '' '.exe' "$func_basename_result" + func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" +} + +# func_ltwrapper_p file +# True iff FILE is a libtool wrapper script or wrapper executable +# This function is only a basic sanity check; it will hardly flush out +# determined imposters. +func_ltwrapper_p () +{ + func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" +} + + +# func_execute_cmds commands fail_cmd +# Execute tilde-delimited COMMANDS. +# If FAIL_CMD is given, eval that upon failure. +# FAIL_CMD may read-access the current command in variable CMD! +func_execute_cmds () +{ + $opt_debug + save_ifs=$IFS; IFS='~' + for cmd in $1; do + IFS=$save_ifs + eval cmd=\"$cmd\" + func_show_eval "$cmd" "${2-:}" + done + IFS=$save_ifs +} + + +# func_source file +# Source FILE, adding directory component if necessary. +# Note that it is not necessary on cygwin/mingw to append a dot to +# FILE even if both FILE and FILE.exe exist: automatic-append-.exe +# behavior happens only for exec(3), not for open(2)! Also, sourcing +# `FILE.' does not work on cygwin managed mounts. +func_source () +{ + $opt_debug + case $1 in + */* | *\\*) . "$1" ;; + *) . "./$1" ;; + esac +} + + +# func_resolve_sysroot PATH +# Replace a leading = in PATH with a sysroot. Store the result into +# func_resolve_sysroot_result +func_resolve_sysroot () +{ + func_resolve_sysroot_result=$1 + case $func_resolve_sysroot_result in + =*) + func_stripname '=' '' "$func_resolve_sysroot_result" + func_resolve_sysroot_result=$lt_sysroot$func_stripname_result + ;; + esac +} + +# func_replace_sysroot PATH +# If PATH begins with the sysroot, replace it with = and +# store the result into func_replace_sysroot_result. +func_replace_sysroot () +{ + case "$lt_sysroot:$1" in + ?*:"$lt_sysroot"*) + func_stripname "$lt_sysroot" '' "$1" + func_replace_sysroot_result="=$func_stripname_result" + ;; + *) + # Including no sysroot. + func_replace_sysroot_result=$1 + ;; + esac +} + +# func_infer_tag arg +# Infer tagged configuration to use if any are available and +# if one wasn't chosen via the "--tag" command line option. +# Only attempt this if the compiler in the base compile +# command doesn't match the default compiler. +# arg is usually of the form 'gcc ...' +func_infer_tag () +{ + $opt_debug + if test -n "$available_tags" && test -z "$tagname"; then + CC_quoted= + for arg in $CC; do + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case $@ in + # Blanks in the command may have been stripped by the calling shell, + # but not from the CC environment variable when configure was run. + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; + # Blanks at the start of $base_compile will cause this to fail + # if we don't check for them as well. + *) + for z in $available_tags; do + if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then + # Evaluate the configuration. + eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" + CC_quoted= + for arg in $CC; do + # Double-quote args containing other shell metacharacters. + func_append_quoted CC_quoted "$arg" + done + CC_expanded=`func_echo_all $CC` + CC_quoted_expanded=`func_echo_all $CC_quoted` + case "$@ " in + " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ + " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) + # The compiler in the base compile command matches + # the one in the tagged configuration. + # Assume this is the tagged configuration we want. + tagname=$z + break + ;; + esac + fi + done + # If $tagname still isn't set, then no tagged configuration + # was found and let the user know that the "--tag" command + # line option must be used. + if test -z "$tagname"; then + func_echo "unable to infer tagged configuration" + func_fatal_error "specify a tag with \`--tag'" +# else +# func_verbose "using $tagname tagged configuration" + fi + ;; + esac + fi +} + + + +# func_write_libtool_object output_name pic_name nonpic_name +# Create a libtool object file (analogous to a ".la" file), +# but don't create it if we're doing a dry run. +func_write_libtool_object () +{ + write_libobj=${1} + if test "$build_libtool_libs" = yes; then + write_lobj=\'${2}\' + else + write_lobj=none + fi + + if test "$build_old_libs" = yes; then + write_oldobj=\'${3}\' + else + write_oldobj=none + fi + + $opt_dry_run || { + cat >${write_libobj}T </dev/null` + if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then + func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" | + $SED -e "$lt_sed_naive_backslashify"` + else + func_convert_core_file_wine_to_w32_result= + fi + fi +} +# end: func_convert_core_file_wine_to_w32 + + +# func_convert_core_path_wine_to_w32 ARG +# Helper function used by path conversion functions when $build is *nix, and +# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly +# configured wine environment available, with the winepath program in $build's +# $PATH. Assumes ARG has no leading or trailing path separator characters. +# +# ARG is path to be converted from $build format to win32. +# Result is available in $func_convert_core_path_wine_to_w32_result. +# Unconvertible file (directory) names in ARG are skipped; if no directory names +# are convertible, then the result may be empty. +func_convert_core_path_wine_to_w32 () +{ + $opt_debug + # unfortunately, winepath doesn't convert paths, only file names + func_convert_core_path_wine_to_w32_result="" + if test -n "$1"; then + oldIFS=$IFS + IFS=: + for func_convert_core_path_wine_to_w32_f in $1; do + IFS=$oldIFS + func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f" + if test -n "$func_convert_core_file_wine_to_w32_result" ; then + if test -z "$func_convert_core_path_wine_to_w32_result"; then + func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result" + else + func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result" + fi + fi + done + IFS=$oldIFS + fi +} +# end: func_convert_core_path_wine_to_w32 + + +# func_cygpath ARGS... +# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when +# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2) +# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or +# (2), returns the Cygwin file name or path in func_cygpath_result (input +# file name or path is assumed to be in w32 format, as previously converted +# from $build's *nix or MSYS format). In case (3), returns the w32 file name +# or path in func_cygpath_result (input file name or path is assumed to be in +# Cygwin format). Returns an empty string on error. +# +# ARGS are passed to cygpath, with the last one being the file name or path to +# be converted. +# +# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH +# environment variable; do not put it in $PATH. +func_cygpath () +{ + $opt_debug + if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then + func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null` + if test "$?" -ne 0; then + # on failure, ensure result is empty + func_cygpath_result= + fi + else + func_cygpath_result= + func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'" + fi +} +#end: func_cygpath + + +# func_convert_core_msys_to_w32 ARG +# Convert file name or path ARG from MSYS format to w32 format. Return +# result in func_convert_core_msys_to_w32_result. +func_convert_core_msys_to_w32 () +{ + $opt_debug + # awkward: cmd appends spaces to result + func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null | + $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` +} +#end: func_convert_core_msys_to_w32 + + +# func_convert_file_check ARG1 ARG2 +# Verify that ARG1 (a file name in $build format) was converted to $host +# format in ARG2. Otherwise, emit an error message, but continue (resetting +# func_to_host_file_result to ARG1). +func_convert_file_check () +{ + $opt_debug + if test -z "$2" && test -n "$1" ; then + func_error "Could not determine host file name corresponding to" + func_error " \`$1'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback: + func_to_host_file_result="$1" + fi +} +# end func_convert_file_check + + +# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH +# Verify that FROM_PATH (a path in $build format) was converted to $host +# format in TO_PATH. Otherwise, emit an error message, but continue, resetting +# func_to_host_file_result to a simplistic fallback value (see below). +func_convert_path_check () +{ + $opt_debug + if test -z "$4" && test -n "$3"; then + func_error "Could not determine the host path corresponding to" + func_error " \`$3'" + func_error "Continuing, but uninstalled executables may not work." + # Fallback. This is a deliberately simplistic "conversion" and + # should not be "improved". See libtool.info. + if test "x$1" != "x$2"; then + lt_replace_pathsep_chars="s|$1|$2|g" + func_to_host_path_result=`echo "$3" | + $SED -e "$lt_replace_pathsep_chars"` + else + func_to_host_path_result="$3" + fi + fi +} +# end func_convert_path_check + + +# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG +# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT +# and appending REPL if ORIG matches BACKPAT. +func_convert_path_front_back_pathsep () +{ + $opt_debug + case $4 in + $1 ) func_to_host_path_result="$3$func_to_host_path_result" + ;; + esac + case $4 in + $2 ) func_append func_to_host_path_result "$3" + ;; + esac +} +# end func_convert_path_front_back_pathsep + + +################################################## +# $build to $host FILE NAME CONVERSION FUNCTIONS # +################################################## +# invoked via `$to_host_file_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# Result will be available in $func_to_host_file_result. + + +# func_to_host_file ARG +# Converts the file name ARG from $build format to $host format. Return result +# in func_to_host_file_result. +func_to_host_file () +{ + $opt_debug + $to_host_file_cmd "$1" +} +# end func_to_host_file + + +# func_to_tool_file ARG LAZY +# converts the file name ARG from $build format to toolchain format. Return +# result in func_to_tool_file_result. If the conversion in use is listed +# in (the comma separated) LAZY, no conversion takes place. +func_to_tool_file () +{ + $opt_debug + case ,$2, in + *,"$to_tool_file_cmd",*) + func_to_tool_file_result=$1 + ;; + *) + $to_tool_file_cmd "$1" + func_to_tool_file_result=$func_to_host_file_result + ;; + esac +} +# end func_to_tool_file + + +# func_convert_file_noop ARG +# Copy ARG to func_to_host_file_result. +func_convert_file_noop () +{ + func_to_host_file_result="$1" +} +# end func_convert_file_noop + + +# func_convert_file_msys_to_w32 ARG +# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_file_result. +func_convert_file_msys_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_to_host_file_result="$func_convert_core_msys_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_w32 + + +# func_convert_file_cygwin_to_w32 ARG +# Convert file name ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_file_cygwin_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # because $build is cygwin, we call "the" cygpath in $PATH; no need to use + # LT_CYGPATH in this case. + func_to_host_file_result=`cygpath -m "$1"` + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_cygwin_to_w32 + + +# func_convert_file_nix_to_w32 ARG +# Convert file name ARG from *nix to w32 format. Requires a wine environment +# and a working winepath. Returns result in func_to_host_file_result. +func_convert_file_nix_to_w32 () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_file_wine_to_w32 "$1" + func_to_host_file_result="$func_convert_core_file_wine_to_w32_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_w32 + + +# func_convert_file_msys_to_cygwin ARG +# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_file_msys_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + func_convert_core_msys_to_w32 "$1" + func_cygpath -u "$func_convert_core_msys_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_msys_to_cygwin + + +# func_convert_file_nix_to_cygwin ARG +# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed +# in a wine environment, working winepath, and LT_CYGPATH set. Returns result +# in func_to_host_file_result. +func_convert_file_nix_to_cygwin () +{ + $opt_debug + func_to_host_file_result="$1" + if test -n "$1"; then + # convert from *nix to w32, then use cygpath to convert from w32 to cygwin. + func_convert_core_file_wine_to_w32 "$1" + func_cygpath -u "$func_convert_core_file_wine_to_w32_result" + func_to_host_file_result="$func_cygpath_result" + fi + func_convert_file_check "$1" "$func_to_host_file_result" +} +# end func_convert_file_nix_to_cygwin + + +############################################# +# $build to $host PATH CONVERSION FUNCTIONS # +############################################# +# invoked via `$to_host_path_cmd ARG' +# +# In each case, ARG is the path to be converted from $build to $host format. +# The result will be available in $func_to_host_path_result. +# +# Path separators are also converted from $build format to $host format. If +# ARG begins or ends with a path separator character, it is preserved (but +# converted to $host format) on output. +# +# All path conversion functions are named using the following convention: +# file name conversion function : func_convert_file_X_to_Y () +# path conversion function : func_convert_path_X_to_Y () +# where, for any given $build/$host combination the 'X_to_Y' value is the +# same. If conversion functions are added for new $build/$host combinations, +# the two new functions must follow this pattern, or func_init_to_host_path_cmd +# will break. + + +# func_init_to_host_path_cmd +# Ensures that function "pointer" variable $to_host_path_cmd is set to the +# appropriate value, based on the value of $to_host_file_cmd. +to_host_path_cmd= +func_init_to_host_path_cmd () +{ + $opt_debug + if test -z "$to_host_path_cmd"; then + func_stripname 'func_convert_file_' '' "$to_host_file_cmd" + to_host_path_cmd="func_convert_path_${func_stripname_result}" + fi +} + + +# func_to_host_path ARG +# Converts the path ARG from $build format to $host format. Return result +# in func_to_host_path_result. +func_to_host_path () +{ + $opt_debug + func_init_to_host_path_cmd + $to_host_path_cmd "$1" +} +# end func_to_host_path + + +# func_convert_path_noop ARG +# Copy ARG to func_to_host_path_result. +func_convert_path_noop () +{ + func_to_host_path_result="$1" +} +# end func_convert_path_noop + + +# func_convert_path_msys_to_w32 ARG +# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic +# conversion to w32 is not available inside the cwrapper. Returns result in +# func_to_host_path_result. +func_convert_path_msys_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from ARG. MSYS + # behavior is inconsistent here; cygpath turns them into '.;' and ';.'; + # and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_msys_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_msys_to_w32 + + +# func_convert_path_cygwin_to_w32 ARG +# Convert path ARG from Cygwin to w32 format. Returns result in +# func_to_host_file_result. +func_convert_path_cygwin_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"` + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_cygwin_to_w32 + + +# func_convert_path_nix_to_w32 ARG +# Convert path ARG from *nix to w32 format. Requires a wine environment and +# a working winepath. Returns result in func_to_host_file_result. +func_convert_path_nix_to_w32 () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_to_host_path_result="$func_convert_core_path_wine_to_w32_result" + func_convert_path_check : ";" \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" ";" "$1" + fi +} +# end func_convert_path_nix_to_w32 + + +# func_convert_path_msys_to_cygwin ARG +# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set. +# Returns result in func_to_host_file_result. +func_convert_path_msys_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # See func_convert_path_msys_to_w32: + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_msys_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_msys_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_msys_to_cygwin + + +# func_convert_path_nix_to_cygwin ARG +# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a +# a wine environment, working winepath, and LT_CYGPATH set. Returns result in +# func_to_host_file_result. +func_convert_path_nix_to_cygwin () +{ + $opt_debug + func_to_host_path_result="$1" + if test -n "$1"; then + # Remove leading and trailing path separator characters from + # ARG. msys behavior is inconsistent here, cygpath turns them + # into '.;' and ';.', and winepath ignores them completely. + func_stripname : : "$1" + func_to_host_path_tmp1=$func_stripname_result + func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1" + func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result" + func_to_host_path_result="$func_cygpath_result" + func_convert_path_check : : \ + "$func_to_host_path_tmp1" "$func_to_host_path_result" + func_convert_path_front_back_pathsep ":*" "*:" : "$1" + fi +} +# end func_convert_path_nix_to_cygwin + + +# func_mode_compile arg... +func_mode_compile () +{ + $opt_debug + # Get the compilation command and the source file. + base_compile= + srcfile="$nonopt" # always keep a non-empty value in "srcfile" + suppress_opt=yes + suppress_output= + arg_mode=normal + libobj= + later= + pie_flag= + + for arg + do + case $arg_mode in + arg ) + # do not "continue". Instead, add this to base_compile + lastarg="$arg" + arg_mode=normal + ;; + + target ) + libobj="$arg" + arg_mode=normal + continue + ;; + + normal ) + # Accept any command-line options. + case $arg in + -o) + test -n "$libobj" && \ + func_fatal_error "you cannot specify \`-o' more than once" + arg_mode=target + continue + ;; + + -pie | -fpie | -fPIE) + func_append pie_flag " $arg" + continue + ;; + + -shared | -static | -prefer-pic | -prefer-non-pic) + func_append later " $arg" + continue + ;; + + -no-suppress) + suppress_opt=no + continue + ;; + + -Xcompiler) + arg_mode=arg # the next one goes into the "base_compile" arg list + continue # The current "srcfile" will either be retained or + ;; # replaced later. I would guess that would be a bug. + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + lastarg= + save_ifs="$IFS"; IFS=',' + for arg in $args; do + IFS="$save_ifs" + func_append_quoted lastarg "$arg" + done + IFS="$save_ifs" + func_stripname ' ' '' "$lastarg" + lastarg=$func_stripname_result + + # Add the arguments to base_compile. + func_append base_compile " $lastarg" + continue + ;; + + *) + # Accept the current argument as the source file. + # The previous "srcfile" becomes the current argument. + # + lastarg="$srcfile" + srcfile="$arg" + ;; + esac # case $arg + ;; + esac # case $arg_mode + + # Aesthetically quote the previous argument. + func_append_quoted base_compile "$lastarg" + done # for arg + + case $arg_mode in + arg) + func_fatal_error "you must specify an argument for -Xcompile" + ;; + target) + func_fatal_error "you must specify a target with \`-o'" + ;; + *) + # Get the name of the library object. + test -z "$libobj" && { + func_basename "$srcfile" + libobj="$func_basename_result" + } + ;; + esac + + # Recognize several different file suffixes. + # If the user specifies -o file.o, it is replaced with file.lo + case $libobj in + *.[cCFSifmso] | \ + *.ada | *.adb | *.ads | *.asm | \ + *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \ + *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup) + func_xform "$libobj" + libobj=$func_xform_result + ;; + esac + + case $libobj in + *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;; + *) + func_fatal_error "cannot determine name of library object from \`$libobj'" + ;; + esac + + func_infer_tag $base_compile + + for arg in $later; do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + continue + ;; + + -static) + build_libtool_libs=no + build_old_libs=yes + continue + ;; + + -prefer-pic) + pic_mode=yes + continue + ;; + + -prefer-non-pic) + pic_mode=no + continue + ;; + esac + done + + func_quote_for_eval "$libobj" + test "X$libobj" != "X$func_quote_for_eval_result" \ + && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \ + && func_warning "libobj name \`$libobj' may not contain shell special characters." + func_dirname_and_basename "$obj" "/" "" + objname="$func_basename_result" + xdir="$func_dirname_result" + lobj=${xdir}$objdir/$objname + + test -z "$base_compile" && \ + func_fatal_help "you must specify a compilation command" + + # Delete any leftover library objects. + if test "$build_old_libs" = yes; then + removelist="$obj $lobj $libobj ${libobj}T" + else + removelist="$lobj $libobj ${libobj}T" + fi + + # On Cygwin there's no "real" PIC flag so we must build both object types + case $host_os in + cygwin* | mingw* | pw32* | os2* | cegcc*) + pic_mode=default + ;; + esac + if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then + # non-PIC code in shared libraries is not supported + pic_mode=default + fi + + # Calculate the filename of the output object if compiler does + # not support -o with -c + if test "$compiler_c_o" = no; then + output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} + lockfile="$output_obj.lock" + else + output_obj= + need_locks=no + lockfile= + fi + + # Lock this critical section if it is needed + # We use this script file to make the link, it avoids creating a new file + if test "$need_locks" = yes; then + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + elif test "$need_locks" = warn; then + if test -f "$lockfile"; then + $ECHO "\ +*** ERROR, $lockfile exists and contains: +`cat $lockfile 2>/dev/null` + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + func_append removelist " $output_obj" + $ECHO "$srcfile" > "$lockfile" + fi + + $opt_dry_run || $RM $removelist + func_append removelist " $lockfile" + trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 + + func_to_tool_file "$srcfile" func_convert_file_msys_to_w32 + srcfile=$func_to_tool_file_result + func_quote_for_eval "$srcfile" + qsrcfile=$func_quote_for_eval_result + + # Only build a PIC object if we are building libtool libraries. + if test "$build_libtool_libs" = yes; then + # Without this assignment, base_compile gets emptied. + fbsd_hideous_sh_bug=$base_compile + + if test "$pic_mode" != no; then + command="$base_compile $qsrcfile $pic_flag" + else + # Don't build PIC code + command="$base_compile $qsrcfile" + fi + + func_mkdir_p "$xdir$objdir" + + if test -z "$output_obj"; then + # Place PIC objects in $objdir + func_append command " -o $lobj" + fi + + func_show_eval_locale "$command" \ + 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed, then go on to compile the next one + if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then + func_show_eval '$MV "$output_obj" "$lobj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + + # Allow error messages only from the first compilation. + if test "$suppress_opt" = yes; then + suppress_output=' >/dev/null 2>&1' + fi + fi + + # Only build a position-dependent object if we build old libraries. + if test "$build_old_libs" = yes; then + if test "$pic_mode" != yes; then + # Don't build PIC code + command="$base_compile $qsrcfile$pie_flag" + else + command="$base_compile $qsrcfile $pic_flag" + fi + if test "$compiler_c_o" = yes; then + func_append command " -o $obj" + fi + + # Suppress compiler output if we already did a PIC compilation. + func_append command "$suppress_output" + func_show_eval_locale "$command" \ + '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' + + if test "$need_locks" = warn && + test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then + $ECHO "\ +*** ERROR, $lockfile contains: +`cat $lockfile 2>/dev/null` + +but it should contain: +$srcfile + +This indicates that another process is trying to use the same +temporary object file, and libtool could not work around it because +your compiler does not support \`-c' and \`-o' together. If you +repeat this compilation, it may succeed, by chance, but you had better +avoid parallel builds (make -j) in this platform, or get a better +compiler." + + $opt_dry_run || $RM $removelist + exit $EXIT_FAILURE + fi + + # Just move the object if needed + if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then + func_show_eval '$MV "$output_obj" "$obj"' \ + 'error=$?; $opt_dry_run || $RM $removelist; exit $error' + fi + fi + + $opt_dry_run || { + func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" + + # Unlock the critical section if it was locked + if test "$need_locks" != no; then + removelist=$lockfile + $RM "$lockfile" + fi + } + + exit $EXIT_SUCCESS +} + +$opt_help || { + test "$opt_mode" = compile && func_mode_compile ${1+"$@"} +} + +func_mode_help () +{ + # We need to display help for each of the modes. + case $opt_mode in + "") + # Generic help is extracted from the usage comments + # at the start of this file. + func_help + ;; + + clean) + $ECHO \ +"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... + +Remove files from the build directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, object or program, all the files associated +with it are deleted. Otherwise, only FILE itself is deleted using RM." + ;; + + compile) + $ECHO \ +"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE + +Compile a source file into a libtool library object. + +This mode accepts the following additional options: + + -o OUTPUT-FILE set the output file name to OUTPUT-FILE + -no-suppress do not suppress compiler output for multiple passes + -prefer-pic try to build PIC objects only + -prefer-non-pic try to build non-PIC objects only + -shared do not build a \`.o' file suitable for static linking + -static only build a \`.o' file suitable for static linking + -Wc,FLAG pass FLAG directly to the compiler + +COMPILE-COMMAND is a command to be used in creating a \`standard' object file +from the given SOURCEFILE. + +The output file name is determined by removing the directory component from +SOURCEFILE, then substituting the C source code suffix \`.c' with the +library object suffix, \`.lo'." + ;; + + execute) + $ECHO \ +"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... + +Automatically set library path, then run a program. + +This mode accepts the following additional options: + + -dlopen FILE add the directory containing FILE to the library path + +This mode sets the library path environment variable according to \`-dlopen' +flags. + +If any of the ARGS are libtool executable wrappers, then they are translated +into their corresponding uninstalled binary, and any of their required library +directories are added to the library path. + +Then, COMMAND is executed, with ARGS as arguments." + ;; + + finish) + $ECHO \ +"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... + +Complete the installation of libtool libraries. + +Each LIBDIR is a directory that contains libtool libraries. + +The commands that this mode executes may require superuser privileges. Use +the \`--dry-run' option if you just want to see what would be executed." + ;; + + install) + $ECHO \ +"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... + +Install executables or libraries. + +INSTALL-COMMAND is the installation command. The first component should be +either the \`install' or \`cp' program. + +The following components of INSTALL-COMMAND are treated specially: + + -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation + +The rest of the components are interpreted as arguments to that command (only +BSD-compatible install options are recognized)." + ;; + + link) + $ECHO \ +"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... + +Link object files or libraries together to form another library, or to +create an executable program. + +LINK-COMMAND is a command using the C compiler that you would use to create +a program from several object files. + +The following components of LINK-COMMAND are treated specially: + + -all-static do not do any dynamic linking at all + -avoid-version do not add a version suffix if possible + -bindir BINDIR specify path to binaries directory (for systems where + libraries must be found in the PATH setting at runtime) + -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime + -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols + -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) + -export-symbols SYMFILE + try to export only the symbols listed in SYMFILE + -export-symbols-regex REGEX + try to export only the symbols matching REGEX + -LLIBDIR search LIBDIR for required installed libraries + -lNAME OUTPUT-FILE requires the installed library libNAME + -module build a library that can dlopened + -no-fast-install disable the fast-install mode + -no-install link a not-installable executable + -no-undefined declare that a library does not refer to external symbols + -o OUTPUT-FILE create OUTPUT-FILE from the specified objects + -objectlist FILE Use a list of object files found in FILE to specify objects + -precious-files-regex REGEX + don't remove output files matching REGEX + -release RELEASE specify package release information + -rpath LIBDIR the created library will eventually be installed in LIBDIR + -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries + -shared only do dynamic linking of libtool libraries + -shrext SUFFIX override the standard shared library file extension + -static do not do any dynamic linking of uninstalled libtool libraries + -static-libtool-libs + do not do any dynamic linking of libtool libraries + -version-info CURRENT[:REVISION[:AGE]] + specify library version info [each variable defaults to 0] + -weak LIBNAME declare that the target provides the LIBNAME interface + -Wc,FLAG + -Xcompiler FLAG pass linker-specific FLAG directly to the compiler + -Wl,FLAG + -Xlinker FLAG pass linker-specific FLAG directly to the linker + -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) + +All other options (arguments beginning with \`-') are ignored. + +Every other argument is treated as a filename. Files ending in \`.la' are +treated as uninstalled libtool libraries, other files are standard or library +object files. + +If the OUTPUT-FILE ends in \`.la', then a libtool library is created, +only library objects (\`.lo' files) may be specified, and \`-rpath' is +required, except when creating a convenience library. + +If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created +using \`ar' and \`ranlib', or on Windows using \`lib'. + +If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file +is created, otherwise an executable program is created." + ;; + + uninstall) + $ECHO \ +"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... + +Remove libraries from an installation directory. + +RM is the name of the program to use to delete files associated with each FILE +(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed +to RM. + +If FILE is a libtool library, all the files associated with it are deleted. +Otherwise, only FILE itself is deleted using RM." + ;; + + *) + func_fatal_help "invalid operation mode \`$opt_mode'" + ;; + esac + + echo + $ECHO "Try \`$progname --help' for more information about other modes." +} + +# Now that we've collected a possible --mode arg, show help if necessary +if $opt_help; then + if test "$opt_help" = :; then + func_mode_help + else + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + func_mode_help + done + } | sed -n '1p; 2,$s/^Usage:/ or: /p' + { + func_help noexit + for opt_mode in compile link execute install finish uninstall clean; do + echo + func_mode_help + done + } | + sed '1d + /^When reporting/,/^Report/{ + H + d + } + $x + /information about other modes/d + /more detailed .*MODE/d + s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' + fi + exit $? +fi + + +# func_mode_execute arg... +func_mode_execute () +{ + $opt_debug + # The first argument is the command name. + cmd="$nonopt" + test -z "$cmd" && \ + func_fatal_help "you must specify a COMMAND" + + # Handle -dlopen flags immediately. + for file in $opt_dlopen; do + test -f "$file" \ + || func_fatal_help "\`$file' is not a file" + + dir= + case $file in + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$lib' is not a valid libtool archive" + + # Read the libtool library. + dlname= + library_names= + func_source "$file" + + # Skip this library if it cannot be dlopened. + if test -z "$dlname"; then + # Warn if it was a shared library. + test -n "$library_names" && \ + func_warning "\`$file' was not linked with \`-export-dynamic'" + continue + fi + + func_dirname "$file" "" "." + dir="$func_dirname_result" + + if test -f "$dir/$objdir/$dlname"; then + func_append dir "/$objdir" + else + if test ! -f "$dir/$dlname"; then + func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" + fi + fi + ;; + + *.lo) + # Just add the directory containing the .lo file. + func_dirname "$file" "" "." + dir="$func_dirname_result" + ;; + + *) + func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" + continue + ;; + esac + + # Get the absolute pathname. + absdir=`cd "$dir" && pwd` + test -n "$absdir" && dir="$absdir" + + # Now add the directory to shlibpath_var. + if eval "test -z \"\$$shlibpath_var\""; then + eval "$shlibpath_var=\"\$dir\"" + else + eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\"" + fi + done + + # This variable tells wrapper scripts just to set shlibpath_var + # rather than running their programs. + libtool_execute_magic="$magic" + + # Check if any of the arguments is a wrapper script. + args= + for file + do + case $file in + -* | *.la | *.lo ) ;; + *) + # Do a test to see if this is really a libtool program. + if func_ltwrapper_script_p "$file"; then + func_source "$file" + # Transform arg to wrapped name. + file="$progdir/$program" + elif func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + func_source "$func_ltwrapper_scriptname_result" + # Transform arg to wrapped name. + file="$progdir/$program" + fi + ;; + esac + # Quote arguments (to preserve shell metacharacters). + func_append_quoted args "$file" + done + + if test "X$opt_dry_run" = Xfalse; then + if test -n "$shlibpath_var"; then + # Export the shlibpath_var. + eval "export $shlibpath_var" + fi + + # Restore saved environment variables + for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES + do + eval "if test \"\${save_$lt_var+set}\" = set; then + $lt_var=\$save_$lt_var; export $lt_var + else + $lt_unset $lt_var + fi" + done + + # Now prepare to actually exec the command. + exec_cmd="\$cmd$args" + else + # Display what would be done. + if test -n "$shlibpath_var"; then + eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" + echo "export $shlibpath_var" + fi + $ECHO "$cmd$args" + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = execute && func_mode_execute ${1+"$@"} + + +# func_mode_finish arg... +func_mode_finish () +{ + $opt_debug + libs= + libdirs= + admincmds= + + for opt in "$nonopt" ${1+"$@"} + do + if test -d "$opt"; then + func_append libdirs " $opt" + + elif test -f "$opt"; then + if func_lalib_unsafe_p "$opt"; then + func_append libs " $opt" + else + func_warning "\`$opt' is not a valid libtool archive" + fi + + else + func_fatal_error "invalid argument \`$opt'" + fi + done + + if test -n "$libs"; then + if test -n "$lt_sysroot"; then + sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"` + sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;" + else + sysroot_cmd= + fi + + # Remove sysroot references + if $opt_dry_run; then + for lib in $libs; do + echo "removing references to $lt_sysroot and \`=' prefixes from $lib" + done + else + tmpdir=`func_mktempdir` + for lib in $libs; do + sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \ + > $tmpdir/tmp-la + mv -f $tmpdir/tmp-la $lib + done + ${RM}r "$tmpdir" + fi + fi + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + for libdir in $libdirs; do + if test -n "$finish_cmds"; then + # Do each command in the finish commands. + func_execute_cmds "$finish_cmds" 'admincmds="$admincmds +'"$cmd"'"' + fi + if test -n "$finish_eval"; then + # Do the single finish_eval. + eval cmds=\"$finish_eval\" + $opt_dry_run || eval "$cmds" || func_append admincmds " + $cmds" + fi + done + fi + + # Exit here if they wanted silent mode. + $opt_silent && exit $EXIT_SUCCESS + + if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then + echo "----------------------------------------------------------------------" + echo "Libraries have been installed in:" + for libdir in $libdirs; do + $ECHO " $libdir" + done + echo + echo "If you ever happen to want to link against installed libraries" + echo "in a given directory, LIBDIR, you must either use libtool, and" + echo "specify the full pathname of the library, or use the \`-LLIBDIR'" + echo "flag during linking and do at least one of the following:" + if test -n "$shlibpath_var"; then + echo " - add LIBDIR to the \`$shlibpath_var' environment variable" + echo " during execution" + fi + if test -n "$runpath_var"; then + echo " - add LIBDIR to the \`$runpath_var' environment variable" + echo " during linking" + fi + if test -n "$hardcode_libdir_flag_spec"; then + libdir=LIBDIR + eval flag=\"$hardcode_libdir_flag_spec\" + + $ECHO " - use the \`$flag' linker flag" + fi + if test -n "$admincmds"; then + $ECHO " - have your system administrator run these commands:$admincmds" + fi + if test -f /etc/ld.so.conf; then + echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" + fi + echo + + echo "See any operating system documentation about shared libraries for" + case $host in + solaris2.[6789]|solaris2.1[0-9]) + echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" + echo "pages." + ;; + *) + echo "more information, such as the ld(1) and ld.so(8) manual pages." + ;; + esac + echo "----------------------------------------------------------------------" + fi + exit $EXIT_SUCCESS +} + +test "$opt_mode" = finish && func_mode_finish ${1+"$@"} + + +# func_mode_install arg... +func_mode_install () +{ + $opt_debug + # There may be an optional sh(1) argument at the beginning of + # install_prog (especially on Windows NT). + if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || + # Allow the use of GNU shtool's install command. + case $nonopt in *shtool*) :;; *) false;; esac; then + # Aesthetically quote it. + func_quote_for_eval "$nonopt" + install_prog="$func_quote_for_eval_result " + arg=$1 + shift + else + install_prog= + arg=$nonopt + fi + + # The real first argument should be the name of the installation program. + # Aesthetically quote it. + func_quote_for_eval "$arg" + func_append install_prog "$func_quote_for_eval_result" + install_shared_prog=$install_prog + case " $install_prog " in + *[\\\ /]cp\ *) install_cp=: ;; + *) install_cp=false ;; + esac + + # We need to accept at least all the BSD install flags. + dest= + files= + opts= + prev= + install_type= + isdir=no + stripme= + no_mode=: + for arg + do + arg2= + if test -n "$dest"; then + func_append files " $dest" + dest=$arg + continue + fi + + case $arg in + -d) isdir=yes ;; + -f) + if $install_cp; then :; else + prev=$arg + fi + ;; + -g | -m | -o) + prev=$arg + ;; + -s) + stripme=" -s" + continue + ;; + -*) + ;; + *) + # If the previous option needed an argument, then skip it. + if test -n "$prev"; then + if test "x$prev" = x-m && test -n "$install_override_mode"; then + arg2=$install_override_mode + no_mode=false + fi + prev= + else + dest=$arg + continue + fi + ;; + esac + + # Aesthetically quote the argument. + func_quote_for_eval "$arg" + func_append install_prog " $func_quote_for_eval_result" + if test -n "$arg2"; then + func_quote_for_eval "$arg2" + fi + func_append install_shared_prog " $func_quote_for_eval_result" + done + + test -z "$install_prog" && \ + func_fatal_help "you must specify an install program" + + test -n "$prev" && \ + func_fatal_help "the \`$prev' option requires an argument" + + if test -n "$install_override_mode" && $no_mode; then + if $install_cp; then :; else + func_quote_for_eval "$install_override_mode" + func_append install_shared_prog " -m $func_quote_for_eval_result" + fi + fi + + if test -z "$files"; then + if test -z "$dest"; then + func_fatal_help "no file or destination specified" + else + func_fatal_help "you must specify a destination" + fi + fi + + # Strip any trailing slash from the destination. + func_stripname '' '/' "$dest" + dest=$func_stripname_result + + # Check to see that the destination is a directory. + test -d "$dest" && isdir=yes + if test "$isdir" = yes; then + destdir="$dest" + destname= + else + func_dirname_and_basename "$dest" "" "." + destdir="$func_dirname_result" + destname="$func_basename_result" + + # Not a directory, so check to see that there is only one file specified. + set dummy $files; shift + test "$#" -gt 1 && \ + func_fatal_help "\`$dest' is not a directory" + fi + case $destdir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + for file in $files; do + case $file in + *.lo) ;; + *) + func_fatal_help "\`$destdir' must be an absolute directory name" + ;; + esac + done + ;; + esac + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + staticlibs= + future_libdirs= + current_libdirs= + for file in $files; do + + # Do each installation. + case $file in + *.$libext) + # Do the static libraries later. + func_append staticlibs " $file" + ;; + + *.la) + func_resolve_sysroot "$file" + file=$func_resolve_sysroot_result + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$file" \ + || func_fatal_help "\`$file' is not a valid libtool archive" + + library_names= + old_library= + relink_command= + func_source "$file" + + # Add the libdir to current_libdirs if it is the destination. + if test "X$destdir" = "X$libdir"; then + case "$current_libdirs " in + *" $libdir "*) ;; + *) func_append current_libdirs " $libdir" ;; + esac + else + # Note the libdir as a future libdir. + case "$future_libdirs " in + *" $libdir "*) ;; + *) func_append future_libdirs " $libdir" ;; + esac + fi + + func_dirname "$file" "/" "" + dir="$func_dirname_result" + func_append dir "$objdir" + + if test -n "$relink_command"; then + # Determine the prefix the user has applied to our future dir. + inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` + + # Don't allow the user to place us outside of our expected + # location b/c this prevents finding dependent libraries that + # are installed to the same prefix. + # At present, this check doesn't affect windows .dll's that + # are installed into $libdir/../bin (currently, that works fine) + # but it's something to keep an eye on. + test "$inst_prefix_dir" = "$destdir" && \ + func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" + + if test -n "$inst_prefix_dir"; then + # Stick the inst_prefix_dir data into the link command. + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` + else + relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` + fi + + func_warning "relinking \`$file'" + func_show_eval "$relink_command" \ + 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' + fi + + # See the names of the shared library. + set dummy $library_names; shift + if test -n "$1"; then + realname="$1" + shift + + srcname="$realname" + test -n "$relink_command" && srcname="$realname"T + + # Install the shared library and build the symlinks. + func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ + 'exit $?' + tstripme="$stripme" + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + case $realname in + *.dll.a) + tstripme="" + ;; + esac + ;; + esac + if test -n "$tstripme" && test -n "$striplib"; then + func_show_eval "$striplib $destdir/$realname" 'exit $?' + fi + + if test "$#" -gt 0; then + # Delete the old symlinks, and create new ones. + # Try `ln -sf' first, because the `ln' binary might depend on + # the symlink we replace! Solaris /bin/ln does not understand -f, + # so we also need to try rm && ln -s. + for linkname + do + test "$linkname" != "$realname" \ + && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" + done + fi + + # Do each command in the postinstall commands. + lib="$destdir/$realname" + func_execute_cmds "$postinstall_cmds" 'exit $?' + fi + + # Install the pseudo-library for information purposes. + func_basename "$file" + name="$func_basename_result" + instname="$dir/$name"i + func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' + + # Maybe install the static library, too. + test -n "$old_library" && func_append staticlibs " $dir/$old_library" + ;; + + *.lo) + # Install (i.e. copy) a libtool object. + + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # Deduce the name of the destination old-style object file. + case $destfile in + *.lo) + func_lo2o "$destfile" + staticdest=$func_lo2o_result + ;; + *.$objext) + staticdest="$destfile" + destfile= + ;; + *) + func_fatal_help "cannot copy a libtool object to \`$destfile'" + ;; + esac + + # Install the libtool object if requested. + test -n "$destfile" && \ + func_show_eval "$install_prog $file $destfile" 'exit $?' + + # Install the old object if enabled. + if test "$build_old_libs" = yes; then + # Deduce the name of the old-style object file. + func_lo2o "$file" + staticobj=$func_lo2o_result + func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' + fi + exit $EXIT_SUCCESS + ;; + + *) + # Figure out destination file name, if it wasn't already specified. + if test -n "$destname"; then + destfile="$destdir/$destname" + else + func_basename "$file" + destfile="$func_basename_result" + destfile="$destdir/$destfile" + fi + + # If the file is missing, and there is a .exe on the end, strip it + # because it is most likely a libtool script we actually want to + # install + stripped_ext="" + case $file in + *.exe) + if test ! -f "$file"; then + func_stripname '' '.exe' "$file" + file=$func_stripname_result + stripped_ext=".exe" + fi + ;; + esac + + # Do a test to see if this is really a libtool program. + case $host in + *cygwin* | *mingw*) + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + wrapper=$func_ltwrapper_scriptname_result + else + func_stripname '' '.exe' "$file" + wrapper=$func_stripname_result + fi + ;; + *) + wrapper=$file + ;; + esac + if func_ltwrapper_script_p "$wrapper"; then + notinst_deplibs= + relink_command= + + func_source "$wrapper" + + # Check the variables that should have been set. + test -z "$generated_by_libtool_version" && \ + func_fatal_error "invalid libtool wrapper script \`$wrapper'" + + finalize=yes + for lib in $notinst_deplibs; do + # Check to see that each library is installed. + libdir= + if test -f "$lib"; then + func_source "$lib" + fi + libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test + if test -n "$libdir" && test ! -f "$libfile"; then + func_warning "\`$lib' has not been installed in \`$libdir'" + finalize=no + fi + done + + relink_command= + func_source "$wrapper" + + outputname= + if test "$fast_install" = no && test -n "$relink_command"; then + $opt_dry_run || { + if test "$finalize" = yes; then + tmpdir=`func_mktempdir` + func_basename "$file$stripped_ext" + file="$func_basename_result" + outputname="$tmpdir/$file" + # Replace the output file specification. + relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` + + $opt_silent || { + func_quote_for_expand "$relink_command" + eval "func_echo $func_quote_for_expand_result" + } + if eval "$relink_command"; then : + else + func_error "error: relink \`$file' with the above command before installing it" + $opt_dry_run || ${RM}r "$tmpdir" + continue + fi + file="$outputname" + else + func_warning "cannot relink \`$file'" + fi + } + else + # Install the binary that we compiled earlier. + file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` + fi + fi + + # remove .exe since cygwin /usr/bin/install will append another + # one anyway + case $install_prog,$host in + */usr/bin/install*,*cygwin*) + case $file:$destfile in + *.exe:*.exe) + # this is ok + ;; + *.exe:*) + destfile=$destfile.exe + ;; + *:*.exe) + func_stripname '' '.exe' "$destfile" + destfile=$func_stripname_result + ;; + esac + ;; + esac + func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' + $opt_dry_run || if test -n "$outputname"; then + ${RM}r "$tmpdir" + fi + ;; + esac + done + + for file in $staticlibs; do + func_basename "$file" + name="$func_basename_result" + + # Set up the ranlib parameters. + oldlib="$destdir/$name" + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + + func_show_eval "$install_prog \$file \$oldlib" 'exit $?' + + if test -n "$stripme" && test -n "$old_striplib"; then + func_show_eval "$old_striplib $tool_oldlib" 'exit $?' + fi + + # Do each command in the postinstall commands. + func_execute_cmds "$old_postinstall_cmds" 'exit $?' + done + + test -n "$future_libdirs" && \ + func_warning "remember to run \`$progname --finish$future_libdirs'" + + if test -n "$current_libdirs"; then + # Maybe just do a dry run. + $opt_dry_run && current_libdirs=" -n$current_libdirs" + exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' + else + exit $EXIT_SUCCESS + fi +} + +test "$opt_mode" = install && func_mode_install ${1+"$@"} + + +# func_generate_dlsyms outputname originator pic_p +# Extract symbols from dlprefiles and create ${outputname}S.o with +# a dlpreopen symbol table. +func_generate_dlsyms () +{ + $opt_debug + my_outputname="$1" + my_originator="$2" + my_pic_p="${3-no}" + my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` + my_dlsyms= + + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + if test -n "$NM" && test -n "$global_symbol_pipe"; then + my_dlsyms="${my_outputname}S.c" + else + func_error "not configured to extract global symbols from dlpreopened files" + fi + fi + + if test -n "$my_dlsyms"; then + case $my_dlsyms in + "") ;; + *.c) + # Discover the nlist of each of the dlfiles. + nlist="$output_objdir/${my_outputname}.nm" + + func_show_eval "$RM $nlist ${nlist}S ${nlist}T" + + # Parse the name list into a source file. + func_verbose "creating $output_objdir/$my_dlsyms" + + $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ +/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ +/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ + +#ifdef __cplusplus +extern \"C\" { +#endif + +#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) +#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" +#endif + +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT_DLSYM_CONST +#else +# define LT_DLSYM_CONST const +#endif + +/* External symbol declarations for the compiler. */\ +" + + if test "$dlself" = yes; then + func_verbose "generating symbol list for \`$output'" + + $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" + + # Add our own program objects to the symbol list. + progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` + for progfile in $progfiles; do + func_to_tool_file "$progfile" func_convert_file_msys_to_w32 + func_verbose "extracting global C symbols from \`$func_to_tool_file_result'" + $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'" + done + + if test -n "$exclude_expsyms"; then + $opt_dry_run || { + eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + if test -n "$export_symbols_regex"; then + $opt_dry_run || { + eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + } + fi + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + export_symbols="$output_objdir/$outputname.exp" + $opt_dry_run || { + $RM $export_symbols + eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"' + ;; + esac + } + else + $opt_dry_run || { + eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"' + eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T' + eval '$MV "$nlist"T "$nlist"' + case $host in + *cygwin* | *mingw* | *cegcc* ) + eval "echo EXPORTS "'> "$output_objdir/$outputname.def"' + eval 'cat "$nlist" >> "$output_objdir/$outputname.def"' + ;; + esac + } + fi + fi + + for dlprefile in $dlprefiles; do + func_verbose "extracting global C symbols from \`$dlprefile'" + func_basename "$dlprefile" + name="$func_basename_result" + case $host in + *cygwin* | *mingw* | *cegcc* ) + # if an import library, we need to obtain dlname + if func_win32_import_lib_p "$dlprefile"; then + func_tr_sh "$dlprefile" + eval "curr_lafile=\$libfile_$func_tr_sh_result" + dlprefile_dlbasename="" + if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then + # Use subshell, to avoid clobbering current variable values + dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"` + if test -n "$dlprefile_dlname" ; then + func_basename "$dlprefile_dlname" + dlprefile_dlbasename="$func_basename_result" + else + # no lafile. user explicitly requested -dlpreopen . + $sharedlib_from_linklib_cmd "$dlprefile" + dlprefile_dlbasename=$sharedlib_from_linklib_result + fi + fi + $opt_dry_run || { + if test -n "$dlprefile_dlbasename" ; then + eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"' + else + func_warning "Could not compute DLL name from $name" + eval '$ECHO ": $name " >> "$nlist"' + fi + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe | + $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'" + } + else # not an import lib + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + fi + ;; + *) + $opt_dry_run || { + eval '$ECHO ": $name " >> "$nlist"' + func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32 + eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'" + } + ;; + esac + done + + $opt_dry_run || { + # Make sure we have at least an empty file. + test -f "$nlist" || : > "$nlist" + + if test -n "$exclude_expsyms"; then + $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T + $MV "$nlist"T "$nlist" + fi + + # Try sorting and uniquifying the output. + if $GREP -v "^: " < "$nlist" | + if sort -k 3 /dev/null 2>&1; then + sort -k 3 + else + sort +2 + fi | + uniq > "$nlist"S; then + : + else + $GREP -v "^: " < "$nlist" > "$nlist"S + fi + + if test -f "$nlist"S; then + eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' + else + echo '/* NONE */' >> "$output_objdir/$my_dlsyms" + fi + + echo >> "$output_objdir/$my_dlsyms" "\ + +/* The mapping between symbol names and symbols. */ +typedef struct { + const char *name; + void *address; +} lt_dlsymlist; +extern LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[]; +LT_DLSYM_CONST lt_dlsymlist +lt_${my_prefix}_LTX_preloaded_symbols[] = +{\ + { \"$my_originator\", (void *) 0 }," + + case $need_lib_prefix in + no) + eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + *) + eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" + ;; + esac + echo >> "$output_objdir/$my_dlsyms" "\ + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt_${my_prefix}_LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif\ +" + } # !$opt_dry_run + + pic_flag_for_symtable= + case "$compile_command " in + *" -static "*) ;; + *) + case $host in + # compiling the symbol table file with pic_flag works around + # a FreeBSD bug that causes programs to crash when -lm is + # linked before any other PIC object. But we must not use + # pic_flag when linking with -static. The problem exists in + # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. + *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) + pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; + *-*-hpux*) + pic_flag_for_symtable=" $pic_flag" ;; + *) + if test "X$my_pic_p" != Xno; then + pic_flag_for_symtable=" $pic_flag" + fi + ;; + esac + ;; + esac + symtab_cflags= + for arg in $LTCFLAGS; do + case $arg in + -pie | -fpie | -fPIE) ;; + *) func_append symtab_cflags " $arg" ;; + esac + done + + # Now compile the dynamic symbol file. + func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' + + # Clean up the generated files. + func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' + + # Transform the symbol file into the correct name. + symfileobj="$output_objdir/${my_outputname}S.$objext" + case $host in + *cygwin* | *mingw* | *cegcc* ) + if test -f "$output_objdir/$my_outputname.def"; then + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` + else + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + fi + ;; + *) + compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` + ;; + esac + ;; + *) + func_fatal_error "unknown suffix for \`$my_dlsyms'" + ;; + esac + else + # We keep going just in case the user didn't refer to + # lt_preloaded_symbols. The linker will fail if global_symbol_pipe + # really was required. + + # Nullify the symbol file. + compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` + finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` + fi +} + +# func_win32_libid arg +# return the library type of file 'arg' +# +# Need a lot of goo to handle *both* DLLs and import libs +# Has to be a shell function in order to 'eat' the argument +# that is supplied when $file_magic_command is called. +# Despite the name, also deal with 64 bit binaries. +func_win32_libid () +{ + $opt_debug + win32_libid_type="unknown" + win32_fileres=`file -L $1 2>/dev/null` + case $win32_fileres in + *ar\ archive\ import\ library*) # definitely import + win32_libid_type="x86 archive import" + ;; + *ar\ archive*) # could be an import, or static + # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD. + if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null | + $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then + func_to_tool_file "$1" func_convert_file_msys_to_w32 + win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" | + $SED -n -e ' + 1,100{ + / I /{ + s,.*,import, + p + q + } + }'` + case $win32_nmres in + import*) win32_libid_type="x86 archive import";; + *) win32_libid_type="x86 archive static";; + esac + fi + ;; + *DLL*) + win32_libid_type="x86 DLL" + ;; + *executable*) # but shell scripts are "executable" too... + case $win32_fileres in + *MS\ Windows\ PE\ Intel*) + win32_libid_type="x86 DLL" + ;; + esac + ;; + esac + $ECHO "$win32_libid_type" +} + +# func_cygming_dll_for_implib ARG +# +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib () +{ + $opt_debug + sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"` +} + +# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs +# +# The is the core of a fallback implementation of a +# platform-specific function to extract the name of the +# DLL associated with the specified import library LIBNAME. +# +# SECTION_NAME is either .idata$6 or .idata$7, depending +# on the platform and compiler that created the implib. +# +# Echos the name of the DLL associated with the +# specified import library. +func_cygming_dll_for_implib_fallback_core () +{ + $opt_debug + match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"` + $OBJDUMP -s --section "$1" "$2" 2>/dev/null | + $SED '/^Contents of section '"$match_literal"':/{ + # Place marker at beginning of archive member dllname section + s/.*/====MARK====/ + p + d + } + # These lines can sometimes be longer than 43 characters, but + # are always uninteresting + /:[ ]*file format pe[i]\{,1\}-/d + /^In archive [^:]*:/d + # Ensure marker is printed + /^====MARK====/p + # Remove all lines with less than 43 characters + /^.\{43\}/!d + # From remaining lines, remove first 43 characters + s/^.\{43\}//' | + $SED -n ' + # Join marker and all lines until next marker into a single line + /^====MARK====/ b para + H + $ b para + b + :para + x + s/\n//g + # Remove the marker + s/^====MARK====// + # Remove trailing dots and whitespace + s/[\. \t]*$// + # Print + /./p' | + # we now have a list, one entry per line, of the stringified + # contents of the appropriate section of all members of the + # archive which possess that section. Heuristic: eliminate + # all those which have a first or second character that is + # a '.' (that is, objdump's representation of an unprintable + # character.) This should work for all archives with less than + # 0x302f exports -- but will fail for DLLs whose name actually + # begins with a literal '.' or a single character followed by + # a '.'. + # + # Of those that remain, print the first one. + $SED -e '/^\./d;/^.\./d;q' +} + +# func_cygming_gnu_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is a GNU/binutils-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_gnu_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'` + test -n "$func_cygming_gnu_implib_tmp" +} + +# func_cygming_ms_implib_p ARG +# This predicate returns with zero status (TRUE) if +# ARG is an MS-style import library. Returns +# with nonzero status (FALSE) otherwise. +func_cygming_ms_implib_p () +{ + $opt_debug + func_to_tool_file "$1" func_convert_file_msys_to_w32 + func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'` + test -n "$func_cygming_ms_implib_tmp" +} + +# func_cygming_dll_for_implib_fallback ARG +# Platform-specific function to extract the +# name of the DLL associated with the specified +# import library ARG. +# +# This fallback implementation is for use when $DLLTOOL +# does not support the --identify-strict option. +# Invoked by eval'ing the libtool variable +# $sharedlib_from_linklib_cmd +# Result is available in the variable +# $sharedlib_from_linklib_result +func_cygming_dll_for_implib_fallback () +{ + $opt_debug + if func_cygming_gnu_implib_p "$1" ; then + # binutils import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"` + elif func_cygming_ms_implib_p "$1" ; then + # ms-generated import library + sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"` + else + # unknown + sharedlib_from_linklib_result="" + fi +} + + +# func_extract_an_archive dir oldlib +func_extract_an_archive () +{ + $opt_debug + f_ex_an_ar_dir="$1"; shift + f_ex_an_ar_oldlib="$1" + if test "$lock_old_archive_extraction" = yes; then + lockfile=$f_ex_an_ar_oldlib.lock + until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do + func_echo "Waiting for $lockfile to be removed" + sleep 2 + done + fi + func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ + 'stat=$?; rm -f "$lockfile"; exit $stat' + if test "$lock_old_archive_extraction" = yes; then + $opt_dry_run || rm -f "$lockfile" + fi + if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then + : + else + func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" + fi +} + + +# func_extract_archives gentop oldlib ... +func_extract_archives () +{ + $opt_debug + my_gentop="$1"; shift + my_oldlibs=${1+"$@"} + my_oldobjs="" + my_xlib="" + my_xabs="" + my_xdir="" + + for my_xlib in $my_oldlibs; do + # Extract the objects. + case $my_xlib in + [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; + *) my_xabs=`pwd`"/$my_xlib" ;; + esac + func_basename "$my_xlib" + my_xlib="$func_basename_result" + my_xlib_u=$my_xlib + while :; do + case " $extracted_archives " in + *" $my_xlib_u "*) + func_arith $extracted_serial + 1 + extracted_serial=$func_arith_result + my_xlib_u=lt$extracted_serial-$my_xlib ;; + *) break ;; + esac + done + extracted_archives="$extracted_archives $my_xlib_u" + my_xdir="$my_gentop/$my_xlib_u" + + func_mkdir_p "$my_xdir" + + case $host in + *-darwin*) + func_verbose "Extracting $my_xabs" + # Do not bother doing anything if just a dry run + $opt_dry_run || { + darwin_orig_dir=`pwd` + cd $my_xdir || exit $? + darwin_archive=$my_xabs + darwin_curdir=`pwd` + darwin_base_archive=`basename "$darwin_archive"` + darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` + if test -n "$darwin_arches"; then + darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` + darwin_arch= + func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" + for darwin_arch in $darwin_arches ; do + func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" + $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" + cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" + func_extract_an_archive "`pwd`" "${darwin_base_archive}" + cd "$darwin_curdir" + $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" + done # $darwin_arches + ## Okay now we've a bunch of thin objects, gotta fatten them up :) + darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` + darwin_file= + darwin_files= + for darwin_file in $darwin_filelist; do + darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP` + $LIPO -create -output "$darwin_file" $darwin_files + done # $darwin_filelist + $RM -rf unfat-$$ + cd "$darwin_orig_dir" + else + cd $darwin_orig_dir + func_extract_an_archive "$my_xdir" "$my_xabs" + fi # $darwin_arches + } # !$opt_dry_run + ;; + *) + func_extract_an_archive "$my_xdir" "$my_xabs" + ;; + esac + my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP` + done + + func_extract_archives_result="$my_oldobjs" +} + + +# func_emit_wrapper [arg=no] +# +# Emit a libtool wrapper script on stdout. +# Don't directly open a file because we may want to +# incorporate the script contents within a cygwin/mingw +# wrapper executable. Must ONLY be called from within +# func_mode_link because it depends on a number of variables +# set therein. +# +# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR +# variable will take. If 'yes', then the emitted script +# will assume that the directory in which it is stored is +# the $objdir directory. This is a cygwin/mingw-specific +# behavior. +func_emit_wrapper () +{ + func_emit_wrapper_arg1=${1-no} + + $ECHO "\ +#! $SHELL + +# $output - temporary wrapper script for $objdir/$outputname +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# The $output program cannot be directly executed until all the libtool +# libraries that it depends on are installed. +# +# This wrapper script should never be moved out of the build directory. +# If it is, it will not operate correctly. + +# Sed substitution that helps us do robust quoting. It backslashifies +# metacharacters that are still active within double-quoted strings. +sed_quote_subst='$sed_quote_subst' + +# Be Bourne compatible +if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +relink_command=\"$relink_command\" + +# This environment variable determines our operation mode. +if test \"\$libtool_install_magic\" = \"$magic\"; then + # install mode needs the following variables: + generated_by_libtool_version='$macro_version' + notinst_deplibs='$notinst_deplibs' +else + # When we are sourced in execute mode, \$file and \$ECHO are already set. + if test \"\$libtool_execute_magic\" != \"$magic\"; then + file=\"\$0\"" + + qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` + $ECHO "\ + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$1 +_LTECHO_EOF' +} + ECHO=\"$qECHO\" + fi + +# Very basic option parsing. These options are (a) specific to +# the libtool wrapper, (b) are identical between the wrapper +# /script/ and the wrapper /executable/ which is used only on +# windows platforms, and (c) all begin with the string "--lt-" +# (application programs are unlikely to have options which match +# this pattern). +# +# There are only two supported options: --lt-debug and +# --lt-dump-script. There is, deliberately, no --lt-help. +# +# The first argument to this parsing function should be the +# script's $0 value, followed by "$@". +lt_option_debug= +func_parse_lt_options () +{ + lt_script_arg0=\$0 + shift + for lt_opt + do + case \"\$lt_opt\" in + --lt-debug) lt_option_debug=1 ;; + --lt-dump-script) + lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\` + test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=. + lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\` + cat \"\$lt_dump_D/\$lt_dump_F\" + exit 0 + ;; + --lt-*) + \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2 + exit 1 + ;; + esac + done + + # Print the debug banner immediately: + if test -n \"\$lt_option_debug\"; then + echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2 + fi +} + +# Used when --lt-debug. Prints its arguments to stdout +# (redirection is the responsibility of the caller) +func_lt_dump_args () +{ + lt_dump_args_N=1; + for lt_arg + do + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\" + lt_dump_args_N=\`expr \$lt_dump_args_N + 1\` + done +} + +# Core function for launching the target application +func_exec_program_core () +{ +" + case $host in + # Backslashes separate directories on plain windows + *-*-mingw | *-*-os2* | *-cegcc*) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} +" + ;; + + *) + $ECHO "\ + if test -n \"\$lt_option_debug\"; then + \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2 + func_lt_dump_args \${1+\"\$@\"} 1>&2 + fi + exec \"\$progdir/\$program\" \${1+\"\$@\"} +" + ;; + esac + $ECHO "\ + \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 + exit 1 +} + +# A function to encapsulate launching the target application +# Strips options in the --lt-* namespace from \$@ and +# launches target application with the remaining arguments. +func_exec_program () +{ + case \" \$* \" in + *\\ --lt-*) + for lt_wr_arg + do + case \$lt_wr_arg in + --lt-*) ;; + *) set x \"\$@\" \"\$lt_wr_arg\"; shift;; + esac + shift + done ;; + esac + func_exec_program_core \${1+\"\$@\"} +} + + # Parse options + func_parse_lt_options \"\$0\" \${1+\"\$@\"} + + # Find the directory that this script lives in. + thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` + test \"x\$thisdir\" = \"x\$file\" && thisdir=. + + # Follow symbolic links until we get to the real thisdir. + file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` + while test -n \"\$file\"; do + destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` + + # If there was a directory component, then change thisdir. + if test \"x\$destdir\" != \"x\$file\"; then + case \"\$destdir\" in + [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; + *) thisdir=\"\$thisdir/\$destdir\" ;; + esac + fi + + file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` + file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` + done + + # Usually 'no', except on cygwin/mingw when embedded into + # the cwrapper. + WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 + if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then + # special case for '.' + if test \"\$thisdir\" = \".\"; then + thisdir=\`pwd\` + fi + # remove .libs from thisdir + case \"\$thisdir\" in + *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; + $objdir ) thisdir=. ;; + esac + fi + + # Try to get the absolute directory name. + absdir=\`cd \"\$thisdir\" && pwd\` + test -n \"\$absdir\" && thisdir=\"\$absdir\" +" + + if test "$fast_install" = yes; then + $ECHO "\ + program=lt-'$outputname'$exeext + progdir=\"\$thisdir/$objdir\" + + if test ! -f \"\$progdir/\$program\" || + { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ + test \"X\$file\" != \"X\$progdir/\$program\"; }; then + + file=\"\$\$-\$program\" + + if test ! -d \"\$progdir\"; then + $MKDIR \"\$progdir\" + else + $RM \"\$progdir/\$file\" + fi" + + $ECHO "\ + + # relink executable if necessary + if test -n \"\$relink_command\"; then + if relink_command_output=\`eval \$relink_command 2>&1\`; then : + else + $ECHO \"\$relink_command_output\" >&2 + $RM \"\$progdir/\$file\" + exit 1 + fi + fi + + $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || + { $RM \"\$progdir/\$program\"; + $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } + $RM \"\$progdir/\$file\" + fi" + else + $ECHO "\ + program='$outputname' + progdir=\"\$thisdir/$objdir\" +" + fi + + $ECHO "\ + + if test -f \"\$progdir/\$program\"; then" + + # fixup the dll searchpath if we need to. + # + # Fix the DLL searchpath if we need to. Do this before prepending + # to shlibpath, because on Windows, both are PATH and uninstalled + # libraries must come first. + if test -n "$dllsearchpath"; then + $ECHO "\ + # Add the dll search path components to the executable PATH + PATH=$dllsearchpath:\$PATH +" + fi + + # Export our shlibpath_var if we have one. + if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then + $ECHO "\ + # Add our own library path to $shlibpath_var + $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" + + # Some systems cannot cope with colon-terminated $shlibpath_var + # The second colon is a workaround for a bug in BeOS R4 sed + $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` + + export $shlibpath_var +" + fi + + $ECHO "\ + if test \"\$libtool_execute_magic\" != \"$magic\"; then + # Run the actual program with our arguments. + func_exec_program \${1+\"\$@\"} + fi + else + # The program doesn't exist. + \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 + \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 + \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 + exit 1 + fi +fi\ +" +} + + +# func_emit_cwrapperexe_src +# emit the source code for a wrapper executable on stdout +# Must ONLY be called from within func_mode_link because +# it depends on a number of variable set therein. +func_emit_cwrapperexe_src () +{ + cat < +#include +#ifdef _MSC_VER +# include +# include +# include +#else +# include +# include +# ifdef __CYGWIN__ +# include +# endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include + +/* declarations of non-ANSI functions */ +#if defined(__MINGW32__) +# ifdef __STRICT_ANSI__ +int _putenv (const char *); +# endif +#elif defined(__CYGWIN__) +# ifdef __STRICT_ANSI__ +char *realpath (const char *, char *); +int putenv (char *); +int setenv (const char *, const char *, int); +# endif +/* #elif defined (other platforms) ... */ +#endif + +/* portability defines, excluding path handling macros */ +#if defined(_MSC_VER) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +# define S_IXUSR _S_IEXEC +# ifndef _INTPTR_T_DEFINED +# define _INTPTR_T_DEFINED +# define intptr_t int +# endif +#elif defined(__MINGW32__) +# define setmode _setmode +# define stat _stat +# define chmod _chmod +# define getcwd _getcwd +# define putenv _putenv +#elif defined(__CYGWIN__) +# define HAVE_SETENV +# define FOPEN_WB "wb" +/* #elif defined (other platforms) ... */ +#endif + +#if defined(PATH_MAX) +# define LT_PATHMAX PATH_MAX +#elif defined(MAXPATHLEN) +# define LT_PATHMAX MAXPATHLEN +#else +# define LT_PATHMAX 1024 +#endif + +#ifndef S_IXOTH +# define S_IXOTH 0 +#endif +#ifndef S_IXGRP +# define S_IXGRP 0 +#endif + +/* path handling portability macros */ +#ifndef DIR_SEPARATOR +# define DIR_SEPARATOR '/' +# define PATH_SEPARATOR ':' +#endif + +#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ + defined (__OS2__) +# define HAVE_DOS_BASED_FILE_SYSTEM +# define FOPEN_WB "wb" +# ifndef DIR_SEPARATOR_2 +# define DIR_SEPARATOR_2 '\\' +# endif +# ifndef PATH_SEPARATOR_2 +# define PATH_SEPARATOR_2 ';' +# endif +#endif + +#ifndef DIR_SEPARATOR_2 +# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) +#else /* DIR_SEPARATOR_2 */ +# define IS_DIR_SEPARATOR(ch) \ + (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) +#endif /* DIR_SEPARATOR_2 */ + +#ifndef PATH_SEPARATOR_2 +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) +#else /* PATH_SEPARATOR_2 */ +# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) +#endif /* PATH_SEPARATOR_2 */ + +#ifndef FOPEN_WB +# define FOPEN_WB "w" +#endif +#ifndef _O_BINARY +# define _O_BINARY 0 +#endif + +#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) +#define XFREE(stale) do { \ + if (stale) { free ((void *) stale); stale = 0; } \ +} while (0) + +#if defined(LT_DEBUGWRAPPER) +static int lt_debug = 1; +#else +static int lt_debug = 0; +#endif + +const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */ + +void *xmalloc (size_t num); +char *xstrdup (const char *string); +const char *base_name (const char *name); +char *find_executable (const char *wrapper); +char *chase_symlinks (const char *pathspec); +int make_executable (const char *path); +int check_executable (const char *path); +char *strendzap (char *str, const char *pat); +void lt_debugprintf (const char *file, int line, const char *fmt, ...); +void lt_fatal (const char *file, int line, const char *message, ...); +static const char *nonnull (const char *s); +static const char *nonempty (const char *s); +void lt_setenv (const char *name, const char *value); +char *lt_extend_str (const char *orig_value, const char *add, int to_end); +void lt_update_exe_path (const char *name, const char *value); +void lt_update_lib_path (const char *name, const char *value); +char **prepare_spawn (char **argv); +void lt_dump_script (FILE *f); +EOF + + cat <= 0) + && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return 1; + else + return 0; +} + +int +make_executable (const char *path) +{ + int rval = 0; + struct stat st; + + lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n", + nonempty (path)); + if ((!path) || (!*path)) + return 0; + + if (stat (path, &st) >= 0) + { + rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); + } + return rval; +} + +/* Searches for the full path of the wrapper. Returns + newly allocated full path name if found, NULL otherwise + Does not chase symlinks, even on platforms that support them. +*/ +char * +find_executable (const char *wrapper) +{ + int has_slash = 0; + const char *p; + const char *p_next; + /* static buffer for getcwd */ + char tmp[LT_PATHMAX + 1]; + int tmp_len; + char *concat_name; + + lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n", + nonempty (wrapper)); + + if ((wrapper == NULL) || (*wrapper == '\0')) + return NULL; + + /* Absolute path? */ +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + else + { +#endif + if (IS_DIR_SEPARATOR (wrapper[0])) + { + concat_name = xstrdup (wrapper); + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } +#if defined (HAVE_DOS_BASED_FILE_SYSTEM) + } +#endif + + for (p = wrapper; *p; p++) + if (*p == '/') + { + has_slash = 1; + break; + } + if (!has_slash) + { + /* no slashes; search PATH */ + const char *path = getenv ("PATH"); + if (path != NULL) + { + for (p = path; *p; p = p_next) + { + const char *q; + size_t p_len; + for (q = p; *q; q++) + if (IS_PATH_SEPARATOR (*q)) + break; + p_len = q - p; + p_next = (*q == '\0' ? q : q + 1); + if (p_len == 0) + { + /* empty path: current directory */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = + XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + } + else + { + concat_name = + XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, p, p_len); + concat_name[p_len] = '/'; + strcpy (concat_name + p_len + 1, wrapper); + } + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + } + } + /* not found in PATH; assume curdir */ + } + /* Relative path | not found in path: prepend cwd */ + if (getcwd (tmp, LT_PATHMAX) == NULL) + lt_fatal (__FILE__, __LINE__, "getcwd failed: %s", + nonnull (strerror (errno))); + tmp_len = strlen (tmp); + concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); + memcpy (concat_name, tmp, tmp_len); + concat_name[tmp_len] = '/'; + strcpy (concat_name + tmp_len + 1, wrapper); + + if (check_executable (concat_name)) + return concat_name; + XFREE (concat_name); + return NULL; +} + +char * +chase_symlinks (const char *pathspec) +{ +#ifndef S_ISLNK + return xstrdup (pathspec); +#else + char buf[LT_PATHMAX]; + struct stat s; + char *tmp_pathspec = xstrdup (pathspec); + char *p; + int has_symlinks = 0; + while (strlen (tmp_pathspec) && !has_symlinks) + { + lt_debugprintf (__FILE__, __LINE__, + "checking path component for symlinks: %s\n", + tmp_pathspec); + if (lstat (tmp_pathspec, &s) == 0) + { + if (S_ISLNK (s.st_mode) != 0) + { + has_symlinks = 1; + break; + } + + /* search backwards for last DIR_SEPARATOR */ + p = tmp_pathspec + strlen (tmp_pathspec) - 1; + while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + p--; + if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) + { + /* no more DIR_SEPARATORS left */ + break; + } + *p = '\0'; + } + else + { + lt_fatal (__FILE__, __LINE__, + "error accessing file \"%s\": %s", + tmp_pathspec, nonnull (strerror (errno))); + } + } + XFREE (tmp_pathspec); + + if (!has_symlinks) + { + return xstrdup (pathspec); + } + + tmp_pathspec = realpath (pathspec, buf); + if (tmp_pathspec == 0) + { + lt_fatal (__FILE__, __LINE__, + "could not follow symlinks for %s", pathspec); + } + return xstrdup (tmp_pathspec); +#endif +} + +char * +strendzap (char *str, const char *pat) +{ + size_t len, patlen; + + assert (str != NULL); + assert (pat != NULL); + + len = strlen (str); + patlen = strlen (pat); + + if (patlen <= len) + { + str += len - patlen; + if (strcmp (str, pat) == 0) + *str = '\0'; + } + return str; +} + +void +lt_debugprintf (const char *file, int line, const char *fmt, ...) +{ + va_list args; + if (lt_debug) + { + (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line); + va_start (args, fmt); + (void) vfprintf (stderr, fmt, args); + va_end (args); + } +} + +static void +lt_error_core (int exit_status, const char *file, + int line, const char *mode, + const char *message, va_list ap) +{ + fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode); + vfprintf (stderr, message, ap); + fprintf (stderr, ".\n"); + + if (exit_status >= 0) + exit (exit_status); +} + +void +lt_fatal (const char *file, int line, const char *message, ...) +{ + va_list ap; + va_start (ap, message); + lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap); + va_end (ap); +} + +static const char * +nonnull (const char *s) +{ + return s ? s : "(null)"; +} + +static const char * +nonempty (const char *s) +{ + return (s && !*s) ? "(empty)" : nonnull (s); +} + +void +lt_setenv (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value)); + { +#ifdef HAVE_SETENV + /* always make a copy, for consistency with !HAVE_SETENV */ + char *str = xstrdup (value); + setenv (name, str, 1); +#else + int len = strlen (name) + 1 + strlen (value) + 1; + char *str = XMALLOC (char, len); + sprintf (str, "%s=%s", name, value); + if (putenv (str) != EXIT_SUCCESS) + { + XFREE (str); + } +#endif + } +} + +char * +lt_extend_str (const char *orig_value, const char *add, int to_end) +{ + char *new_value; + if (orig_value && *orig_value) + { + int orig_value_len = strlen (orig_value); + int add_len = strlen (add); + new_value = XMALLOC (char, add_len + orig_value_len + 1); + if (to_end) + { + strcpy (new_value, orig_value); + strcpy (new_value + orig_value_len, add); + } + else + { + strcpy (new_value, add); + strcpy (new_value + add_len, orig_value); + } + } + else + { + new_value = xstrdup (add); + } + return new_value; +} + +void +lt_update_exe_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_exe_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + /* some systems can't cope with a ':'-terminated path #' */ + int len = strlen (new_value); + while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) + { + new_value[len-1] = '\0'; + } + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +void +lt_update_lib_path (const char *name, const char *value) +{ + lt_debugprintf (__FILE__, __LINE__, + "(lt_update_lib_path) modifying '%s' by prepending '%s'\n", + nonnull (name), nonnull (value)); + + if (name && *name && value && *value) + { + char *new_value = lt_extend_str (getenv (name), value, 0); + lt_setenv (name, new_value); + XFREE (new_value); + } +} + +EOF + case $host_os in + mingw*) + cat <<"EOF" + +/* Prepares an argument vector before calling spawn(). + Note that spawn() does not by itself call the command interpreter + (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : + ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&v); + v.dwPlatformId == VER_PLATFORM_WIN32_NT; + }) ? "cmd.exe" : "command.com"). + Instead it simply concatenates the arguments, separated by ' ', and calls + CreateProcess(). We must quote the arguments since Win32 CreateProcess() + interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a + special way: + - Space and tab are interpreted as delimiters. They are not treated as + delimiters if they are surrounded by double quotes: "...". + - Unescaped double quotes are removed from the input. Their only effect is + that within double quotes, space and tab are treated like normal + characters. + - Backslashes not followed by double quotes are not special. + - But 2*n+1 backslashes followed by a double quote become + n backslashes followed by a double quote (n >= 0): + \" -> " + \\\" -> \" + \\\\\" -> \\" + */ +#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" +char ** +prepare_spawn (char **argv) +{ + size_t argc; + char **new_argv; + size_t i; + + /* Count number of arguments. */ + for (argc = 0; argv[argc] != NULL; argc++) + ; + + /* Allocate new argument vector. */ + new_argv = XMALLOC (char *, argc + 1); + + /* Put quoted arguments into the new argument vector. */ + for (i = 0; i < argc; i++) + { + const char *string = argv[i]; + + if (string[0] == '\0') + new_argv[i] = xstrdup ("\"\""); + else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) + { + int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); + size_t length; + unsigned int backslashes; + const char *s; + char *quoted_string; + char *p; + + length = 0; + backslashes = 0; + if (quote_around) + length++; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + length += backslashes + 1; + length++; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + length += backslashes + 1; + + quoted_string = XMALLOC (char, length + 1); + + p = quoted_string; + backslashes = 0; + if (quote_around) + *p++ = '"'; + for (s = string; *s != '\0'; s++) + { + char c = *s; + if (c == '"') + { + unsigned int j; + for (j = backslashes + 1; j > 0; j--) + *p++ = '\\'; + } + *p++ = c; + if (c == '\\') + backslashes++; + else + backslashes = 0; + } + if (quote_around) + { + unsigned int j; + for (j = backslashes; j > 0; j--) + *p++ = '\\'; + *p++ = '"'; + } + *p = '\0'; + + new_argv[i] = quoted_string; + } + else + new_argv[i] = (char *) string; + } + new_argv[argc] = NULL; + + return new_argv; +} +EOF + ;; + esac + + cat <<"EOF" +void lt_dump_script (FILE* f) +{ +EOF + func_emit_wrapper yes | + $SED -n -e ' +s/^\(.\{79\}\)\(..*\)/\1\ +\2/ +h +s/\([\\"]\)/\\\1/g +s/$/\\n/ +s/\([^\n]*\).*/ fputs ("\1", f);/p +g +D' + cat <<"EOF" +} +EOF +} +# end: func_emit_cwrapperexe_src + +# func_win32_import_lib_p ARG +# True if ARG is an import lib, as indicated by $file_magic_cmd +func_win32_import_lib_p () +{ + $opt_debug + case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in + *import*) : ;; + *) false ;; + esac +} + +# func_mode_link arg... +func_mode_link () +{ + $opt_debug + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + # It is impossible to link a dll without this setting, and + # we shouldn't force the makefile maintainer to figure out + # which system we are compiling for in order to pass an extra + # flag for every libtool invocation. + # allow_undefined=no + + # FIXME: Unfortunately, there are problems with the above when trying + # to make a dll which has undefined symbols, in which case not + # even a static library is built. For now, we need to specify + # -no-undefined on the libtool link line when we can be certain + # that all symbols are satisfied, otherwise we get a static library. + allow_undefined=yes + ;; + *) + allow_undefined=yes + ;; + esac + libtool_args=$nonopt + base_compile="$nonopt $@" + compile_command=$nonopt + finalize_command=$nonopt + + compile_rpath= + finalize_rpath= + compile_shlibpath= + finalize_shlibpath= + convenience= + old_convenience= + deplibs= + old_deplibs= + compiler_flags= + linker_flags= + dllsearchpath= + lib_search_path=`pwd` + inst_prefix_dir= + new_inherited_linker_flags= + + avoid_version=no + bindir= + dlfiles= + dlprefiles= + dlself=no + export_dynamic=no + export_symbols= + export_symbols_regex= + generated= + libobjs= + ltlibs= + module=no + no_install=no + objs= + non_pic_objects= + precious_files_regex= + prefer_static_libs=no + preload=no + prev= + prevarg= + release= + rpath= + xrpath= + perm_rpath= + temp_rpath= + thread_safe=no + vinfo= + vinfo_number=no + weak_libs= + single_module="${wl}-single_module" + func_infer_tag $base_compile + + # We need to know -static, to get the right output filenames. + for arg + do + case $arg in + -shared) + test "$build_libtool_libs" != yes && \ + func_fatal_configuration "can not build a shared library" + build_old_libs=no + break + ;; + -all-static | -static | -static-libtool-libs) + case $arg in + -all-static) + if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then + func_warning "complete static linking is impossible in this configuration" + fi + if test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + -static) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=built + ;; + -static-libtool-libs) + if test -z "$pic_flag" && test -n "$link_static_flag"; then + dlopen_self=$dlopen_self_static + fi + prefer_static_libs=yes + ;; + esac + build_libtool_libs=no + build_old_libs=yes + break + ;; + esac + done + + # See if our shared archives depend on static archives. + test -n "$old_archive_from_new_cmds" && build_old_libs=yes + + # Go through the arguments, transforming them on the way. + while test "$#" -gt 0; do + arg="$1" + shift + func_quote_for_eval "$arg" + qarg=$func_quote_for_eval_unquoted_result + func_append libtool_args " $func_quote_for_eval_result" + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + case $prev in + output) + func_append compile_command " @OUTPUT@" + func_append finalize_command " @OUTPUT@" + ;; + esac + + case $prev in + bindir) + bindir="$arg" + prev= + continue + ;; + dlfiles|dlprefiles) + if test "$preload" = no; then + # Add the symbol object into the linking commands. + func_append compile_command " @SYMFILE@" + func_append finalize_command " @SYMFILE@" + preload=yes + fi + case $arg in + *.la | *.lo) ;; # We handle these cases below. + force) + if test "$dlself" = no; then + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + self) + if test "$prev" = dlprefiles; then + dlself=yes + elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then + dlself=yes + else + dlself=needless + export_dynamic=yes + fi + prev= + continue + ;; + *) + if test "$prev" = dlfiles; then + func_append dlfiles " $arg" + else + func_append dlprefiles " $arg" + fi + prev= + continue + ;; + esac + ;; + expsyms) + export_symbols="$arg" + test -f "$arg" \ + || func_fatal_error "symbol file \`$arg' does not exist" + prev= + continue + ;; + expsyms_regex) + export_symbols_regex="$arg" + prev= + continue + ;; + framework) + case $host in + *-*-darwin*) + case "$deplibs " in + *" $qarg.ltframework "*) ;; + *) func_append deplibs " $qarg.ltframework" # this is fixed later + ;; + esac + ;; + esac + prev= + continue + ;; + inst_prefix) + inst_prefix_dir="$arg" + prev= + continue + ;; + objectlist) + if test -f "$arg"; then + save_arg=$arg + moreargs= + for fil in `cat "$save_arg"` + do +# func_append moreargs " $fil" + arg=$fil + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + done + else + func_fatal_error "link input file \`$arg' does not exist" + fi + arg=$save_arg + prev= + continue + ;; + precious_regex) + precious_files_regex="$arg" + prev= + continue + ;; + release) + release="-$arg" + prev= + continue + ;; + rpath | xrpath) + # We need an absolute path. + case $arg in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + if test "$prev" = rpath; then + case "$rpath " in + *" $arg "*) ;; + *) func_append rpath " $arg" ;; + esac + else + case "$xrpath " in + *" $arg "*) ;; + *) func_append xrpath " $arg" ;; + esac + fi + prev= + continue + ;; + shrext) + shrext_cmds="$arg" + prev= + continue + ;; + weak) + func_append weak_libs " $arg" + prev= + continue + ;; + xcclinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xcompiler) + func_append compiler_flags " $qarg" + prev= + func_append compile_command " $qarg" + func_append finalize_command " $qarg" + continue + ;; + xlinker) + func_append linker_flags " $qarg" + func_append compiler_flags " $wl$qarg" + prev= + func_append compile_command " $wl$qarg" + func_append finalize_command " $wl$qarg" + continue + ;; + *) + eval "$prev=\"\$arg\"" + prev= + continue + ;; + esac + fi # test -n "$prev" + + prevarg="$arg" + + case $arg in + -all-static) + if test -n "$link_static_flag"; then + # See comment for -static flag below, for more details. + func_append compile_command " $link_static_flag" + func_append finalize_command " $link_static_flag" + fi + continue + ;; + + -allow-undefined) + # FIXME: remove this flag sometime in the future. + func_fatal_error "\`-allow-undefined' must not be used because it is the default" + ;; + + -avoid-version) + avoid_version=yes + continue + ;; + + -bindir) + prev=bindir + continue + ;; + + -dlopen) + prev=dlfiles + continue + ;; + + -dlpreopen) + prev=dlprefiles + continue + ;; + + -export-dynamic) + export_dynamic=yes + continue + ;; + + -export-symbols | -export-symbols-regex) + if test -n "$export_symbols" || test -n "$export_symbols_regex"; then + func_fatal_error "more than one -exported-symbols argument is not allowed" + fi + if test "X$arg" = "X-export-symbols"; then + prev=expsyms + else + prev=expsyms_regex + fi + continue + ;; + + -framework) + prev=framework + continue + ;; + + -inst-prefix-dir) + prev=inst_prefix + continue + ;; + + # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* + # so, if we see these flags be careful not to treat them like -L + -L[A-Z][A-Z]*:*) + case $with_gcc/$host in + no/*-*-irix* | /*-*-irix*) + func_append compile_command " $arg" + func_append finalize_command " $arg" + ;; + esac + continue + ;; + + -L*) + func_stripname "-L" '' "$arg" + if test -z "$func_stripname_result"; then + if test "$#" -gt 0; then + func_fatal_error "require no space between \`-L' and \`$1'" + else + func_fatal_error "need path for \`-L' option" + fi + fi + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + *) + absdir=`cd "$dir" && pwd` + test -z "$absdir" && \ + func_fatal_error "cannot determine absolute directory name of \`$dir'" + dir="$absdir" + ;; + esac + case "$deplibs " in + *" -L$dir "* | *" $arg "*) + # Will only happen for absolute or sysroot arguments + ;; + *) + # Preserve sysroot, but never include relative directories + case $dir in + [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;; + *) func_append deplibs " -L$dir" ;; + esac + func_append lib_search_path " $dir" + ;; + esac + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$dir:"*) ;; + ::) dllsearchpath=$dir;; + *) func_append dllsearchpath ":$dir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + continue + ;; + + -l*) + if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) + # These systems don't actually have a C or math library (as such) + continue + ;; + *-*-os2*) + # These systems don't actually have a C library (as such) + test "X$arg" = "X-lc" && continue + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + test "X$arg" = "X-lc" && continue + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C and math libraries are in the System framework + func_append deplibs " System.ltframework" + continue + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + test "X$arg" = "X-lc" && continue + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + test "X$arg" = "X-lc" && continue + ;; + esac + elif test "X$arg" = "X-lc_r"; then + case $host in + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc_r directly, use -pthread flag. + continue + ;; + esac + fi + func_append deplibs " $arg" + continue + ;; + + -module) + module=yes + continue + ;; + + # Tru64 UNIX uses -model [arg] to determine the layout of C++ + # classes, name mangling, and exception handling. + # Darwin uses the -arch flag to determine output architecture. + -model|-arch|-isysroot|--sysroot) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + prev=xcompiler + continue + ;; + + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + func_append compiler_flags " $arg" + func_append compile_command " $arg" + func_append finalize_command " $arg" + case "$new_inherited_linker_flags " in + *" $arg "*) ;; + * ) func_append new_inherited_linker_flags " $arg" ;; + esac + continue + ;; + + -multi_module) + single_module="${wl}-multi_module" + continue + ;; + + -no-fast-install) + fast_install=no + continue + ;; + + -no-install) + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) + # The PATH hackery in wrapper scripts is required on Windows + # and Darwin in order for the loader to find any dlls it needs. + func_warning "\`-no-install' is ignored for $host" + func_warning "assuming \`-no-fast-install' instead" + fast_install=no + ;; + *) no_install=yes ;; + esac + continue + ;; + + -no-undefined) + allow_undefined=no + continue + ;; + + -objectlist) + prev=objectlist + continue + ;; + + -o) prev=output ;; + + -precious-files-regex) + prev=precious_regex + continue + ;; + + -release) + prev=release + continue + ;; + + -rpath) + prev=rpath + continue + ;; + + -R) + prev=xrpath + continue + ;; + + -R*) + func_stripname '-R' '' "$arg" + dir=$func_stripname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) ;; + =*) + func_stripname '=' '' "$dir" + dir=$lt_sysroot$func_stripname_result + ;; + *) + func_fatal_error "only absolute run-paths are allowed" + ;; + esac + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + continue + ;; + + -shared) + # The effects of -shared are defined in a previous loop. + continue + ;; + + -shrext) + prev=shrext + continue + ;; + + -static | -static-libtool-libs) + # The effects of -static are defined in a previous loop. + # We used to do the same as -all-static on platforms that + # didn't have a PIC flag, but the assumption that the effects + # would be equivalent was wrong. It would break on at least + # Digital Unix and AIX. + continue + ;; + + -thread-safe) + thread_safe=yes + continue + ;; + + -version-info) + prev=vinfo + continue + ;; + + -version-number) + prev=vinfo + vinfo_number=yes + continue + ;; + + -weak) + prev=weak + continue + ;; + + -Wc,*) + func_stripname '-Wc,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $func_quote_for_eval_result" + func_append compiler_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Wl,*) + func_stripname '-Wl,' '' "$arg" + args=$func_stripname_result + arg= + save_ifs="$IFS"; IFS=',' + for flag in $args; do + IFS="$save_ifs" + func_quote_for_eval "$flag" + func_append arg " $wl$func_quote_for_eval_result" + func_append compiler_flags " $wl$func_quote_for_eval_result" + func_append linker_flags " $func_quote_for_eval_result" + done + IFS="$save_ifs" + func_stripname ' ' '' "$arg" + arg=$func_stripname_result + ;; + + -Xcompiler) + prev=xcompiler + continue + ;; + + -Xlinker) + prev=xlinker + continue + ;; + + -XCClinker) + prev=xcclinker + continue + ;; + + # -msg_* for osf cc + -msg_*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + # Flags to be passed through unchanged, with rationale: + # -64, -mips[0-9] enable 64-bit mode for the SGI compiler + # -r[0-9][0-9]* specify processor for the SGI compiler + # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler + # +DA*, +DD* enable 64-bit mode for the HP compiler + # -q* compiler args for the IBM compiler + # -m*, -t[45]*, -txscale* architecture-specific flags for GCC + # -F/path path to uninstalled frameworks, gcc on darwin + # -p, -pg, --coverage, -fprofile-* profiling flags for GCC + # @file GCC response files + # -tp=* Portland pgcc target processor selection + # --sysroot=* for sysroot support + # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization + -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ + -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \ + -O*|-flto*|-fwhopr*|-fuse-linker-plugin) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + func_append compile_command " $arg" + func_append finalize_command " $arg" + func_append compiler_flags " $arg" + continue + ;; + + # Some other compiler flag. + -* | +*) + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + + *.$objext) + # A standard object. + func_append objs " $arg" + ;; + + *.lo) + # A libtool-controlled object. + + # Check to see that this really is a libtool object. + if func_lalib_unsafe_p "$arg"; then + pic_object= + non_pic_object= + + # Read the .lo file + func_source "$arg" + + if test -z "$pic_object" || + test -z "$non_pic_object" || + test "$pic_object" = none && + test "$non_pic_object" = none; then + func_fatal_error "cannot find name of object for \`$arg'" + fi + + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + if test "$pic_object" != none; then + # Prepend the subdirectory the object is found in. + pic_object="$xdir$pic_object" + + if test "$prev" = dlfiles; then + if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then + func_append dlfiles " $pic_object" + prev= + continue + else + # If libtool objects are unsupported, then we need to preload. + prev=dlprefiles + fi + fi + + # CHECK ME: I think I busted this. -Ossama + if test "$prev" = dlprefiles; then + # Preload the old-style object. + func_append dlprefiles " $pic_object" + prev= + fi + + # A PIC object. + func_append libobjs " $pic_object" + arg="$pic_object" + fi + + # Non-PIC object. + if test "$non_pic_object" != none; then + # Prepend the subdirectory the object is found in. + non_pic_object="$xdir$non_pic_object" + + # A standard non-PIC object + func_append non_pic_objects " $non_pic_object" + if test -z "$pic_object" || test "$pic_object" = none ; then + arg="$non_pic_object" + fi + else + # If the PIC object exists, use it instead. + # $xdir was prepended to $pic_object above. + non_pic_object="$pic_object" + func_append non_pic_objects " $non_pic_object" + fi + else + # Only an error if not doing a dry-run. + if $opt_dry_run; then + # Extract subdirectory from the argument. + func_dirname "$arg" "/" "" + xdir="$func_dirname_result" + + func_lo2o "$arg" + pic_object=$xdir$objdir/$func_lo2o_result + non_pic_object=$xdir$func_lo2o_result + func_append libobjs " $pic_object" + func_append non_pic_objects " $non_pic_object" + else + func_fatal_error "\`$arg' is not a valid libtool object" + fi + fi + ;; + + *.$libext) + # An archive. + func_append deplibs " $arg" + func_append old_deplibs " $arg" + continue + ;; + + *.la) + # A libtool-controlled library. + + func_resolve_sysroot "$arg" + if test "$prev" = dlfiles; then + # This library was specified with -dlopen. + func_append dlfiles " $func_resolve_sysroot_result" + prev= + elif test "$prev" = dlprefiles; then + # The library was specified with -dlpreopen. + func_append dlprefiles " $func_resolve_sysroot_result" + prev= + else + func_append deplibs " $func_resolve_sysroot_result" + fi + continue + ;; + + # Some other compiler argument. + *) + # Unknown arguments in both finalize_command and compile_command need + # to be aesthetically quoted because they are evaled later. + func_quote_for_eval "$arg" + arg="$func_quote_for_eval_result" + ;; + esac # arg + + # Now actually substitute the argument into the commands. + if test -n "$arg"; then + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + done # argument parsing loop + + test -n "$prev" && \ + func_fatal_help "the \`$prevarg' option requires an argument" + + if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then + eval arg=\"$export_dynamic_flag_spec\" + func_append compile_command " $arg" + func_append finalize_command " $arg" + fi + + oldlibs= + # calculate the name of the file, without its directory + func_basename "$output" + outputname="$func_basename_result" + libobjs_save="$libobjs" + + if test -n "$shlibpath_var"; then + # get the directories listed in $shlibpath_var + eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` + else + shlib_search_path= + fi + eval sys_lib_search_path=\"$sys_lib_search_path_spec\" + eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\" + + func_dirname "$output" "/" "" + output_objdir="$func_dirname_result$objdir" + func_to_tool_file "$output_objdir/" + tool_output_objdir=$func_to_tool_file_result + # Create the object directory. + func_mkdir_p "$output_objdir" + + # Determine the type of output + case $output in + "") + func_fatal_help "you must specify an output file" + ;; + *.$libext) linkmode=oldlib ;; + *.lo | *.$objext) linkmode=obj ;; + *.la) linkmode=lib ;; + *) linkmode=prog ;; # Anything else should be a program. + esac + + specialdeplibs= + + libs= + # Find all interdependent deplibs by searching for libraries + # that are linked more than once (e.g. -la -lb -la) + for deplib in $deplibs; do + if $opt_preserve_dup_deps ; then + case "$libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append libs " $deplib" + done + + if test "$linkmode" = lib; then + libs="$predeps $libs $compiler_lib_search_path $postdeps" + + # Compute libraries that are listed more than once in $predeps + # $postdeps and mark them as special (i.e., whose duplicates are + # not to be eliminated). + pre_post_deps= + if $opt_duplicate_compiler_generated_deps; then + for pre_post_dep in $predeps $postdeps; do + case "$pre_post_deps " in + *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;; + esac + func_append pre_post_deps " $pre_post_dep" + done + fi + pre_post_deps= + fi + + deplibs= + newdependency_libs= + newlib_search_path= + need_relink=no # whether we're linking any uninstalled libtool libraries + notinst_deplibs= # not-installed libtool libraries + notinst_path= # paths that contain not-installed libtool libraries + + case $linkmode in + lib) + passes="conv dlpreopen link" + for file in $dlfiles $dlprefiles; do + case $file in + *.la) ;; + *) + func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" + ;; + esac + done + ;; + prog) + compile_deplibs= + finalize_deplibs= + alldeplibs=no + newdlfiles= + newdlprefiles= + passes="conv scan dlopen dlpreopen link" + ;; + *) passes="conv" + ;; + esac + + for pass in $passes; do + # The preopen pass in lib mode reverses $deplibs; put it back here + # so that -L comes before libs that need it for instance... + if test "$linkmode,$pass" = "lib,link"; then + ## FIXME: Find the place where the list is rebuilt in the wrong + ## order, and fix it there properly + tmp_deplibs= + for deplib in $deplibs; do + tmp_deplibs="$deplib $tmp_deplibs" + done + deplibs="$tmp_deplibs" + fi + + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan"; then + libs="$deplibs" + deplibs= + fi + if test "$linkmode" = prog; then + case $pass in + dlopen) libs="$dlfiles" ;; + dlpreopen) libs="$dlprefiles" ;; + link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; + esac + fi + if test "$linkmode,$pass" = "lib,dlpreopen"; then + # Collect and forward deplibs of preopened libtool libs + for lib in $dlprefiles; do + # Ignore non-libtool-libs + dependency_libs= + func_resolve_sysroot "$lib" + case $lib in + *.la) func_source "$func_resolve_sysroot_result" ;; + esac + + # Collect preopened libtool deplibs, except any this library + # has declared as weak libs + for deplib in $dependency_libs; do + func_basename "$deplib" + deplib_base=$func_basename_result + case " $weak_libs " in + *" $deplib_base "*) ;; + *) func_append deplibs " $deplib" ;; + esac + done + done + libs="$dlprefiles" + fi + if test "$pass" = dlopen; then + # Collect dlpreopened libraries + save_deplibs="$deplibs" + deplibs= + fi + + for deplib in $libs; do + lib= + found=no + case $deplib in + -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \ + |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append compiler_flags " $deplib" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -l*) + if test "$linkmode" != lib && test "$linkmode" != prog; then + func_warning "\`-l' is ignored for archives/objects" + continue + fi + func_stripname '-l' '' "$deplib" + name=$func_stripname_result + if test "$linkmode" = lib; then + searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" + else + searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" + fi + for searchdir in $searchdirs; do + for search_ext in .la $std_shrext .so .a; do + # Search the libtool library + lib="$searchdir/lib${name}${search_ext}" + if test -f "$lib"; then + if test "$search_ext" = ".la"; then + found=yes + else + found=no + fi + break 2 + fi + done + done + if test "$found" != yes; then + # deplib doesn't seem to be a libtool library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + else # deplib is a libtool library + # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, + # We need to do some special things here, and not later. + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $deplib "*) + if func_lalib_p "$lib"; then + library_names= + old_library= + func_source "$lib" + for l in $old_library $library_names; do + ll="$l" + done + if test "X$ll" = "X$old_library" ; then # only static version available + found=no + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + lib=$ladir/$old_library + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" + fi + continue + fi + fi + ;; + *) ;; + esac + fi + fi + ;; # -l + *.ltframework) + if test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + deplibs="$deplib $deplibs" + if test "$linkmode" = lib ; then + case "$new_inherited_linker_flags " in + *" $deplib "*) ;; + * ) func_append new_inherited_linker_flags " $deplib" ;; + esac + fi + fi + continue + ;; + -L*) + case $linkmode in + lib) + deplibs="$deplib $deplibs" + test "$pass" = conv && continue + newdependency_libs="$deplib $newdependency_libs" + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + prog) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + if test "$pass" = scan; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + *) + func_warning "\`-L' is ignored for archives/objects" + ;; + esac # linkmode + continue + ;; # -L + -R*) + if test "$pass" = link; then + func_stripname '-R' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + dir=$func_resolve_sysroot_result + # Make sure the xrpath contains only unique directories. + case "$xrpath " in + *" $dir "*) ;; + *) func_append xrpath " $dir" ;; + esac + fi + deplibs="$deplib $deplibs" + continue + ;; + *.la) + func_resolve_sysroot "$deplib" + lib=$func_resolve_sysroot_result + ;; + *.$libext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + continue + fi + case $linkmode in + lib) + # Linking convenience modules into shared libraries is allowed, + # but linking other static libraries is non-portable. + case " $dlpreconveniencelibs " in + *" $deplib "*) ;; + *) + valid_a_lib=no + case $deplibs_check_method in + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ + | $EGREP "$match_pattern_regex" > /dev/null; then + valid_a_lib=yes + fi + ;; + pass_all) + valid_a_lib=yes + ;; + esac + if test "$valid_a_lib" != yes; then + echo + $ECHO "*** Warning: Trying to link with static lib archive $deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because the file extensions .$libext of this argument makes me believe" + echo "*** that it is just a static archive that I should not use here." + else + echo + $ECHO "*** Warning: Linking the shared library $output against the" + $ECHO "*** static library $deplib is not portable!" + deplibs="$deplib $deplibs" + fi + ;; + esac + continue + ;; + prog) + if test "$pass" != link; then + deplibs="$deplib $deplibs" + else + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + fi + continue + ;; + esac # linkmode + ;; # *.$libext + *.lo | *.$objext) + if test "$pass" = conv; then + deplibs="$deplib $deplibs" + elif test "$linkmode" = prog; then + if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then + # If there is no dlopen support or we're linking statically, + # we need to preload. + func_append newdlprefiles " $deplib" + compile_deplibs="$deplib $compile_deplibs" + finalize_deplibs="$deplib $finalize_deplibs" + else + func_append newdlfiles " $deplib" + fi + fi + continue + ;; + %DEPLIBS%) + alldeplibs=yes + continue + ;; + esac # case $deplib + + if test "$found" = yes || test -f "$lib"; then : + else + func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" + fi + + # Check to see that this really is a libtool archive. + func_lalib_unsafe_p "$lib" \ + || func_fatal_error "\`$lib' is not a valid libtool archive" + + func_dirname "$lib" "" "." + ladir="$func_dirname_result" + + dlname= + dlopen= + dlpreopen= + libdir= + library_names= + old_library= + inherited_linker_flags= + # If the library was installed with an old release of libtool, + # it will not redefine variables installed, or shouldnotlink + installed=yes + shouldnotlink=no + avoidtemprpath= + + + # Read the .la file + func_source "$lib" + + # Convert "-framework foo" to "foo.ltframework" + if test -n "$inherited_linker_flags"; then + tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` + for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do + case " $new_inherited_linker_flags " in + *" $tmp_inherited_linker_flag "*) ;; + *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";; + esac + done + fi + dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + if test "$linkmode,$pass" = "lib,link" || + test "$linkmode,$pass" = "prog,scan" || + { test "$linkmode" != prog && test "$linkmode" != lib; }; then + test -n "$dlopen" && func_append dlfiles " $dlopen" + test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen" + fi + + if test "$pass" = conv; then + # Only check for convenience libraries + deplibs="$lib $deplibs" + if test -z "$libdir"; then + if test -z "$old_library"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + # It is a libtool convenience library, so add in its objects. + func_append convenience " $ladir/$objdir/$old_library" + func_append old_convenience " $ladir/$objdir/$old_library" + elif test "$linkmode" != prog && test "$linkmode" != lib; then + func_fatal_error "\`$lib' is not a convenience library" + fi + tmp_libs= + for deplib in $dependency_libs; do + deplibs="$deplib $deplibs" + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done + continue + fi # $pass = conv + + + # Get the name of the library we link against. + linklib= + if test -n "$old_library" && + { test "$prefer_static_libs" = yes || + test "$prefer_static_libs,$installed" = "built,no"; }; then + linklib=$old_library + else + for l in $old_library $library_names; do + linklib="$l" + done + fi + if test -z "$linklib"; then + func_fatal_error "cannot find name of link library for \`$lib'" + fi + + # This library was specified with -dlopen. + if test "$pass" = dlopen; then + if test -z "$libdir"; then + func_fatal_error "cannot -dlopen a convenience library: \`$lib'" + fi + if test -z "$dlname" || + test "$dlopen_support" != yes || + test "$build_libtool_libs" = no; then + # If there is no dlname, no dlopen support or we're linking + # statically, we need to preload. We also need to preload any + # dependent libraries so libltdl's deplib preloader doesn't + # bomb out in the load deplibs phase. + func_append dlprefiles " $lib $dependency_libs" + else + func_append newdlfiles " $lib" + fi + continue + fi # $pass = dlopen + + # We need an absolute path. + case $ladir in + [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; + *) + abs_ladir=`cd "$ladir" && pwd` + if test -z "$abs_ladir"; then + func_warning "cannot determine absolute directory name of \`$ladir'" + func_warning "passing it literally to the linker, although it might fail" + abs_ladir="$ladir" + fi + ;; + esac + func_basename "$lib" + laname="$func_basename_result" + + # Find the relevant object directory and library name. + if test "X$installed" = Xyes; then + if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then + func_warning "library \`$lib' was moved." + dir="$ladir" + absdir="$abs_ladir" + libdir="$abs_ladir" + else + dir="$lt_sysroot$libdir" + absdir="$lt_sysroot$libdir" + fi + test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes + else + if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then + dir="$ladir" + absdir="$abs_ladir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + else + dir="$ladir/$objdir" + absdir="$abs_ladir/$objdir" + # Remove this search path later + func_append notinst_path " $abs_ladir" + fi + fi # $installed = yes + func_stripname 'lib' '.la' "$laname" + name=$func_stripname_result + + # This library was specified with -dlpreopen. + if test "$pass" = dlpreopen; then + if test -z "$libdir" && test "$linkmode" = prog; then + func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" + fi + case "$host" in + # special handling for platforms with PE-DLLs. + *cygwin* | *mingw* | *cegcc* ) + # Linker will automatically link against shared library if both + # static and shared are present. Therefore, ensure we extract + # symbols from the import library if a shared library is present + # (otherwise, the dlopen module name will be incorrect). We do + # this by putting the import library name into $newdlprefiles. + # We recover the dlopen module name by 'saving' the la file + # name in a special purpose variable, and (later) extracting the + # dlname from the la file. + if test -n "$dlname"; then + func_tr_sh "$dir/$linklib" + eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname" + func_append newdlprefiles " $dir/$linklib" + else + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + fi + ;; + * ) + # Prefer using a static library (so that no silly _DYNAMIC symbols + # are required to link). + if test -n "$old_library"; then + func_append newdlprefiles " $dir/$old_library" + # Keep a list of preopened convenience libraries to check + # that they are being used correctly in the link pass. + test -z "$libdir" && \ + func_append dlpreconveniencelibs " $dir/$old_library" + # Otherwise, use the dlname, so that lt_dlopen finds it. + elif test -n "$dlname"; then + func_append newdlprefiles " $dir/$dlname" + else + func_append newdlprefiles " $dir/$linklib" + fi + ;; + esac + fi # $pass = dlpreopen + + if test -z "$libdir"; then + # Link the convenience library + if test "$linkmode" = lib; then + deplibs="$dir/$old_library $deplibs" + elif test "$linkmode,$pass" = "prog,link"; then + compile_deplibs="$dir/$old_library $compile_deplibs" + finalize_deplibs="$dir/$old_library $finalize_deplibs" + else + deplibs="$lib $deplibs" # used for prog,scan pass + fi + continue + fi + + + if test "$linkmode" = prog && test "$pass" != link; then + func_append newlib_search_path " $ladir" + deplibs="$lib $deplibs" + + linkalldeplibs=no + if test "$link_all_deplibs" != no || test -z "$library_names" || + test "$build_libtool_libs" = no; then + linkalldeplibs=yes + fi + + tmp_libs= + for deplib in $dependency_libs; do + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result" + func_append newlib_search_path " $func_resolve_sysroot_result" + ;; + esac + # Need to link against all dependency_libs? + if test "$linkalldeplibs" = yes; then + deplibs="$deplib $deplibs" + else + # Need to hardcode shared library paths + # or/and link against static libraries + newdependency_libs="$deplib $newdependency_libs" + fi + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $deplib "*) func_append specialdeplibs " $deplib" ;; + esac + fi + func_append tmp_libs " $deplib" + done # for deplib + continue + fi # $linkmode = prog... + + if test "$linkmode,$pass" = "prog,link"; then + if test -n "$library_names" && + { { test "$prefer_static_libs" = no || + test "$prefer_static_libs,$installed" = "built,yes"; } || + test -z "$old_library"; }; then + # We need to hardcode the library path + if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then + # Make sure the rpath contains only unique directories. + case "$temp_rpath:" in + *"$absdir:"*) ;; + *) func_append temp_rpath "$absdir:" ;; + esac + fi + + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi # $linkmode,$pass = prog,link... + + if test "$alldeplibs" = yes && + { test "$deplibs_check_method" = pass_all || + { test "$build_libtool_libs" = yes && + test -n "$library_names"; }; }; then + # We only need to search for static libraries + continue + fi + fi + + link_static=no # Whether the deplib will be linked statically + use_static_libs=$prefer_static_libs + if test "$use_static_libs" = built && test "$installed" = yes; then + use_static_libs=no + fi + if test -n "$library_names" && + { test "$use_static_libs" = no || test -z "$old_library"; }; then + case $host in + *cygwin* | *mingw* | *cegcc*) + # No point in relinking DLLs because paths are not encoded + func_append notinst_deplibs " $lib" + need_relink=no + ;; + *) + if test "$installed" = no; then + func_append notinst_deplibs " $lib" + need_relink=yes + fi + ;; + esac + # This is a shared library + + # Warn about portability, can't link against -module's on some + # systems (darwin). Don't bleat about dlopened modules though! + dlopenmodule="" + for dlpremoduletest in $dlprefiles; do + if test "X$dlpremoduletest" = "X$lib"; then + dlopenmodule="$dlpremoduletest" + break + fi + done + if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then + echo + if test "$linkmode" = prog; then + $ECHO "*** Warning: Linking the executable $output against the loadable module" + else + $ECHO "*** Warning: Linking the shared library $output against the loadable module" + fi + $ECHO "*** $linklib is not portable!" + fi + if test "$linkmode" = lib && + test "$hardcode_into_libs" = yes; then + # Hardcode the library path. + # Skip directories that are in the system default run-time + # search path. + case " $sys_lib_dlsearch_path " in + *" $absdir "*) ;; + *) + case "$compile_rpath " in + *" $absdir "*) ;; + *) func_append compile_rpath " $absdir" ;; + esac + ;; + esac + case " $sys_lib_dlsearch_path " in + *" $libdir "*) ;; + *) + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + ;; + esac + fi + + if test -n "$old_archive_from_expsyms_cmds"; then + # figure out the soname + set dummy $library_names + shift + realname="$1" + shift + libname=`eval "\\$ECHO \"$libname_spec\""` + # use dlname if we got it. it's perfectly good, no? + if test -n "$dlname"; then + soname="$dlname" + elif test -n "$soname_spec"; then + # bleh windows + case $host in + *cygwin* | mingw* | *cegcc*) + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + esac + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + + # Make a new name for the extract_expsyms_cmds to use + soroot="$soname" + func_basename "$soroot" + soname="$func_basename_result" + func_stripname 'lib' '.dll' "$soname" + newlib=libimp-$func_stripname_result.a + + # If the library has no export list, then create one now + if test -f "$output_objdir/$soname-def"; then : + else + func_verbose "extracting exported symbol list from \`$soname'" + func_execute_cmds "$extract_expsyms_cmds" 'exit $?' + fi + + # Create $newlib + if test -f "$output_objdir/$newlib"; then :; else + func_verbose "generating import library for \`$soname'" + func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' + fi + # make sure the library variables are pointing to the new library + dir=$output_objdir + linklib=$newlib + fi # test -n "$old_archive_from_expsyms_cmds" + + if test "$linkmode" = prog || test "$opt_mode" != relink; then + add_shlibpath= + add_dir= + add= + lib_linked=yes + case $hardcode_action in + immediate | unsupported) + if test "$hardcode_direct" = no; then + add="$dir/$linklib" + case $host in + *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; + *-*-sysv4*uw2*) add_dir="-L$dir" ;; + *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ + *-*-unixware7*) add_dir="-L$dir" ;; + *-*-darwin* ) + # if the lib is a (non-dlopened) module then we can not + # link against it, someone is ignoring the earlier warnings + if /usr/bin/file -L $add 2> /dev/null | + $GREP ": [^:]* bundle" >/dev/null ; then + if test "X$dlopenmodule" != "X$lib"; then + $ECHO "*** Warning: lib $linklib is a module, not a shared library" + if test -z "$old_library" ; then + echo + echo "*** And there doesn't seem to be a static archive available" + echo "*** The link will probably fail, sorry" + else + add="$dir/$old_library" + fi + elif test -n "$old_library"; then + add="$dir/$old_library" + fi + fi + esac + elif test "$hardcode_minus_L" = no; then + case $host in + *-*-sunos*) add_shlibpath="$dir" ;; + esac + add_dir="-L$dir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = no; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + relink) + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$dir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$absdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + add_shlibpath="$dir" + add="-l$name" + else + lib_linked=no + fi + ;; + *) lib_linked=no ;; + esac + + if test "$lib_linked" != yes; then + func_fatal_configuration "unsupported hardcode properties" + fi + + if test -n "$add_shlibpath"; then + case :$compile_shlibpath: in + *":$add_shlibpath:"*) ;; + *) func_append compile_shlibpath "$add_shlibpath:" ;; + esac + fi + if test "$linkmode" = prog; then + test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" + test -n "$add" && compile_deplibs="$add $compile_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + if test "$hardcode_direct" != yes && + test "$hardcode_minus_L" != yes && + test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + fi + fi + fi + + if test "$linkmode" = prog || test "$opt_mode" = relink; then + add_shlibpath= + add_dir= + add= + # Finalize command for both is simple: just hardcode it. + if test "$hardcode_direct" = yes && + test "$hardcode_direct_absolute" = no; then + add="$libdir/$linklib" + elif test "$hardcode_minus_L" = yes; then + add_dir="-L$libdir" + add="-l$name" + elif test "$hardcode_shlibpath_var" = yes; then + case :$finalize_shlibpath: in + *":$libdir:"*) ;; + *) func_append finalize_shlibpath "$libdir:" ;; + esac + add="-l$name" + elif test "$hardcode_automatic" = yes; then + if test -n "$inst_prefix_dir" && + test -f "$inst_prefix_dir$libdir/$linklib" ; then + add="$inst_prefix_dir$libdir/$linklib" + else + add="$libdir/$linklib" + fi + else + # We cannot seem to hardcode it, guess we'll fake it. + add_dir="-L$libdir" + # Try looking first in the location we're being installed to. + if test -n "$inst_prefix_dir"; then + case $libdir in + [\\/]*) + func_append add_dir " -L$inst_prefix_dir$libdir" + ;; + esac + fi + add="-l$name" + fi + + if test "$linkmode" = prog; then + test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" + test -n "$add" && finalize_deplibs="$add $finalize_deplibs" + else + test -n "$add_dir" && deplibs="$add_dir $deplibs" + test -n "$add" && deplibs="$add $deplibs" + fi + fi + elif test "$linkmode" = prog; then + # Here we assume that one of hardcode_direct or hardcode_minus_L + # is not unsupported. This is valid on all known static and + # shared platforms. + if test "$hardcode_direct" != unsupported; then + test -n "$old_library" && linklib="$old_library" + compile_deplibs="$dir/$linklib $compile_deplibs" + finalize_deplibs="$dir/$linklib $finalize_deplibs" + else + compile_deplibs="-l$name -L$dir $compile_deplibs" + finalize_deplibs="-l$name -L$dir $finalize_deplibs" + fi + elif test "$build_libtool_libs" = yes; then + # Not a shared library + if test "$deplibs_check_method" != pass_all; then + # We're trying link a shared library against a static one + # but the system doesn't support it. + + # Just print a warning and add the library to dependency_libs so + # that the program can be linked against the static library. + echo + $ECHO "*** Warning: This system can not link to static lib archive $lib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have." + if test "$module" = yes; then + echo "*** But as you try to build a module library, libtool will still create " + echo "*** a static module, that should work as long as the dlopening application" + echo "*** is linked with the -dlopen flag to resolve symbols at runtime." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + else + deplibs="$dir/$old_library $deplibs" + link_static=yes + fi + fi # link shared/static library? + + if test "$linkmode" = lib; then + if test -n "$dependency_libs" && + { test "$hardcode_into_libs" != yes || + test "$build_old_libs" = yes || + test "$link_static" = yes; }; then + # Extract -R from dependency_libs + temp_deplibs= + for libdir in $dependency_libs; do + case $libdir in + -R*) func_stripname '-R' '' "$libdir" + temp_xrpath=$func_stripname_result + case " $xrpath " in + *" $temp_xrpath "*) ;; + *) func_append xrpath " $temp_xrpath";; + esac;; + *) func_append temp_deplibs " $libdir";; + esac + done + dependency_libs="$temp_deplibs" + fi + + func_append newlib_search_path " $absdir" + # Link against this library + test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" + # ... and its dependency_libs + tmp_libs= + for deplib in $dependency_libs; do + newdependency_libs="$deplib $newdependency_libs" + case $deplib in + -L*) func_stripname '-L' '' "$deplib" + func_resolve_sysroot "$func_stripname_result";; + *) func_resolve_sysroot "$deplib" ;; + esac + if $opt_preserve_dup_deps ; then + case "$tmp_libs " in + *" $func_resolve_sysroot_result "*) + func_append specialdeplibs " $func_resolve_sysroot_result" ;; + esac + fi + func_append tmp_libs " $func_resolve_sysroot_result" + done + + if test "$link_all_deplibs" != no; then + # Add the search paths of all dependency libraries + for deplib in $dependency_libs; do + path= + case $deplib in + -L*) path="$deplib" ;; + *.la) + func_resolve_sysroot "$deplib" + deplib=$func_resolve_sysroot_result + func_dirname "$deplib" "" "." + dir=$func_dirname_result + # We need an absolute path. + case $dir in + [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; + *) + absdir=`cd "$dir" && pwd` + if test -z "$absdir"; then + func_warning "cannot determine absolute directory name of \`$dir'" + absdir="$dir" + fi + ;; + esac + if $GREP "^installed=no" $deplib > /dev/null; then + case $host in + *-*-darwin*) + depdepl= + eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` + if test -n "$deplibrary_names" ; then + for tmp in $deplibrary_names ; do + depdepl=$tmp + done + if test -f "$absdir/$objdir/$depdepl" ; then + depdepl="$absdir/$objdir/$depdepl" + darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + if test -z "$darwin_install_name"; then + darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` + fi + func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" + func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}" + path= + fi + fi + ;; + *) + path="-L$absdir/$objdir" + ;; + esac + else + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + test "$absdir" != "$libdir" && \ + func_warning "\`$deplib' seems to be moved" + + path="-L$absdir" + fi + ;; + esac + case " $deplibs " in + *" $path "*) ;; + *) deplibs="$path $deplibs" ;; + esac + done + fi # link_all_deplibs != no + fi # linkmode = lib + done # for deplib in $libs + if test "$pass" = link; then + if test "$linkmode" = "prog"; then + compile_deplibs="$new_inherited_linker_flags $compile_deplibs" + finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" + else + compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + fi + fi + dependency_libs="$newdependency_libs" + if test "$pass" = dlpreopen; then + # Link the dlpreopened libraries before other libraries + for deplib in $save_deplibs; do + deplibs="$deplib $deplibs" + done + fi + if test "$pass" != dlopen; then + if test "$pass" != conv; then + # Make sure lib_search_path contains only unique directories. + lib_search_path= + for dir in $newlib_search_path; do + case "$lib_search_path " in + *" $dir "*) ;; + *) func_append lib_search_path " $dir" ;; + esac + done + newlib_search_path= + fi + + if test "$linkmode,$pass" != "prog,link"; then + vars="deplibs" + else + vars="compile_deplibs finalize_deplibs" + fi + for var in $vars dependency_libs; do + # Add libraries to $var in reverse order + eval tmp_libs=\"\$$var\" + new_libs= + for deplib in $tmp_libs; do + # FIXME: Pedantically, this is the right thing to do, so + # that some nasty dependency loop isn't accidentally + # broken: + #new_libs="$deplib $new_libs" + # Pragmatically, this seems to cause very few problems in + # practice: + case $deplib in + -L*) new_libs="$deplib $new_libs" ;; + -R*) ;; + *) + # And here is the reason: when a library appears more + # than once as an explicit dependence of a library, or + # is implicitly linked in more than once by the + # compiler, it is considered special, and multiple + # occurrences thereof are not removed. Compare this + # with having the same library being listed as a + # dependency of multiple other libraries: in this case, + # we know (pedantically, we assume) the library does not + # need to be listed more than once, so we keep only the + # last copy. This is not always right, but it is rare + # enough that we require users that really mean to play + # such unportable linking tricks to link the library + # using -Wl,-lname, so that libtool does not consider it + # for duplicate removal. + case " $specialdeplibs " in + *" $deplib "*) new_libs="$deplib $new_libs" ;; + *) + case " $new_libs " in + *" $deplib "*) ;; + *) new_libs="$deplib $new_libs" ;; + esac + ;; + esac + ;; + esac + done + tmp_libs= + for deplib in $new_libs; do + case $deplib in + -L*) + case " $tmp_libs " in + *" $deplib "*) ;; + *) func_append tmp_libs " $deplib" ;; + esac + ;; + *) func_append tmp_libs " $deplib" ;; + esac + done + eval $var=\"$tmp_libs\" + done # for var + fi + # Last step: remove runtime libs from dependency_libs + # (they stay in deplibs) + tmp_libs= + for i in $dependency_libs ; do + case " $predeps $postdeps $compiler_lib_search_path " in + *" $i "*) + i="" + ;; + esac + if test -n "$i" ; then + func_append tmp_libs " $i" + fi + done + dependency_libs=$tmp_libs + done # for pass + if test "$linkmode" = prog; then + dlfiles="$newdlfiles" + fi + if test "$linkmode" = prog || test "$linkmode" = lib; then + dlprefiles="$newdlprefiles" + fi + + case $linkmode in + oldlib) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for archives" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for archives" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for archives" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for archives" + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for archives" + + test -n "$release" && \ + func_warning "\`-release' is ignored for archives" + + test -n "$export_symbols$export_symbols_regex" && \ + func_warning "\`-export-symbols' is ignored for archives" + + # Now set the variables for building old libraries. + build_libtool_libs=no + oldlibs="$output" + func_append objs "$old_deplibs" + ;; + + lib) + # Make sure we only generate libraries of the form `libNAME.la'. + case $outputname in + lib*) + func_stripname 'lib' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + ;; + *) + test "$module" = no && \ + func_fatal_help "libtool library \`$output' must begin with \`lib'" + + if test "$need_lib_prefix" != no; then + # Add the "lib" prefix for modules if required + func_stripname '' '.la' "$outputname" + name=$func_stripname_result + eval shared_ext=\"$shrext_cmds\" + eval libname=\"$libname_spec\" + else + func_stripname '' '.la' "$outputname" + libname=$func_stripname_result + fi + ;; + esac + + if test -n "$objs"; then + if test "$deplibs_check_method" != pass_all; then + func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" + else + echo + $ECHO "*** Warning: Linking the shared library $output against the non-libtool" + $ECHO "*** objects $objs is not portable!" + func_append libobjs " $objs" + fi + fi + + test "$dlself" != no && \ + func_warning "\`-dlopen self' is ignored for libtool libraries" + + set dummy $rpath + shift + test "$#" -gt 1 && \ + func_warning "ignoring multiple \`-rpath's for a libtool library" + + install_libdir="$1" + + oldlibs= + if test -z "$rpath"; then + if test "$build_libtool_libs" = yes; then + # Building a libtool convenience library. + # Some compilers have problems with a `.al' extension so + # convenience libraries should have the same extension an + # archive normally would. + oldlibs="$output_objdir/$libname.$libext $oldlibs" + build_libtool_libs=convenience + build_old_libs=yes + fi + + test -n "$vinfo" && \ + func_warning "\`-version-info/-version-number' is ignored for convenience libraries" + + test -n "$release" && \ + func_warning "\`-release' is ignored for convenience libraries" + else + + # Parse the version information argument. + save_ifs="$IFS"; IFS=':' + set dummy $vinfo 0 0 0 + shift + IFS="$save_ifs" + + test -n "$7" && \ + func_fatal_help "too many parameters to \`-version-info'" + + # convert absolute version numbers to libtool ages + # this retains compatibility with .la files and attempts + # to make the code below a bit more comprehensible + + case $vinfo_number in + yes) + number_major="$1" + number_minor="$2" + number_revision="$3" + # + # There are really only two kinds -- those that + # use the current revision as the major version + # and those that subtract age and use age as + # a minor version. But, then there is irix + # which has an extra 1 added just for fun + # + case $version_type in + # correct linux to gnu/linux during the next big refactor + darwin|linux|osf|windows|none) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_revision" + ;; + freebsd-aout|freebsd-elf|qnx|sunos) + current="$number_major" + revision="$number_minor" + age="0" + ;; + irix|nonstopux) + func_arith $number_major + $number_minor + current=$func_arith_result + age="$number_minor" + revision="$number_minor" + lt_irix_increment=no + ;; + esac + ;; + no) + current="$1" + revision="$2" + age="$3" + ;; + esac + + # Check that each of the things are valid numbers. + case $current in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "CURRENT \`$current' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $revision in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "REVISION \`$revision' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + case $age in + 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; + *) + func_error "AGE \`$age' must be a nonnegative integer" + func_fatal_error "\`$vinfo' is not valid version information" + ;; + esac + + if test "$age" -gt "$current"; then + func_error "AGE \`$age' is greater than the current interface number \`$current'" + func_fatal_error "\`$vinfo' is not valid version information" + fi + + # Calculate the version variables. + major= + versuffix= + verstring= + case $version_type in + none) ;; + + darwin) + # Like Linux, but with the current version available in + # verstring for coding it into the library header + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + # Darwin ld doesn't like 0 for these options... + func_arith $current + 1 + minor_current=$func_arith_result + xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" + verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" + ;; + + freebsd-aout) + major=".$current" + versuffix=".$current.$revision"; + ;; + + freebsd-elf) + major=".$current" + versuffix=".$current" + ;; + + irix | nonstopux) + if test "X$lt_irix_increment" = "Xno"; then + func_arith $current - $age + else + func_arith $current - $age + 1 + fi + major=$func_arith_result + + case $version_type in + nonstopux) verstring_prefix=nonstopux ;; + *) verstring_prefix=sgi ;; + esac + verstring="$verstring_prefix$major.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$revision + while test "$loop" -ne 0; do + func_arith $revision - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring_prefix$major.$iface:$verstring" + done + + # Before this point, $major must not contain `.'. + major=.$major + versuffix="$major.$revision" + ;; + + linux) # correct to gnu/linux during the next big refactor + func_arith $current - $age + major=.$func_arith_result + versuffix="$major.$age.$revision" + ;; + + osf) + func_arith $current - $age + major=.$func_arith_result + versuffix=".$current.$age.$revision" + verstring="$current.$age.$revision" + + # Add in all the interfaces that we are compatible with. + loop=$age + while test "$loop" -ne 0; do + func_arith $current - $loop + iface=$func_arith_result + func_arith $loop - 1 + loop=$func_arith_result + verstring="$verstring:${iface}.0" + done + + # Make executables depend on our current version. + func_append verstring ":${current}.0" + ;; + + qnx) + major=".$current" + versuffix=".$current" + ;; + + sunos) + major=".$current" + versuffix=".$current.$revision" + ;; + + windows) + # Use '-' rather than '.', since we only want one + # extension on DOS 8.3 filesystems. + func_arith $current - $age + major=$func_arith_result + versuffix="-$major" + ;; + + *) + func_fatal_configuration "unknown library version type \`$version_type'" + ;; + esac + + # Clear the version info if we defaulted, and they specified a release. + if test -z "$vinfo" && test -n "$release"; then + major= + case $version_type in + darwin) + # we can't check for "0.0" in archive_cmds due to quoting + # problems, so we reset it completely + verstring= + ;; + *) + verstring="0.0" + ;; + esac + if test "$need_version" = no; then + versuffix= + else + versuffix=".0.0" + fi + fi + + # Remove version info from name if versioning should be avoided + if test "$avoid_version" = yes && test "$need_version" = no; then + major= + versuffix= + verstring="" + fi + + # Check to see if the archive will have undefined symbols. + if test "$allow_undefined" = yes; then + if test "$allow_undefined_flag" = unsupported; then + func_warning "undefined symbols not allowed in $host shared libraries" + build_libtool_libs=no + build_old_libs=yes + fi + else + # Don't allow undefined symbols. + allow_undefined_flag="$no_undefined_flag" + fi + + fi + + func_generate_dlsyms "$libname" "$libname" "yes" + func_append libobjs " $symfileobj" + test "X$libobjs" = "X " && libobjs= + + if test "$opt_mode" != relink; then + # Remove our outputs, but don't remove object files since they + # may have been created when compiling PIC objects. + removelist= + tempremovelist=`$ECHO "$output_objdir/*"` + for p in $tempremovelist; do + case $p in + *.$objext | *.gcno) + ;; + $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) + if test "X$precious_files_regex" != "X"; then + if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 + then + continue + fi + fi + func_append removelist " $p" + ;; + *) ;; + esac + done + test -n "$removelist" && \ + func_show_eval "${RM}r \$removelist" + fi + + # Now set the variables for building old libraries. + if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then + func_append oldlibs " $output_objdir/$libname.$libext" + + # Transform .lo files to .o files. + oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` + fi + + # Eliminate all temporary directories. + #for path in $notinst_path; do + # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` + # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` + # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` + #done + + if test -n "$xrpath"; then + # If the user specified any rpath flags, then add them. + temp_xrpath= + for libdir in $xrpath; do + func_replace_sysroot "$libdir" + func_append temp_xrpath " -R$func_replace_sysroot_result" + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then + dependency_libs="$temp_xrpath $dependency_libs" + fi + fi + + # Make sure dlfiles contains only unique files that won't be dlpreopened + old_dlfiles="$dlfiles" + dlfiles= + for lib in $old_dlfiles; do + case " $dlprefiles $dlfiles " in + *" $lib "*) ;; + *) func_append dlfiles " $lib" ;; + esac + done + + # Make sure dlprefiles contains only unique files + old_dlprefiles="$dlprefiles" + dlprefiles= + for lib in $old_dlprefiles; do + case "$dlprefiles " in + *" $lib "*) ;; + *) func_append dlprefiles " $lib" ;; + esac + done + + if test "$build_libtool_libs" = yes; then + if test -n "$rpath"; then + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) + # these systems don't actually have a c library (as such)! + ;; + *-*-rhapsody* | *-*-darwin1.[012]) + # Rhapsody C library is in the System framework + func_append deplibs " System.ltframework" + ;; + *-*-netbsd*) + # Don't link with libc until the a.out ld.so is fixed. + ;; + *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) + # Do not include libc due to us having libc/libc_r. + ;; + *-*-sco3.2v5* | *-*-sco5v6*) + # Causes problems with __ctype + ;; + *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) + # Compiler inserts libc in the correct place for threads to work + ;; + *) + # Add libc to deplibs on all other systems if necessary. + if test "$build_libtool_need_lc" = "yes"; then + func_append deplibs " -lc" + fi + ;; + esac + fi + + # Transform deplibs into only deplibs that can be linked in shared. + name_save=$name + libname_save=$libname + release_save=$release + versuffix_save=$versuffix + major_save=$major + # I'm not sure if I'm treating the release correctly. I think + # release should show up in the -l (ie -lgmp5) so we don't want to + # add it in twice. Is that correct? + release="" + versuffix="" + major="" + newdeplibs= + droppeddeps=no + case $deplibs_check_method in + pass_all) + # Don't check for shared/static. Everything works. + # This might be a little naive. We might want to check + # whether the library exists or not. But this is on + # osf3 & osf4 and I'm not really sure... Just + # implementing what was already the behavior. + newdeplibs=$deplibs + ;; + test_compile) + # This code stresses the "libraries are programs" paradigm to its + # limits. Maybe even breaks it. We compile a program, linking it + # against the deplibs as a proxy for the library. Then we can check + # whether they linked in statically or dynamically with ldd. + $opt_dry_run || $RM conftest.c + cat > conftest.c </dev/null` + $nocaseglob + else + potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null` + fi + for potent_lib in $potential_libs; do + # Follow soft links. + if ls -lLd "$potent_lib" 2>/dev/null | + $GREP " -> " >/dev/null; then + continue + fi + # The statement above tries to avoid entering an + # endless loop below, in case of cyclic links. + # We might still enter an endless loop, since a link + # loop can be closed while we follow links, + # but so what? + potlib="$potent_lib" + while test -h "$potlib" 2>/dev/null; do + potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` + case $potliblink in + [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; + *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; + esac + done + if eval $file_magic_cmd \"\$potlib\" 2>/dev/null | + $SED -e 10q | + $EGREP "$file_magic_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for file magic test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a file magic. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + match_pattern*) + set dummy $deplibs_check_method; shift + match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` + for a_deplib in $deplibs; do + case $a_deplib in + -l*) + func_stripname -l '' "$a_deplib" + name=$func_stripname_result + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + case " $predeps $postdeps " in + *" $a_deplib "*) + func_append newdeplibs " $a_deplib" + a_deplib="" + ;; + esac + fi + if test -n "$a_deplib" ; then + libname=`eval "\\$ECHO \"$libname_spec\""` + for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do + potential_libs=`ls $i/$libname[.-]* 2>/dev/null` + for potent_lib in $potential_libs; do + potlib="$potent_lib" # see symlink-check above in file_magic test + if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ + $EGREP "$match_pattern_regex" > /dev/null; then + func_append newdeplibs " $a_deplib" + a_deplib="" + break 2 + fi + done + done + fi + if test -n "$a_deplib" ; then + droppeddeps=yes + echo + $ECHO "*** Warning: linker path does not have real file for library $a_deplib." + echo "*** I have the capability to make that library automatically link in when" + echo "*** you link to this library. But I can only do this if you have a" + echo "*** shared version of the library, which you do not appear to have" + echo "*** because I did check the linker path looking for a file starting" + if test -z "$potlib" ; then + $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" + else + $ECHO "*** with $libname and none of the candidates passed a file format test" + $ECHO "*** using a regex pattern. Last file checked: $potlib" + fi + fi + ;; + *) + # Add a -L argument. + func_append newdeplibs " $a_deplib" + ;; + esac + done # Gone through all deplibs. + ;; + none | unknown | *) + newdeplibs="" + tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` + if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then + for i in $predeps $postdeps ; do + # can't use Xsed below, because $i might contain '/' + tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` + done + fi + case $tmp_deplibs in + *[!\ \ ]*) + echo + if test "X$deplibs_check_method" = "Xnone"; then + echo "*** Warning: inter-library dependencies are not supported in this platform." + else + echo "*** Warning: inter-library dependencies are not known to be supported." + fi + echo "*** All declared inter-library dependencies are being dropped." + droppeddeps=yes + ;; + esac + ;; + esac + versuffix=$versuffix_save + major=$major_save + release=$release_save + libname=$libname_save + name=$name_save + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library with the System framework + newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + if test "$droppeddeps" = yes; then + if test "$module" = yes; then + echo + echo "*** Warning: libtool could not satisfy all declared inter-library" + $ECHO "*** dependencies of module $libname. Therefore, libtool will create" + echo "*** a static module, that should work as long as the dlopening" + echo "*** application is linked with the -dlopen flag." + if test -z "$global_symbol_pipe"; then + echo + echo "*** However, this would only work if libtool was able to extract symbol" + echo "*** lists from a program, using \`nm' or equivalent, but libtool could" + echo "*** not find such a program. So, this module is probably useless." + echo "*** \`nm' from GNU binutils and a full rebuild may help." + fi + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + else + echo "*** The inter-library dependencies that have been dropped here will be" + echo "*** automatically added whenever a program is linked with this library" + echo "*** or is declared to -dlopen it." + + if test "$allow_undefined" = no; then + echo + echo "*** Since this library must not contain undefined symbols," + echo "*** because either the platform does not support them or" + echo "*** it was explicitly requested with -no-undefined," + echo "*** libtool will only create a static version of it." + if test "$build_old_libs" = no; then + oldlibs="$output_objdir/$libname.$libext" + build_libtool_libs=module + build_old_libs=yes + else + build_libtool_libs=no + fi + fi + fi + fi + # Done checking deplibs! + deplibs=$newdeplibs + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + case $host in + *-*-darwin*) + newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + deplibs="$new_libs" + + # All the library-specific variables (install_libdir is set above). + library_names= + old_library= + dlname= + + # Test again, we may have decided not to build it any more + if test "$build_libtool_libs" = yes; then + # Remove ${wl} instances when linking with ld. + # FIXME: should test the right _cmds variable. + case $archive_cmds in + *\$LD\ *) wl= ;; + esac + if test "$hardcode_into_libs" = yes; then + # Hardcode the library paths + hardcode_libdirs= + dep_rpath= + rpath="$finalize_rpath" + test "$opt_mode" != relink && rpath="$compile_rpath$rpath" + for libdir in $rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + func_replace_sysroot "$libdir" + libdir=$func_replace_sysroot_result + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append dep_rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" + fi + if test -n "$runpath_var" && test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var" + fi + test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" + fi + + shlibpath="$finalize_shlibpath" + test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath" + if test -n "$shlibpath"; then + eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var" + fi + + # Get the real and link names of the library. + eval shared_ext=\"$shrext_cmds\" + eval library_names=\"$library_names_spec\" + set dummy $library_names + shift + realname="$1" + shift + + if test -n "$soname_spec"; then + eval soname=\"$soname_spec\" + else + soname="$realname" + fi + if test -z "$dlname"; then + dlname=$soname + fi + + lib="$output_objdir/$realname" + linknames= + for link + do + func_append linknames " $link" + done + + # Use standard objects if they are pic + test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` + test "X$libobjs" = "X " && libobjs= + + delfiles= + if test -n "$export_symbols" && test -n "$include_expsyms"; then + $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" + export_symbols="$output_objdir/$libname.uexp" + func_append delfiles " $export_symbols" + fi + + orig_export_symbols= + case $host_os in + cygwin* | mingw* | cegcc*) + if test -n "$export_symbols" && test -z "$export_symbols_regex"; then + # exporting using user supplied symfile + if test "x`$SED 1q $export_symbols`" != xEXPORTS; then + # and it's NOT already a .def file. Must figure out + # which of the given symbols are data symbols and tag + # them as such. So, trigger use of export_symbols_cmds. + # export_symbols gets reassigned inside the "prepare + # the list of exported symbols" if statement, so the + # include_expsyms logic still works. + orig_export_symbols="$export_symbols" + export_symbols= + always_export_symbols=yes + fi + fi + ;; + esac + + # Prepare the list of exported symbols + if test -z "$export_symbols"; then + if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + cmds=$export_symbols_cmds + save_ifs="$IFS"; IFS='~' + for cmd1 in $cmds; do + IFS="$save_ifs" + # Take the normal branch if the nm_file_list_spec branch + # doesn't work or if tool conversion is not needed. + case $nm_file_list_spec~$to_tool_file_cmd in + *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*) + try_normal_branch=yes + eval cmd=\"$cmd1\" + func_len " $cmd" + len=$func_len_result + ;; + *) + try_normal_branch=no + ;; + esac + if test "$try_normal_branch" = yes \ + && { test "$len" -lt "$max_cmd_len" \ + || test "$max_cmd_len" -le -1; } + then + func_show_eval "$cmd" 'exit $?' + skipped_export=false + elif test -n "$nm_file_list_spec"; then + func_basename "$output" + output_la=$func_basename_result + save_libobjs=$libobjs + save_output=$output + output=${output_objdir}/${output_la}.nm + func_to_tool_file "$output" + libobjs=$nm_file_list_spec$func_to_tool_file_result + func_append delfiles " $output" + func_verbose "creating $NM input file list: $output" + for obj in $save_libobjs; do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > "$output" + eval cmd=\"$cmd1\" + func_show_eval "$cmd" 'exit $?' + output=$save_output + libobjs=$save_libobjs + skipped_export=false + else + # The command line is too long to execute in one step. + func_verbose "using reloadable object file for export list..." + skipped_export=: + # Break out early, otherwise skipped_export may be + # set to false by a later but shorter cmd. + break + fi + done + IFS="$save_ifs" + if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + fi + + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + + tmp_deplibs= + for test_deplib in $deplibs; do + case " $convenience " in + *" $test_deplib "*) ;; + *) + func_append tmp_deplibs " $test_deplib" + ;; + esac + done + deplibs="$tmp_deplibs" + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec" && + test "$compiler_needs_object" = yes && + test -z "$libobjs"; then + # extract the archives, so we have objects to list. + # TODO: could optimize this to just extract one archive. + whole_archive_flag_spec= + fi + if test -n "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + else + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + fi + + if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then + eval flag=\"$thread_safe_flag_spec\" + func_append linker_flags " $flag" + fi + + # Make a backup of the uninstalled library when relinking + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $? + fi + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + eval test_cmds=\"$module_expsym_cmds\" + cmds=$module_expsym_cmds + else + eval test_cmds=\"$module_cmds\" + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + eval test_cmds=\"$archive_expsym_cmds\" + cmds=$archive_expsym_cmds + else + eval test_cmds=\"$archive_cmds\" + cmds=$archive_cmds + fi + fi + + if test "X$skipped_export" != "X:" && + func_len " $test_cmds" && + len=$func_len_result && + test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + : + else + # The command line is too long to link in one step, link piecewise + # or, if using GNU ld and skipped_export is not :, use a linker + # script. + + # Save the value of $output and $libobjs because we want to + # use them later. If we have whole_archive_flag_spec, we + # want to use save_libobjs as it was before + # whole_archive_flag_spec was expanded, because we can't + # assume the linker understands whole_archive_flag_spec. + # This may have to be revisited, in case too many + # convenience libraries get linked in and end up exceeding + # the spec. + if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then + save_libobjs=$libobjs + fi + save_output=$output + func_basename "$output" + output_la=$func_basename_result + + # Clear the reloadable object creation command queue and + # initialize k to one. + test_cmds= + concat_cmds= + objlist= + last_robj= + k=1 + + if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then + output=${output_objdir}/${output_la}.lnkscript + func_verbose "creating GNU ld script: $output" + echo 'INPUT (' > $output + for obj in $save_libobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + echo ')' >> $output + func_append delfiles " $output" + func_to_tool_file "$output" + output=$func_to_tool_file_result + elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then + output=${output_objdir}/${output_la}.lnk + func_verbose "creating linker input file list: $output" + : > $output + set x $save_libobjs + shift + firstobj= + if test "$compiler_needs_object" = yes; then + firstobj="$1 " + shift + fi + for obj + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" >> $output + done + func_append delfiles " $output" + func_to_tool_file "$output" + output=$firstobj\"$file_list_spec$func_to_tool_file_result\" + else + if test -n "$save_libobjs"; then + func_verbose "creating reloadable object files..." + output=$output_objdir/$output_la-${k}.$objext + eval test_cmds=\"$reload_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + + # Loop over the list of objects to be linked. + for obj in $save_libobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + if test "X$objlist" = X || + test "$len" -lt "$max_cmd_len"; then + func_append objlist " $obj" + else + # The command $test_cmds is almost too long, add a + # command to the queue. + if test "$k" -eq 1 ; then + # The first file doesn't have a previous command to add. + reload_objs=$objlist + eval concat_cmds=\"$reload_cmds\" + else + # All subsequent reloadable object files will link in + # the last one created. + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\" + fi + last_robj=$output_objdir/$output_la-${k}.$objext + func_arith $k + 1 + k=$func_arith_result + output=$output_objdir/$output_la-${k}.$objext + objlist=" $obj" + func_len " $last_robj" + func_arith $len0 + $func_len_result + len=$func_arith_result + fi + done + # Handle the remaining objects by creating one last + # reloadable object file. All subsequent reloadable object + # files will link in the last one created. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + reload_objs="$objlist $last_robj" + eval concat_cmds=\"\${concat_cmds}$reload_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\" + fi + func_append delfiles " $output" + + else + output= + fi + + if ${skipped_export-false}; then + func_verbose "generating symbol list for \`$libname.la'" + export_symbols="$output_objdir/$libname.exp" + $opt_dry_run || $RM $export_symbols + libobjs=$output + # Append the command to create the export file. + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\" + if test -n "$last_robj"; then + eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\" + fi + fi + + test -n "$save_libobjs" && + func_verbose "creating a temporary reloadable object file: $output" + + # Loop through the commands generated above and execute them. + save_ifs="$IFS"; IFS='~' + for cmd in $concat_cmds; do + IFS="$save_ifs" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + if test -n "$export_symbols_regex" && ${skipped_export-false}; then + func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' + func_show_eval '$MV "${export_symbols}T" "$export_symbols"' + fi + fi + + if ${skipped_export-false}; then + if test -n "$export_symbols" && test -n "$include_expsyms"; then + tmp_export_symbols="$export_symbols" + test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" + $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"' + fi + + if test -n "$orig_export_symbols"; then + # The given exports_symbols file has to be filtered, so filter it. + func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" + # FIXME: $output_objdir/$libname.filter potentially contains lots of + # 's' commands which not all seds can handle. GNU sed should be fine + # though. Also, the filter scales superlinearly with the number of + # global variables. join(1) would be nice here, but unfortunately + # isn't a blessed tool. + $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter + func_append delfiles " $export_symbols $output_objdir/$libname.filter" + export_symbols=$output_objdir/$libname.def + $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols + fi + fi + + libobjs=$output + # Restore the value of output. + output=$save_output + + if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then + eval libobjs=\"\$libobjs $whole_archive_flag_spec\" + test "X$libobjs" = "X " && libobjs= + fi + # Expand the library linking commands again to reset the + # value of $libobjs for piecewise linking. + + # Do each of the archive commands. + if test "$module" = yes && test -n "$module_cmds" ; then + if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then + cmds=$module_expsym_cmds + else + cmds=$module_cmds + fi + else + if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then + cmds=$archive_expsym_cmds + else + cmds=$archive_cmds + fi + fi + fi + + if test -n "$delfiles"; then + # Append the command to remove temporary files to $cmds. + eval cmds=\"\$cmds~\$RM $delfiles\" + fi + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append libobjs " $func_extract_archives_result" + test "X$libobjs" = "X " && libobjs= + fi + + save_ifs="$IFS"; IFS='~' + for cmd in $cmds; do + IFS="$save_ifs" + eval cmd=\"$cmd\" + $opt_silent || { + func_quote_for_expand "$cmd" + eval "func_echo $func_quote_for_expand_result" + } + $opt_dry_run || eval "$cmd" || { + lt_exit=$? + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + ( cd "$output_objdir" && \ + $RM "${realname}T" && \ + $MV "${realname}U" "$realname" ) + fi + + exit $lt_exit + } + done + IFS="$save_ifs" + + # Restore the uninstalled library and exit + if test "$opt_mode" = relink; then + $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $? + + if test -n "$convenience"; then + if test -z "$whole_archive_flag_spec"; then + func_show_eval '${RM}r "$gentop"' + fi + fi + + exit $EXIT_SUCCESS + fi + + # Create links to the real library. + for linkname in $linknames; do + if test "$realname" != "$linkname"; then + func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' + fi + done + + # If -module or -export-dynamic was specified, set the dlname. + if test "$module" = yes || test "$export_dynamic" = yes; then + # On all known operating systems, these are identical. + dlname="$soname" + fi + fi + ;; + + obj) + if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then + func_warning "\`-dlopen' is ignored for objects" + fi + + case " $deplibs" in + *\ -l* | *\ -L*) + func_warning "\`-l' and \`-L' are ignored for objects" ;; + esac + + test -n "$rpath" && \ + func_warning "\`-rpath' is ignored for objects" + + test -n "$xrpath" && \ + func_warning "\`-R' is ignored for objects" + + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for objects" + + test -n "$release" && \ + func_warning "\`-release' is ignored for objects" + + case $output in + *.lo) + test -n "$objs$old_deplibs" && \ + func_fatal_error "cannot build library object \`$output' from non-libtool objects" + + libobj=$output + func_lo2o "$libobj" + obj=$func_lo2o_result + ;; + *) + libobj= + obj="$output" + ;; + esac + + # Delete the old objects. + $opt_dry_run || $RM $obj $libobj + + # Objects from convenience libraries. This assumes + # single-version convenience libraries. Whenever we create + # different ones for PIC/non-PIC, this we'll have to duplicate + # the extraction. + reload_conv_objs= + gentop= + # reload_cmds runs $LD directly, so let us get rid of + # -Wl from whole_archive_flag_spec and hope we can get by with + # turning comma into space.. + wl= + + if test -n "$convenience"; then + if test -n "$whole_archive_flag_spec"; then + eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\" + reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` + else + gentop="$output_objdir/${obj}x" + func_append generated " $gentop" + + func_extract_archives $gentop $convenience + reload_conv_objs="$reload_objs $func_extract_archives_result" + fi + fi + + # If we're not building shared, we need to use non_pic_objs + test "$build_libtool_libs" != yes && libobjs="$non_pic_objects" + + # Create the old-style object. + reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test + + output="$obj" + func_execute_cmds "$reload_cmds" 'exit $?' + + # Exit if we aren't doing a library object file. + if test -z "$libobj"; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + fi + + if test "$build_libtool_libs" != yes; then + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + # Create an invalid libtool object if no PIC, so that we don't + # accidentally link it into a program. + # $show "echo timestamp > $libobj" + # $opt_dry_run || eval "echo timestamp > $libobj" || exit $? + exit $EXIT_SUCCESS + fi + + if test -n "$pic_flag" || test "$pic_mode" != default; then + # Only do commands if we really have different PIC objects. + reload_objs="$libobjs $reload_conv_objs" + output="$libobj" + func_execute_cmds "$reload_cmds" 'exit $?' + fi + + if test -n "$gentop"; then + func_show_eval '${RM}r "$gentop"' + fi + + exit $EXIT_SUCCESS + ;; + + prog) + case $host in + *cygwin*) func_stripname '' '.exe' "$output" + output=$func_stripname_result.exe;; + esac + test -n "$vinfo" && \ + func_warning "\`-version-info' is ignored for programs" + + test -n "$release" && \ + func_warning "\`-release' is ignored for programs" + + test "$preload" = yes \ + && test "$dlopen_support" = unknown \ + && test "$dlopen_self" = unknown \ + && test "$dlopen_self_static" = unknown && \ + func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." + + case $host in + *-*-rhapsody* | *-*-darwin1.[012]) + # On Rhapsody replace the C library is the System framework + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` + ;; + esac + + case $host in + *-*-darwin*) + # Don't allow lazy linking, it breaks C++ global constructors + # But is supposedly fixed on 10.4 or later (yay!). + if test "$tagname" = CXX ; then + case ${MACOSX_DEPLOYMENT_TARGET-10.0} in + 10.[0123]) + func_append compile_command " ${wl}-bind_at_load" + func_append finalize_command " ${wl}-bind_at_load" + ;; + esac + fi + # Time to change all our "foo.ltframework" stuff back to "-framework foo" + compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` + ;; + esac + + + # move library search paths that coincide with paths to not yet + # installed libraries to the beginning of the library search list + new_libs= + for path in $notinst_path; do + case " $new_libs " in + *" -L$path/$objdir "*) ;; + *) + case " $compile_deplibs " in + *" -L$path/$objdir "*) + func_append new_libs " -L$path/$objdir" ;; + esac + ;; + esac + done + for deplib in $compile_deplibs; do + case $deplib in + -L*) + case " $new_libs " in + *" $deplib "*) ;; + *) func_append new_libs " $deplib" ;; + esac + ;; + *) func_append new_libs " $deplib" ;; + esac + done + compile_deplibs="$new_libs" + + + func_append compile_command " $compile_deplibs" + func_append finalize_command " $finalize_deplibs" + + if test -n "$rpath$xrpath"; then + # If the user specified any rpath flags, then add them. + for libdir in $rpath $xrpath; do + # This is the magic to use -rpath. + case "$finalize_rpath " in + *" $libdir "*) ;; + *) func_append finalize_rpath " $libdir" ;; + esac + done + fi + + # Now hardcode the library paths + rpath= + hardcode_libdirs= + for libdir in $compile_rpath $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$perm_rpath " in + *" $libdir "*) ;; + *) func_append perm_rpath " $libdir" ;; + esac + fi + case $host in + *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) + testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` + case :$dllsearchpath: in + *":$libdir:"*) ;; + ::) dllsearchpath=$libdir;; + *) func_append dllsearchpath ":$libdir";; + esac + case :$dllsearchpath: in + *":$testbindir:"*) ;; + ::) dllsearchpath=$testbindir;; + *) func_append dllsearchpath ":$testbindir";; + esac + ;; + esac + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + compile_rpath="$rpath" + + rpath= + hardcode_libdirs= + for libdir in $finalize_rpath; do + if test -n "$hardcode_libdir_flag_spec"; then + if test -n "$hardcode_libdir_separator"; then + if test -z "$hardcode_libdirs"; then + hardcode_libdirs="$libdir" + else + # Just accumulate the unique libdirs. + case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in + *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) + ;; + *) + func_append hardcode_libdirs "$hardcode_libdir_separator$libdir" + ;; + esac + fi + else + eval flag=\"$hardcode_libdir_flag_spec\" + func_append rpath " $flag" + fi + elif test -n "$runpath_var"; then + case "$finalize_perm_rpath " in + *" $libdir "*) ;; + *) func_append finalize_perm_rpath " $libdir" ;; + esac + fi + done + # Substitute the hardcoded libdirs into the rpath. + if test -n "$hardcode_libdir_separator" && + test -n "$hardcode_libdirs"; then + libdir="$hardcode_libdirs" + eval rpath=\" $hardcode_libdir_flag_spec\" + fi + finalize_rpath="$rpath" + + if test -n "$libobjs" && test "$build_old_libs" = yes; then + # Transform all the library objects into standard objects. + compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` + fi + + func_generate_dlsyms "$outputname" "@PROGRAM@" "no" + + # template prelinking step + if test -n "$prelink_cmds"; then + func_execute_cmds "$prelink_cmds" 'exit $?' + fi + + wrappers_required=yes + case $host in + *cegcc* | *mingw32ce*) + # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. + wrappers_required=no + ;; + *cygwin* | *mingw* ) + if test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + *) + if test "$need_relink" = no || test "$build_libtool_libs" != yes; then + wrappers_required=no + fi + ;; + esac + if test "$wrappers_required" = no; then + # Replace the output file specification. + compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + link_command="$compile_command$compile_rpath" + + # We have no uninstalled library dependencies, so finalize right now. + exit_status=0 + func_show_eval "$link_command" 'exit_status=$?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Delete the generated files. + if test -f "$output_objdir/${outputname}S.${objext}"; then + func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' + fi + + exit $exit_status + fi + + if test -n "$compile_shlibpath$finalize_shlibpath"; then + compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" + fi + if test -n "$finalize_shlibpath"; then + finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" + fi + + compile_var= + finalize_var= + if test -n "$runpath_var"; then + if test -n "$perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $perm_rpath; do + func_append rpath "$dir:" + done + compile_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + if test -n "$finalize_perm_rpath"; then + # We should set the runpath_var. + rpath= + for dir in $finalize_perm_rpath; do + func_append rpath "$dir:" + done + finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " + fi + fi + + if test "$no_install" = yes; then + # We don't need to create a wrapper script. + link_command="$compile_var$compile_command$compile_rpath" + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` + # Delete the old output file. + $opt_dry_run || $RM $output + # Link the executable and exit + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + exit $EXIT_SUCCESS + fi + + if test "$hardcode_action" = relink; then + # Fast installation is not supported + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + + func_warning "this platform does not like uninstalled shared libraries" + func_warning "\`$output' will be relinked during installation" + else + if test "$fast_install" != no; then + link_command="$finalize_var$compile_command$finalize_rpath" + if test "$fast_install" = yes; then + relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` + else + # fast_install is set to needless + relink_command= + fi + else + link_command="$compile_var$compile_command$compile_rpath" + relink_command="$finalize_var$finalize_command$finalize_rpath" + fi + fi + + # Replace the output file specification. + link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` + + # Delete the old output files. + $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname + + func_show_eval "$link_command" 'exit $?' + + if test -n "$postlink_cmds"; then + func_to_tool_file "$output_objdir/$outputname" + postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'` + func_execute_cmds "$postlink_cmds" 'exit $?' + fi + + # Now create the wrapper script. + func_verbose "creating $output" + + # Quote the relink command for shipping. + if test -n "$relink_command"; then + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + relink_command="(cd `pwd`; $relink_command)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + fi + + # Only actually do things if not in dry run mode. + $opt_dry_run || { + # win32 will think the script is a binary if it has + # a .exe suffix, so we strip it off here. + case $output in + *.exe) func_stripname '' '.exe' "$output" + output=$func_stripname_result ;; + esac + # test for cygwin because mv fails w/o .exe extensions + case $host in + *cygwin*) + exeext=.exe + func_stripname '' '.exe' "$outputname" + outputname=$func_stripname_result ;; + *) exeext= ;; + esac + case $host in + *cygwin* | *mingw* ) + func_dirname_and_basename "$output" "" "." + output_name=$func_basename_result + output_path=$func_dirname_result + cwrappersource="$output_path/$objdir/lt-$output_name.c" + cwrapper="$output_path/$output_name.exe" + $RM $cwrappersource $cwrapper + trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 + + func_emit_cwrapperexe_src > $cwrappersource + + # The wrapper executable is built using the $host compiler, + # because it contains $host paths and files. If cross- + # compiling, it, like the target executable, must be + # executed on the $host or under an emulation environment. + $opt_dry_run || { + $LTCC $LTCFLAGS -o $cwrapper $cwrappersource + $STRIP $cwrapper + } + + # Now, create the wrapper script for func_source use: + func_ltwrapper_scriptname $cwrapper + $RM $func_ltwrapper_scriptname_result + trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 + $opt_dry_run || { + # note: this script will not be executed, so do not chmod. + if test "x$build" = "x$host" ; then + $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result + else + func_emit_wrapper no > $func_ltwrapper_scriptname_result + fi + } + ;; + * ) + $RM $output + trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 + + func_emit_wrapper no > $output + chmod +x $output + ;; + esac + } + exit $EXIT_SUCCESS + ;; + esac + + # See if we need to build an old-fashioned archive. + for oldlib in $oldlibs; do + + if test "$build_libtool_libs" = convenience; then + oldobjs="$libobjs_save $symfileobj" + addlibs="$convenience" + build_libtool_libs=no + else + if test "$build_libtool_libs" = module; then + oldobjs="$libobjs_save" + build_libtool_libs=no + else + oldobjs="$old_deplibs $non_pic_objects" + if test "$preload" = yes && test -f "$symfileobj"; then + func_append oldobjs " $symfileobj" + fi + fi + addlibs="$old_convenience" + fi + + if test -n "$addlibs"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $addlibs + func_append oldobjs " $func_extract_archives_result" + fi + + # Do each command in the archive commands. + if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then + cmds=$old_archive_from_new_cmds + else + + # Add any objects from preloaded convenience libraries + if test -n "$dlprefiles"; then + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + + func_extract_archives $gentop $dlprefiles + func_append oldobjs " $func_extract_archives_result" + fi + + # POSIX demands no paths to be encoded in archives. We have + # to avoid creating archives with duplicate basenames if we + # might have to extract them afterwards, e.g., when creating a + # static archive out of a convenience library, or when linking + # the entirety of a libtool archive into another (currently + # not supported by libtool). + if (for obj in $oldobjs + do + func_basename "$obj" + $ECHO "$func_basename_result" + done | sort | sort -uc >/dev/null 2>&1); then + : + else + echo "copying selected object files to avoid basename conflicts..." + gentop="$output_objdir/${outputname}x" + func_append generated " $gentop" + func_mkdir_p "$gentop" + save_oldobjs=$oldobjs + oldobjs= + counter=1 + for obj in $save_oldobjs + do + func_basename "$obj" + objbase="$func_basename_result" + case " $oldobjs " in + " ") oldobjs=$obj ;; + *[\ /]"$objbase "*) + while :; do + # Make sure we don't pick an alternate name that also + # overlaps. + newobj=lt$counter-$objbase + func_arith $counter + 1 + counter=$func_arith_result + case " $oldobjs " in + *[\ /]"$newobj "*) ;; + *) if test ! -f "$gentop/$newobj"; then break; fi ;; + esac + done + func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" + func_append oldobjs " $gentop/$newobj" + ;; + *) func_append oldobjs " $obj" ;; + esac + done + fi + func_to_tool_file "$oldlib" func_convert_file_msys_to_w32 + tool_oldlib=$func_to_tool_file_result + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" + len=$func_len_result + if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then + cmds=$old_archive_cmds + elif test -n "$archiver_list_spec"; then + func_verbose "using command file archive linking..." + for obj in $oldobjs + do + func_to_tool_file "$obj" + $ECHO "$func_to_tool_file_result" + done > $output_objdir/$libname.libcmd + func_to_tool_file "$output_objdir/$libname.libcmd" + oldobjs=" $archiver_list_spec$func_to_tool_file_result" + cmds=$old_archive_cmds + else + # the command line is too long to link in one step, link in parts + func_verbose "using piecewise archive linking..." + save_RANLIB=$RANLIB + RANLIB=: + objlist= + concat_cmds= + save_oldobjs=$oldobjs + oldobjs= + # Is there a better way of finding the last object in the list? + for obj in $save_oldobjs + do + last_oldobj=$obj + done + eval test_cmds=\"$old_archive_cmds\" + func_len " $test_cmds" + len0=$func_len_result + len=$len0 + for obj in $save_oldobjs + do + func_len " $obj" + func_arith $len + $func_len_result + len=$func_arith_result + func_append objlist " $obj" + if test "$len" -lt "$max_cmd_len"; then + : + else + # the above command should be used before it gets too long + oldobjs=$objlist + if test "$obj" = "$last_oldobj" ; then + RANLIB=$save_RANLIB + fi + test -z "$concat_cmds" || concat_cmds=$concat_cmds~ + eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\" + objlist= + len=$len0 + fi + done + RANLIB=$save_RANLIB + oldobjs=$objlist + if test "X$oldobjs" = "X" ; then + eval cmds=\"\$concat_cmds\" + else + eval cmds=\"\$concat_cmds~\$old_archive_cmds\" + fi + fi + fi + func_execute_cmds "$cmds" 'exit $?' + done + + test -n "$generated" && \ + func_show_eval "${RM}r$generated" + + # Now create the libtool archive. + case $output in + *.la) + old_library= + test "$build_old_libs" = yes && old_library="$libname.$libext" + func_verbose "creating $output" + + # Preserve any variables that may affect compiler behavior + for var in $variables_saved_for_relink; do + if eval test -z \"\${$var+set}\"; then + relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" + elif eval var_value=\$$var; test -z "$var_value"; then + relink_command="$var=; export $var; $relink_command" + else + func_quote_for_eval "$var_value" + relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" + fi + done + # Quote the link command for shipping. + relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" + relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` + if test "$hardcode_automatic" = yes ; then + relink_command= + fi + + # Only create the output if not a dry run. + $opt_dry_run || { + for installed in no yes; do + if test "$installed" = yes; then + if test -z "$install_libdir"; then + break + fi + output="$output_objdir/$outputname"i + # Replace all uninstalled libtool libraries with the installed ones + newdependency_libs= + for deplib in $dependency_libs; do + case $deplib in + *.la) + func_basename "$deplib" + name="$func_basename_result" + func_resolve_sysroot "$deplib" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result` + test -z "$libdir" && \ + func_fatal_error "\`$deplib' is not a valid libtool archive" + func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name" + ;; + -L*) + func_stripname -L '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -L$func_replace_sysroot_result" + ;; + -R*) + func_stripname -R '' "$deplib" + func_replace_sysroot "$func_stripname_result" + func_append newdependency_libs " -R$func_replace_sysroot_result" + ;; + *) func_append newdependency_libs " $deplib" ;; + esac + done + dependency_libs="$newdependency_libs" + newdlfiles= + + for lib in $dlfiles; do + case $lib in + *.la) + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name" + ;; + *) func_append newdlfiles " $lib" ;; + esac + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + *.la) + # Only pass preopened files to the pseudo-archive (for + # eventual linking with the app. that links it) if we + # didn't already link the preopened objects directly into + # the library: + func_basename "$lib" + name="$func_basename_result" + eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` + test -z "$libdir" && \ + func_fatal_error "\`$lib' is not a valid libtool archive" + func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name" + ;; + esac + done + dlprefiles="$newdlprefiles" + else + newdlfiles= + for lib in $dlfiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlfiles " $abs" + done + dlfiles="$newdlfiles" + newdlprefiles= + for lib in $dlprefiles; do + case $lib in + [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; + *) abs=`pwd`"/$lib" ;; + esac + func_append newdlprefiles " $abs" + done + dlprefiles="$newdlprefiles" + fi + $RM $output + # place dlname in correct position for cygwin + # In fact, it would be nice if we could use this code for all target + # systems that can't hard-code library paths into their executables + # and that have no shared library path variable independent of PATH, + # but it turns out we can't easily determine that from inspecting + # libtool variables, so we have to hard-code the OSs to which it + # applies here; at the moment, that means platforms that use the PE + # object format with DLL files. See the long comment at the top of + # tests/bindir.at for full details. + tdlname=$dlname + case $host,$output,$installed,$module,$dlname in + *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) + # If a -bindir argument was supplied, place the dll there. + if test "x$bindir" != x ; + then + func_relative_path "$install_libdir" "$bindir" + tdlname=$func_relative_path_result$dlname + else + # Otherwise fall back on heuristic. + tdlname=../bin/$dlname + fi + ;; + esac + $ECHO > $output "\ +# $outputname - a libtool library file +# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION +# +# Please DO NOT delete this file! +# It is necessary for linking the library. + +# The name that we can dlopen(3). +dlname='$tdlname' + +# Names of this library. +library_names='$library_names' + +# The name of the static archive. +old_library='$old_library' + +# Linker flags that can not go in dependency_libs. +inherited_linker_flags='$new_inherited_linker_flags' + +# Libraries that this one depends upon. +dependency_libs='$dependency_libs' + +# Names of additional weak libraries provided by this library +weak_library_names='$weak_libs' + +# Version information for $libname. +current=$current +age=$age +revision=$revision + +# Is this an already installed library? +installed=$installed + +# Should we warn about portability when linking against -modules? +shouldnotlink=$module + +# Files to dlopen/dlpreopen +dlopen='$dlfiles' +dlpreopen='$dlprefiles' + +# Directory that this library needs to be installed in: +libdir='$install_libdir'" + if test "$installed" = no && test "$need_relink" = yes; then + $ECHO >> $output "\ +relink_command=\"$relink_command\"" + fi + done + } + + # Do a symbolic link so that the libtool archive can be found in + # LD_LIBRARY_PATH before the program is installed. + func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' + ;; + esac + exit $EXIT_SUCCESS +} + +{ test "$opt_mode" = link || test "$opt_mode" = relink; } && + func_mode_link ${1+"$@"} + + +# func_mode_uninstall arg... +func_mode_uninstall () +{ + $opt_debug + RM="$nonopt" + files= + rmforce= + exit_status=0 + + # This variable tells wrapper scripts just to set variables rather + # than running their programs. + libtool_install_magic="$magic" + + for arg + do + case $arg in + -f) func_append RM " $arg"; rmforce=yes ;; + -*) func_append RM " $arg" ;; + *) func_append files " $arg" ;; + esac + done + + test -z "$RM" && \ + func_fatal_help "you must specify an RM program" + + rmdirs= + + for file in $files; do + func_dirname "$file" "" "." + dir="$func_dirname_result" + if test "X$dir" = X.; then + odir="$objdir" + else + odir="$dir/$objdir" + fi + func_basename "$file" + name="$func_basename_result" + test "$opt_mode" = uninstall && odir="$dir" + + # Remember odir for removal later, being careful to avoid duplicates + if test "$opt_mode" = clean; then + case " $rmdirs " in + *" $odir "*) ;; + *) func_append rmdirs " $odir" ;; + esac + fi + + # Don't error if the file doesn't exist and rm -f was used. + if { test -L "$file"; } >/dev/null 2>&1 || + { test -h "$file"; } >/dev/null 2>&1 || + test -f "$file"; then + : + elif test -d "$file"; then + exit_status=1 + continue + elif test "$rmforce" = yes; then + continue + fi + + rmfiles="$file" + + case $name in + *.la) + # Possibly a libtool archive, so verify it. + if func_lalib_p "$file"; then + func_source $dir/$name + + # Delete the libtool libraries and symlinks. + for n in $library_names; do + func_append rmfiles " $odir/$n" + done + test -n "$old_library" && func_append rmfiles " $odir/$old_library" + + case "$opt_mode" in + clean) + case " $library_names " in + *" $dlname "*) ;; + *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;; + esac + test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i" + ;; + uninstall) + if test -n "$library_names"; then + # Do each command in the postuninstall commands. + func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + + if test -n "$old_library"; then + # Do each command in the old_postuninstall commands. + func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' + fi + # FIXME: should reinstall the best remaining shared library. + ;; + esac + fi + ;; + + *.lo) + # Possibly a libtool object, so verify it. + if func_lalib_p "$file"; then + + # Read the .lo file + func_source $dir/$name + + # Add PIC object to the list of files to remove. + if test -n "$pic_object" && + test "$pic_object" != none; then + func_append rmfiles " $dir/$pic_object" + fi + + # Add non-PIC object to the list of files to remove. + if test -n "$non_pic_object" && + test "$non_pic_object" != none; then + func_append rmfiles " $dir/$non_pic_object" + fi + fi + ;; + + *) + if test "$opt_mode" = clean ; then + noexename=$name + case $file in + *.exe) + func_stripname '' '.exe' "$file" + file=$func_stripname_result + func_stripname '' '.exe' "$name" + noexename=$func_stripname_result + # $file with .exe has already been added to rmfiles, + # add $file without .exe + func_append rmfiles " $file" + ;; + esac + # Do a test to see if this is a libtool program. + if func_ltwrapper_p "$file"; then + if func_ltwrapper_executable_p "$file"; then + func_ltwrapper_scriptname "$file" + relink_command= + func_source $func_ltwrapper_scriptname_result + func_append rmfiles " $func_ltwrapper_scriptname_result" + else + relink_command= + func_source $dir/$noexename + fi + + # note $name still contains .exe if it was in $file originally + # as does the version of $file that was added into $rmfiles + func_append rmfiles " $odir/$name $odir/${name}S.${objext}" + if test "$fast_install" = yes && test -n "$relink_command"; then + func_append rmfiles " $odir/lt-$name" + fi + if test "X$noexename" != "X$name" ; then + func_append rmfiles " $odir/lt-${noexename}.c" + fi + fi + fi + ;; + esac + func_show_eval "$RM $rmfiles" 'exit_status=1' + done + + # Try to remove the ${objdir}s in the directories where we deleted files + for dir in $rmdirs; do + if test -d "$dir"; then + func_show_eval "rmdir $dir >/dev/null 2>&1" + fi + done + + exit $exit_status +} + +{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } && + func_mode_uninstall ${1+"$@"} + +test -z "$opt_mode" && { + help="$generic_help" + func_fatal_help "you must specify a MODE" +} + +test -z "$exec_cmd" && \ + func_fatal_help "invalid operation mode \`$opt_mode'" + +if test -n "$exec_cmd"; then + eval exec "$exec_cmd" + exit $EXIT_FAILURE +fi + +exit $exit_status + + +# The TAGs below are defined such that we never get into a situation +# in which we disable both kinds of libraries. Given conflicting +# choices, we go for a static library, that is the most portable, +# since we can't tell whether shared libraries were disabled because +# the user asked for that or because the platform doesn't support +# them. This is particularly important on AIX, because we don't +# support having both static and shared libraries enabled at the same +# time on that platform, so we default to a shared-only configuration. +# If a disable-shared tag is given, we'll fallback to a static-only +# configuration. But we'll never go from static-only to shared-only. + +# ### BEGIN LIBTOOL TAG CONFIG: disable-shared +build_libtool_libs=no +build_old_libs=yes +# ### END LIBTOOL TAG CONFIG: disable-shared + +# ### BEGIN LIBTOOL TAG CONFIG: disable-static +build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` +# ### END LIBTOOL TAG CONFIG: disable-static + +# Local Variables: +# mode:shell-script +# sh-indentation:2 +# End: +# vi:sw=2 + diff --git a/m4/Makefile.am b/m4/Makefile.am new file mode 100644 index 00000000..e69de29b diff --git a/m4/Makefile.in b/m4/Makefile.in new file mode 100644 index 00000000..133f09aa --- /dev/null +++ b/m4/Makefile.in @@ -0,0 +1,390 @@ +# Makefile.in generated by automake 1.11.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = m4 +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUG_DEFINES = @DEBUG_DEFINES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTPMS_VERSION = @LIBTPMS_VERSION@ +LIBTPMS_VERSION_INFO = @LIBTPMS_VERSION_INFO@ +LIBTPMS_VER_MAJOR = @LIBTPMS_VER_MAJOR@ +LIBTPMS_VER_MICRO = @LIBTPMS_VER_MICRO@ +LIBTPMS_VER_MINOR = @LIBTPMS_VER_MINOR@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign m4/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign m4/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/m4/libtool.m4 b/m4/libtool.m4 new file mode 100644 index 00000000..56666f0e --- /dev/null +++ b/m4/libtool.m4 @@ -0,0 +1,7986 @@ +# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- +# +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +m4_define([_LT_COPYING], [dnl +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, +# 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# Written by Gordon Matzigkeit, 1996 +# +# This file is part of GNU Libtool. +# +# GNU Libtool 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. +# +# As a special exception to the GNU General Public License, +# if you distribute this file as part of a program or library that +# is built using GNU Libtool, you may include this file under the +# same distribution terms that you use for the rest of that program. +# +# GNU Libtool 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 GNU Libtool; see the file COPYING. If not, a copy +# can be downloaded from http://www.gnu.org/licenses/gpl.html, or +# obtained by writing to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +]) + +# serial 57 LT_INIT + + +# LT_PREREQ(VERSION) +# ------------------ +# Complain and exit if this libtool version is less that VERSION. +m4_defun([LT_PREREQ], +[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, + [m4_default([$3], + [m4_fatal([Libtool version $1 or higher is required], + 63)])], + [$2])]) + + +# _LT_CHECK_BUILDDIR +# ------------------ +# Complain if the absolute build directory name contains unusual characters +m4_defun([_LT_CHECK_BUILDDIR], +[case `pwd` in + *\ * | *\ *) + AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; +esac +]) + + +# LT_INIT([OPTIONS]) +# ------------------ +AC_DEFUN([LT_INIT], +[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT +AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl +AC_BEFORE([$0], [LT_LANG])dnl +AC_BEFORE([$0], [LT_OUTPUT])dnl +AC_BEFORE([$0], [LTDL_INIT])dnl +m4_require([_LT_CHECK_BUILDDIR])dnl + +dnl Autoconf doesn't catch unexpanded LT_ macros by default: +m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl +m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl +dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 +dnl unless we require an AC_DEFUNed macro: +AC_REQUIRE([LTOPTIONS_VERSION])dnl +AC_REQUIRE([LTSUGAR_VERSION])dnl +AC_REQUIRE([LTVERSION_VERSION])dnl +AC_REQUIRE([LTOBSOLETE_VERSION])dnl +m4_require([_LT_PROG_LTMAIN])dnl + +_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) + +dnl Parse OPTIONS +_LT_SET_OPTIONS([$0], [$1]) + +# This can be used to rebuild libtool when needed +LIBTOOL_DEPS="$ltmain" + +# Always use our own libtool. +LIBTOOL='$(SHELL) $(top_builddir)/libtool' +AC_SUBST(LIBTOOL)dnl + +_LT_SETUP + +# Only expand once: +m4_define([LT_INIT]) +])# LT_INIT + +# Old names: +AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) +AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PROG_LIBTOOL], []) +dnl AC_DEFUN([AM_PROG_LIBTOOL], []) + + +# _LT_CC_BASENAME(CC) +# ------------------- +# Calculate cc_basename. Skip known compiler wrappers and cross-prefix. +m4_defun([_LT_CC_BASENAME], +[for cc_temp in $1""; do + case $cc_temp in + compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; + distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; + \-*) ;; + *) break;; + esac +done +cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` +]) + + +# _LT_FILEUTILS_DEFAULTS +# ---------------------- +# It is okay to use these file commands and assume they have been set +# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. +m4_defun([_LT_FILEUTILS_DEFAULTS], +[: ${CP="cp -f"} +: ${MV="mv -f"} +: ${RM="rm -f"} +])# _LT_FILEUTILS_DEFAULTS + + +# _LT_SETUP +# --------- +m4_defun([_LT_SETUP], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl + +_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl +dnl +_LT_DECL([], [host_alias], [0], [The host system])dnl +_LT_DECL([], [host], [0])dnl +_LT_DECL([], [host_os], [0])dnl +dnl +_LT_DECL([], [build_alias], [0], [The build system])dnl +_LT_DECL([], [build], [0])dnl +_LT_DECL([], [build_os], [0])dnl +dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +dnl +AC_REQUIRE([AC_PROG_LN_S])dnl +test -z "$LN_S" && LN_S="ln -s" +_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl +dnl +AC_REQUIRE([LT_CMD_MAX_LEN])dnl +_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl +_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl +dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl +m4_require([_LT_CMD_RELOAD])dnl +m4_require([_LT_CHECK_MAGIC_METHOD])dnl +m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl +m4_require([_LT_CMD_OLD_ARCHIVE])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_WITH_SYSROOT])dnl + +_LT_CONFIG_LIBTOOL_INIT([ +# See if we are running on zsh, and set the options which allow our +# commands through without removal of \ escapes INIT. +if test -n "\${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi +]) +if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST +fi + +_LT_CHECK_OBJDIR + +m4_require([_LT_TAG_COMPILER])dnl + +case $host_os in +aix3*) + # AIX sometimes has problems with the GCC collect2 program. For some + # reason, if we set the COLLECT_NAMES environment variable, the problems + # vanish in a puff of smoke. + if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES + fi + ;; +esac + +# Global variables: +ofile=libtool +can_build_shared=yes + +# All known linkers require a `.a' archive for static linking (except MSVC, +# which needs '.lib'). +libext=a + +with_gnu_ld="$lt_cv_prog_gnu_ld" + +old_CC="$CC" +old_CFLAGS="$CFLAGS" + +# Set sane defaults for various variables +test -z "$CC" && CC=cc +test -z "$LTCC" && LTCC=$CC +test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS +test -z "$LD" && LD=ld +test -z "$ac_objext" && ac_objext=o + +_LT_CC_BASENAME([$compiler]) + +# Only perform the check for file, if the check method requires it +test -z "$MAGIC_CMD" && MAGIC_CMD=file +case $deplibs_check_method in +file_magic*) + if test "$file_magic_cmd" = '$MAGIC_CMD'; then + _LT_PATH_MAGIC + fi + ;; +esac + +# Use C for the default configuration in the libtool script +LT_SUPPORTED_TAG([CC]) +_LT_LANG_C_CONFIG +_LT_LANG_DEFAULT_CONFIG +_LT_CONFIG_COMMANDS +])# _LT_SETUP + + +# _LT_PREPARE_SED_QUOTE_VARS +# -------------------------- +# Define a few sed substitution that help us do robust quoting. +m4_defun([_LT_PREPARE_SED_QUOTE_VARS], +[# Backslashify metacharacters that are still active within +# double-quoted strings. +sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' + +# Same as above, but do not quote variable references. +double_quote_subst='s/\([["`\\]]\)/\\\1/g' + +# Sed substitution to delay expansion of an escaped shell variable in a +# double_quote_subst'ed string. +delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' + +# Sed substitution to delay expansion of an escaped single quote. +delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' + +# Sed substitution to avoid accidental globbing in evaled expressions +no_glob_subst='s/\*/\\\*/g' +]) + +# _LT_PROG_LTMAIN +# --------------- +# Note that this code is called both from `configure', and `config.status' +# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, +# `config.status' has no value for ac_aux_dir unless we are using Automake, +# so we pass a copy along to make sure it has a sensible value anyway. +m4_defun([_LT_PROG_LTMAIN], +[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl +_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) +ltmain="$ac_aux_dir/ltmain.sh" +])# _LT_PROG_LTMAIN + + +## ------------------------------------- ## +## Accumulate code for creating libtool. ## +## ------------------------------------- ## + +# So that we can recreate a full libtool script including additional +# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS +# in macros and then make a single call at the end using the `libtool' +# label. + + +# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) +# ---------------------------------------- +# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL_INIT], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_INIT], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_INIT]) + + +# _LT_CONFIG_LIBTOOL([COMMANDS]) +# ------------------------------ +# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. +m4_define([_LT_CONFIG_LIBTOOL], +[m4_ifval([$1], + [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], + [$1 +])])]) + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) + + +# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) +# ----------------------------------------------------- +m4_defun([_LT_CONFIG_SAVE_COMMANDS], +[_LT_CONFIG_LIBTOOL([$1]) +_LT_CONFIG_LIBTOOL_INIT([$2]) +]) + + +# _LT_FORMAT_COMMENT([COMMENT]) +# ----------------------------- +# Add leading comment marks to the start of each line, and a trailing +# full-stop to the whole comment if one is not present already. +m4_define([_LT_FORMAT_COMMENT], +[m4_ifval([$1], [ +m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], + [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) +)]) + + + +## ------------------------ ## +## FIXME: Eliminate VARNAME ## +## ------------------------ ## + + +# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) +# ------------------------------------------------------------------- +# CONFIGNAME is the name given to the value in the libtool script. +# VARNAME is the (base) name used in the configure script. +# VALUE may be 0, 1 or 2 for a computed quote escaped value based on +# VARNAME. Any other value will be used directly. +m4_define([_LT_DECL], +[lt_if_append_uniq([lt_decl_varnames], [$2], [, ], + [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], + [m4_ifval([$1], [$1], [$2])]) + lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) + m4_ifval([$4], + [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) + lt_dict_add_subkey([lt_decl_dict], [$2], + [tagged?], [m4_ifval([$5], [yes], [no])])]) +]) + + +# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) +# -------------------------------------------------------- +m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) + + +# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_tag_varnames], +[_lt_decl_filter([tagged?], [yes], $@)]) + + +# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) +# --------------------------------------------------------- +m4_define([_lt_decl_filter], +[m4_case([$#], + [0], [m4_fatal([$0: too few arguments: $#])], + [1], [m4_fatal([$0: too few arguments: $#: $1])], + [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], + [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], + [lt_dict_filter([lt_decl_dict], $@)])[]dnl +]) + + +# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) +# -------------------------------------------------- +m4_define([lt_decl_quote_varnames], +[_lt_decl_filter([value], [1], $@)]) + + +# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_dquote_varnames], +[_lt_decl_filter([value], [2], $@)]) + + +# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) +# --------------------------------------------------- +m4_define([lt_decl_varnames_tagged], +[m4_assert([$# <= 2])dnl +_$0(m4_quote(m4_default([$1], [[, ]])), + m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), + m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) +m4_define([_lt_decl_varnames_tagged], +[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) + + +# lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) +# ------------------------------------------------ +m4_define([lt_decl_all_varnames], +[_$0(m4_quote(m4_default([$1], [[, ]])), + m4_if([$2], [], + m4_quote(lt_decl_varnames), + m4_quote(m4_shift($@))))[]dnl +]) +m4_define([_lt_decl_all_varnames], +[lt_join($@, lt_decl_varnames_tagged([$1], + lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl +]) + + +# _LT_CONFIG_STATUS_DECLARE([VARNAME]) +# ------------------------------------ +# Quote a variable value, and forward it to `config.status' so that its +# declaration there will have the same value as in `configure'. VARNAME +# must have a single quote delimited value for this to work. +m4_define([_LT_CONFIG_STATUS_DECLARE], +[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) + + +# _LT_CONFIG_STATUS_DECLARATIONS +# ------------------------------ +# We delimit libtool config variables with single quotes, so when +# we write them to config.status, we have to be sure to quote all +# embedded single quotes properly. In configure, this macro expands +# each variable declared with _LT_DECL (and _LT_TAGDECL) into: +# +# ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' +m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], +[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), + [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAGS +# ---------------- +# Output comment and list of tags supported by the script +m4_defun([_LT_LIBTOOL_TAGS], +[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl +available_tags="_LT_TAGS"dnl +]) + + +# _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) +# ----------------------------------- +# Extract the dictionary values for VARNAME (optionally with TAG) and +# expand to a commented shell variable setting: +# +# # Some comment about what VAR is for. +# visible_name=$lt_internal_name +m4_define([_LT_LIBTOOL_DECLARE], +[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], + [description])))[]dnl +m4_pushdef([_libtool_name], + m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl +m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), + [0], [_libtool_name=[$]$1], + [1], [_libtool_name=$lt_[]$1], + [2], [_libtool_name=$lt_[]$1], + [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl +m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl +]) + + +# _LT_LIBTOOL_CONFIG_VARS +# ----------------------- +# Produce commented declarations of non-tagged libtool config variables +# suitable for insertion in the LIBTOOL CONFIG section of the `libtool' +# script. Tagged libtool config variables (even for the LIBTOOL CONFIG +# section) are produced by _LT_LIBTOOL_TAG_VARS. +m4_defun([_LT_LIBTOOL_CONFIG_VARS], +[m4_foreach([_lt_var], + m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) + + +# _LT_LIBTOOL_TAG_VARS(TAG) +# ------------------------- +m4_define([_LT_LIBTOOL_TAG_VARS], +[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), + [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) + + +# _LT_TAGVAR(VARNAME, [TAGNAME]) +# ------------------------------ +m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) + + +# _LT_CONFIG_COMMANDS +# ------------------- +# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of +# variables for single and double quote escaping we saved from calls +# to _LT_DECL, we can put quote escaped variables declarations +# into `config.status', and then the shell code to quote escape them in +# for loops in `config.status'. Finally, any additional code accumulated +# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. +m4_defun([_LT_CONFIG_COMMANDS], +[AC_PROVIDE_IFELSE([LT_OUTPUT], + dnl If the libtool generation code has been placed in $CONFIG_LT, + dnl instead of duplicating it all over again into config.status, + dnl then we will have config.status run $CONFIG_LT later, so it + dnl needs to know what name is stored there: + [AC_CONFIG_COMMANDS([libtool], + [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], + dnl If the libtool generation code is destined for config.status, + dnl expand the accumulated commands and init code now: + [AC_CONFIG_COMMANDS([libtool], + [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) +])#_LT_CONFIG_COMMANDS + + +# Initialize. +m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], +[ + +# The HP-UX ksh and POSIX shell print the target directory to stdout +# if CDPATH is set. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +sed_quote_subst='$sed_quote_subst' +double_quote_subst='$double_quote_subst' +delay_variable_subst='$delay_variable_subst' +_LT_CONFIG_STATUS_DECLARATIONS +LTCC='$LTCC' +LTCFLAGS='$LTCFLAGS' +compiler='$compiler_DEFAULT' + +# A function that is used when there is no print builtin or printf. +func_fallback_echo () +{ + eval 'cat <<_LTECHO_EOF +\$[]1 +_LTECHO_EOF' +} + +# Quote evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_quote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +# Double-quote double-evaled strings. +for var in lt_decl_all_varnames([[ \ +]], lt_decl_dquote_varnames); do + case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in + *[[\\\\\\\`\\"\\\$]]*) + eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" + ;; + *) + eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" + ;; + esac +done + +_LT_OUTPUT_LIBTOOL_INIT +]) + +# _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) +# ------------------------------------ +# Generate a child script FILE with all initialization necessary to +# reuse the environment learned by the parent script, and make the +# file executable. If COMMENT is supplied, it is inserted after the +# `#!' sequence but before initialization text begins. After this +# macro, additional text can be appended to FILE to form the body of +# the child script. The macro ends with non-zero status if the +# file could not be fully written (such as if the disk is full). +m4_ifdef([AS_INIT_GENERATED], +[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], +[m4_defun([_LT_GENERATED_FILE_INIT], +[m4_require([AS_PREPARE])]dnl +[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl +[lt_write_fail=0 +cat >$1 <<_ASEOF || lt_write_fail=1 +#! $SHELL +# Generated by $as_me. +$2 +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$1 <<\_ASEOF || lt_write_fail=1 +AS_SHELL_SANITIZE +_AS_PREPARE +exec AS_MESSAGE_FD>&1 +_ASEOF +test $lt_write_fail = 0 && chmod +x $1[]dnl +m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT + +# LT_OUTPUT +# --------- +# This macro allows early generation of the libtool script (before +# AC_OUTPUT is called), incase it is used in configure for compilation +# tests. +AC_DEFUN([LT_OUTPUT], +[: ${CONFIG_LT=./config.lt} +AC_MSG_NOTICE([creating $CONFIG_LT]) +_LT_GENERATED_FILE_INIT(["$CONFIG_LT"], +[# Run this file to recreate a libtool stub with the current configuration.]) + +cat >>"$CONFIG_LT" <<\_LTEOF +lt_cl_silent=false +exec AS_MESSAGE_LOG_FD>>config.log +{ + echo + AS_BOX([Running $as_me.]) +} >&AS_MESSAGE_LOG_FD + +lt_cl_help="\ +\`$as_me' creates a local libtool stub from the current configuration, +for use in further configure time tests before the real libtool is +generated. + +Usage: $[0] [[OPTIONS]] + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + +Report bugs to ." + +lt_cl_version="\ +m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl +m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) +configured by $[0], generated by m4_PACKAGE_STRING. + +Copyright (C) 2011 Free Software Foundation, Inc. +This config.lt script is free software; the Free Software Foundation +gives unlimited permision to copy, distribute and modify it." + +while test $[#] != 0 +do + case $[1] in + --version | --v* | -V ) + echo "$lt_cl_version"; exit 0 ;; + --help | --h* | -h ) + echo "$lt_cl_help"; exit 0 ;; + --debug | --d* | -d ) + debug=: ;; + --quiet | --q* | --silent | --s* | -q ) + lt_cl_silent=: ;; + + -*) AC_MSG_ERROR([unrecognized option: $[1] +Try \`$[0] --help' for more information.]) ;; + + *) AC_MSG_ERROR([unrecognized argument: $[1] +Try \`$[0] --help' for more information.]) ;; + esac + shift +done + +if $lt_cl_silent; then + exec AS_MESSAGE_FD>/dev/null +fi +_LTEOF + +cat >>"$CONFIG_LT" <<_LTEOF +_LT_OUTPUT_LIBTOOL_COMMANDS_INIT +_LTEOF + +cat >>"$CONFIG_LT" <<\_LTEOF +AC_MSG_NOTICE([creating $ofile]) +_LT_OUTPUT_LIBTOOL_COMMANDS +AS_EXIT(0) +_LTEOF +chmod +x "$CONFIG_LT" + +# configure is writing to config.log, but config.lt does its own redirection, +# appending to config.log, which fails on DOS, as config.log is still kept +# open by configure. Here we exec the FD to /dev/null, effectively closing +# config.log, so it can be properly (re)opened and appended to by config.lt. +lt_cl_success=: +test "$silent" = yes && + lt_config_lt_args="$lt_config_lt_args --quiet" +exec AS_MESSAGE_LOG_FD>/dev/null +$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false +exec AS_MESSAGE_LOG_FD>>config.log +$lt_cl_success || AS_EXIT(1) +])# LT_OUTPUT + + +# _LT_CONFIG(TAG) +# --------------- +# If TAG is the built-in tag, create an initial libtool script with a +# default configuration from the untagged config vars. Otherwise add code +# to config.status for appending the configuration named by TAG from the +# matching tagged config vars. +m4_defun([_LT_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_CONFIG_SAVE_COMMANDS([ + m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl + m4_if(_LT_TAG, [C], [ + # See if we are running on zsh, and set the options which allow our + # commands through without removal of \ escapes. + if test -n "${ZSH_VERSION+set}" ; then + setopt NO_GLOB_SUBST + fi + + cfgfile="${ofile}T" + trap "$RM \"$cfgfile\"; exit 1" 1 2 15 + $RM "$cfgfile" + + cat <<_LT_EOF >> "$cfgfile" +#! $SHELL + +# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. +# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION +# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: +# NOTE: Changes made to this file will be lost: look at ltmain.sh. +# +_LT_COPYING +_LT_LIBTOOL_TAGS + +# ### BEGIN LIBTOOL CONFIG +_LT_LIBTOOL_CONFIG_VARS +_LT_LIBTOOL_TAG_VARS +# ### END LIBTOOL CONFIG + +_LT_EOF + + case $host_os in + aix3*) + cat <<\_LT_EOF >> "$cfgfile" +# AIX sometimes has problems with the GCC collect2 program. For some +# reason, if we set the COLLECT_NAMES environment variable, the problems +# vanish in a puff of smoke. +if test "X${COLLECT_NAMES+set}" != Xset; then + COLLECT_NAMES= + export COLLECT_NAMES +fi +_LT_EOF + ;; + esac + + _LT_PROG_LTMAIN + + # We use sed instead of cat because bash on DJGPP gets confused if + # if finds mixed CR/LF and LF-only lines. Since sed operates in + # text mode, it properly converts lines to CR/LF. This bash problem + # is reportedly fixed, but why not run on old versions too? + sed '$q' "$ltmain" >> "$cfgfile" \ + || (rm -f "$cfgfile"; exit 1) + + _LT_PROG_REPLACE_SHELLFNS + + mv -f "$cfgfile" "$ofile" || + (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") + chmod +x "$ofile" +], +[cat <<_LT_EOF >> "$ofile" + +dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded +dnl in a comment (ie after a #). +# ### BEGIN LIBTOOL TAG CONFIG: $1 +_LT_LIBTOOL_TAG_VARS(_LT_TAG) +# ### END LIBTOOL TAG CONFIG: $1 +_LT_EOF +])dnl /m4_if +], +[m4_if([$1], [], [ + PACKAGE='$PACKAGE' + VERSION='$VERSION' + TIMESTAMP='$TIMESTAMP' + RM='$RM' + ofile='$ofile'], []) +])dnl /_LT_CONFIG_SAVE_COMMANDS +])# _LT_CONFIG + + +# LT_SUPPORTED_TAG(TAG) +# --------------------- +# Trace this macro to discover what tags are supported by the libtool +# --tag option, using: +# autoconf --trace 'LT_SUPPORTED_TAG:$1' +AC_DEFUN([LT_SUPPORTED_TAG], []) + + +# C support is built-in for now +m4_define([_LT_LANG_C_enabled], []) +m4_define([_LT_TAGS], []) + + +# LT_LANG(LANG) +# ------------- +# Enable libtool support for the given language if not already enabled. +AC_DEFUN([LT_LANG], +[AC_BEFORE([$0], [LT_OUTPUT])dnl +m4_case([$1], + [C], [_LT_LANG(C)], + [C++], [_LT_LANG(CXX)], + [Go], [_LT_LANG(GO)], + [Java], [_LT_LANG(GCJ)], + [Fortran 77], [_LT_LANG(F77)], + [Fortran], [_LT_LANG(FC)], + [Windows Resource], [_LT_LANG(RC)], + [m4_ifdef([_LT_LANG_]$1[_CONFIG], + [_LT_LANG($1)], + [m4_fatal([$0: unsupported language: "$1"])])])dnl +])# LT_LANG + + +# _LT_LANG(LANGNAME) +# ------------------ +m4_defun([_LT_LANG], +[m4_ifdef([_LT_LANG_]$1[_enabled], [], + [LT_SUPPORTED_TAG([$1])dnl + m4_append([_LT_TAGS], [$1 ])dnl + m4_define([_LT_LANG_]$1[_enabled], [])dnl + _LT_LANG_$1_CONFIG($1)])dnl +])# _LT_LANG + + +m4_ifndef([AC_PROG_GO], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_GO. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ +m4_defun([AC_PROG_GO], +[AC_LANG_PUSH(Go)dnl +AC_ARG_VAR([GOC], [Go compiler command])dnl +AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl +_AC_ARG_VAR_LDFLAGS()dnl +AC_CHECK_TOOL(GOC, gccgo) +if test -z "$GOC"; then + if test -n "$ac_tool_prefix"; then + AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) + fi +fi +if test -z "$GOC"; then + AC_CHECK_PROG(GOC, gccgo, gccgo, false) +fi +])#m4_defun +])#m4_ifndef + + +# _LT_LANG_DEFAULT_CONFIG +# ----------------------- +m4_defun([_LT_LANG_DEFAULT_CONFIG], +[AC_PROVIDE_IFELSE([AC_PROG_CXX], + [LT_LANG(CXX)], + [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) + +AC_PROVIDE_IFELSE([AC_PROG_F77], + [LT_LANG(F77)], + [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) + +AC_PROVIDE_IFELSE([AC_PROG_FC], + [LT_LANG(FC)], + [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) + +dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal +dnl pulling things in needlessly. +AC_PROVIDE_IFELSE([AC_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], + [LT_LANG(GCJ)], + [AC_PROVIDE_IFELSE([LT_PROG_GCJ], + [LT_LANG(GCJ)], + [m4_ifdef([AC_PROG_GCJ], + [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([A][M_PROG_GCJ], + [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) + m4_ifdef([LT_PROG_GCJ], + [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) + +AC_PROVIDE_IFELSE([AC_PROG_GO], + [LT_LANG(GO)], + [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) + +AC_PROVIDE_IFELSE([LT_PROG_RC], + [LT_LANG(RC)], + [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) +])# _LT_LANG_DEFAULT_CONFIG + +# Obsolete macros: +AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) +AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) +AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) +AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) +AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_CXX], []) +dnl AC_DEFUN([AC_LIBTOOL_F77], []) +dnl AC_DEFUN([AC_LIBTOOL_FC], []) +dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) +dnl AC_DEFUN([AC_LIBTOOL_RC], []) + + +# _LT_TAG_COMPILER +# ---------------- +m4_defun([_LT_TAG_COMPILER], +[AC_REQUIRE([AC_PROG_CC])dnl + +_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl +_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl +_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl +_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl + +# If no C compiler was specified, use CC. +LTCC=${LTCC-"$CC"} + +# If no C compiler flags were specified, use CFLAGS. +LTCFLAGS=${LTCFLAGS-"$CFLAGS"} + +# Allow CC to be a program name with arguments. +compiler=$CC +])# _LT_TAG_COMPILER + + +# _LT_COMPILER_BOILERPLATE +# ------------------------ +# Check for compiler boilerplate output or warnings with +# the simple compiler test code. +m4_defun([_LT_COMPILER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_compile_test_code" >conftest.$ac_ext +eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_compiler_boilerplate=`cat conftest.err` +$RM conftest* +])# _LT_COMPILER_BOILERPLATE + + +# _LT_LINKER_BOILERPLATE +# ---------------------- +# Check for linker boilerplate output or warnings with +# the simple link test code. +m4_defun([_LT_LINKER_BOILERPLATE], +[m4_require([_LT_DECL_SED])dnl +ac_outfile=conftest.$ac_objext +echo "$lt_simple_link_test_code" >conftest.$ac_ext +eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err +_lt_linker_boilerplate=`cat conftest.err` +$RM -r conftest* +])# _LT_LINKER_BOILERPLATE + +# _LT_REQUIRED_DARWIN_CHECKS +# ------------------------- +m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ + case $host_os in + rhapsody* | darwin*) + AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) + AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) + AC_CHECK_TOOL([LIPO], [lipo], [:]) + AC_CHECK_TOOL([OTOOL], [otool], [:]) + AC_CHECK_TOOL([OTOOL64], [otool64], [:]) + _LT_DECL([], [DSYMUTIL], [1], + [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) + _LT_DECL([], [NMEDIT], [1], + [Tool to change global to local symbols on Mac OS X]) + _LT_DECL([], [LIPO], [1], + [Tool to manipulate fat objects and archives on Mac OS X]) + _LT_DECL([], [OTOOL], [1], + [ldd/readelf like tool for Mach-O binaries on Mac OS X]) + _LT_DECL([], [OTOOL64], [1], + [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) + + AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], + [lt_cv_apple_cc_single_mod=no + if test -z "${LT_MULTI_MODULE}"; then + # By default we will add the -single_module flag. You can override + # by either setting the environment variable LT_MULTI_MODULE + # non-empty at configure time, or by adding -multi_module to the + # link flags. + rm -rf libconftest.dylib* + echo "int foo(void){return 1;}" > conftest.c + echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ +-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ + -dynamiclib -Wl,-single_module conftest.c 2>conftest.err + _lt_result=$? + # If there is a non-empty error log, and "single_module" + # appears in it, assume the flag caused a linker warning + if test -s conftest.err && $GREP single_module conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + # Otherwise, if the output was created with a 0 exit code from + # the compiler, it worked. + elif test -f libconftest.dylib && test $_lt_result -eq 0; then + lt_cv_apple_cc_single_mod=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -rf libconftest.dylib* + rm -f conftest.* + fi]) + + AC_CACHE_CHECK([for -exported_symbols_list linker flag], + [lt_cv_ld_exported_symbols_list], + [lt_cv_ld_exported_symbols_list=no + save_LDFLAGS=$LDFLAGS + echo "_main" > conftest.sym + LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [lt_cv_ld_exported_symbols_list=yes], + [lt_cv_ld_exported_symbols_list=no]) + LDFLAGS="$save_LDFLAGS" + ]) + + AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], + [lt_cv_ld_force_load=no + cat > conftest.c << _LT_EOF +int forced_loaded() { return 2;} +_LT_EOF + echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD + echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD + $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD + echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD + $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD + cat > conftest.c << _LT_EOF +int main() { return 0;} +_LT_EOF + echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD + $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err + _lt_result=$? + if test -s conftest.err && $GREP force_load conftest.err; then + cat conftest.err >&AS_MESSAGE_LOG_FD + elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then + lt_cv_ld_force_load=yes + else + cat conftest.err >&AS_MESSAGE_LOG_FD + fi + rm -f conftest.err libconftest.a conftest conftest.c + rm -rf conftest.dSYM + ]) + case $host_os in + rhapsody* | darwin1.[[012]]) + _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; + darwin1.*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + darwin*) # darwin 5.x on + # if running on 10.5 or later, the deployment target defaults + # to the OS version, if on x86, and 10.4, the deployment + # target defaults to 10.4. Don't you love it? + case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in + 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + 10.[[012]]*) + _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; + 10.*) + _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; + esac + ;; + esac + if test "$lt_cv_apple_cc_single_mod" = "yes"; then + _lt_dar_single_mod='$single_module' + fi + if test "$lt_cv_ld_exported_symbols_list" = "yes"; then + _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' + else + _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' + fi + if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then + _lt_dsymutil='~$DSYMUTIL $lib || :' + else + _lt_dsymutil= + fi + ;; + esac +]) + + +# _LT_DARWIN_LINKER_FEATURES([TAG]) +# --------------------------------- +# Checks for linker and compiler features on darwin +m4_defun([_LT_DARWIN_LINKER_FEATURES], +[ + m4_require([_LT_REQUIRED_DARWIN_CHECKS]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_automatic, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + if test "$lt_cv_ld_force_load" = "yes"; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' + m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], + [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='' + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" + case $cc_basename in + ifort*) _lt_dar_can_shared=yes ;; + *) _lt_dar_can_shared=$GCC ;; + esac + if test "$_lt_dar_can_shared" = "yes"; then + output_verbose_link_cmd=func_echo_all + _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" + _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" + _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" + m4_if([$1], [CXX], +[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then + _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" + _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" + fi +],[]) + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi +]) + +# _LT_SYS_MODULE_PATH_AIX([TAGNAME]) +# ---------------------------------- +# Links a minimal program and checks the executable +# for the system default hardcoded library path. In most cases, +# this is /usr/lib:/lib, but when the MPI compilers are used +# the location of the communication and MPI libs are included too. +# If we don't find anything, use the default library path according +# to the aix ld manual. +# Store the results from the different compilers for each TAGNAME. +# Allow to override them for all tags through lt_cv_aix_libpath. +m4_defun([_LT_SYS_MODULE_PATH_AIX], +[m4_require([_LT_DECL_SED])dnl +if test "${lt_cv_aix_libpath+set}" = set; then + aix_libpath=$lt_cv_aix_libpath +else + AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], + [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ + lt_aix_libpath_sed='[ + /Import File Strings/,/^$/ { + /^0/ { + s/^0 *\([^ ]*\) *$/\1/ + p + } + }]' + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + # Check for a 64-bit object if we didn't find anything. + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` + fi],[]) + if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then + _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" + fi + ]) + aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) +fi +])# _LT_SYS_MODULE_PATH_AIX + + +# _LT_SHELL_INIT(ARG) +# ------------------- +m4_define([_LT_SHELL_INIT], +[m4_divert_text([M4SH-INIT], [$1 +])])# _LT_SHELL_INIT + + + +# _LT_PROG_ECHO_BACKSLASH +# ----------------------- +# Find how we can fake an echo command that does not interpret backslash. +# In particular, with Autoconf 2.60 or later we add some code to the start +# of the generated configure script which will find a shell with a builtin +# printf (which we can use as an echo command). +m4_defun([_LT_PROG_ECHO_BACKSLASH], +[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO +ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + +AC_MSG_CHECKING([how to print strings]) +# Test print first, because it will be a builtin if present. +if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ + test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='print -r --' +elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then + ECHO='printf %s\n' +else + # Use this function as a fallback that always works. + func_fallback_echo () + { + eval 'cat <<_LTECHO_EOF +$[]1 +_LTECHO_EOF' + } + ECHO='func_fallback_echo' +fi + +# func_echo_all arg... +# Invoke $ECHO with all args, space-separated. +func_echo_all () +{ + $ECHO "$*" +} + +case "$ECHO" in + printf*) AC_MSG_RESULT([printf]) ;; + print*) AC_MSG_RESULT([print -r]) ;; + *) AC_MSG_RESULT([cat]) ;; +esac + +m4_ifdef([_AS_DETECT_SUGGESTED], +[_AS_DETECT_SUGGESTED([ + test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( + ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO + ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO + PATH=/empty FPATH=/empty; export PATH FPATH + test "X`printf %s $ECHO`" = "X$ECHO" \ + || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) + +_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) +_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) +])# _LT_PROG_ECHO_BACKSLASH + + +# _LT_WITH_SYSROOT +# ---------------- +AC_DEFUN([_LT_WITH_SYSROOT], +[AC_MSG_CHECKING([for sysroot]) +AC_ARG_WITH([sysroot], +[ --with-sysroot[=DIR] Search for dependent libraries within DIR + (or the compiler's sysroot if not specified).], +[], [with_sysroot=no]) + +dnl lt_sysroot will always be passed unquoted. We quote it here +dnl in case the user passed a directory name. +lt_sysroot= +case ${with_sysroot} in #( + yes) + if test "$GCC" = yes; then + lt_sysroot=`$CC --print-sysroot 2>/dev/null` + fi + ;; #( + /*) + lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` + ;; #( + no|'') + ;; #( + *) + AC_MSG_RESULT([${with_sysroot}]) + AC_MSG_ERROR([The sysroot must be an absolute path.]) + ;; +esac + + AC_MSG_RESULT([${lt_sysroot:-no}]) +_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl +[dependent libraries, and in which our libraries should be installed.])]) + +# _LT_ENABLE_LOCK +# --------------- +m4_defun([_LT_ENABLE_LOCK], +[AC_ARG_ENABLE([libtool-lock], + [AS_HELP_STRING([--disable-libtool-lock], + [avoid locking (might break parallel builds)])]) +test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes + +# Some flags need to be propagated to the compiler or linker for good +# libtool support. +case $host in +ia64-*-hpux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.$ac_objext` in + *ELF-32*) + HPUX_IA64_MODE="32" + ;; + *ELF-64*) + HPUX_IA64_MODE="64" + ;; + esac + fi + rm -rf conftest* + ;; +*-*-irix6*) + # Find out which ABI we are using. + echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + if test "$lt_cv_prog_gnu_ld" = yes; then + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -melf32bsmip" + ;; + *N32*) + LD="${LD-ld} -melf32bmipn32" + ;; + *64-bit*) + LD="${LD-ld} -melf64bmip" + ;; + esac + else + case `/usr/bin/file conftest.$ac_objext` in + *32-bit*) + LD="${LD-ld} -32" + ;; + *N32*) + LD="${LD-ld} -n32" + ;; + *64-bit*) + LD="${LD-ld} -64" + ;; + esac + fi + fi + rm -rf conftest* + ;; + +x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ +s390*-*linux*|s390*-*tpf*|sparc*-*linux*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *32-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_i386_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_i386" + ;; + ppc64-*linux*|powerpc64-*linux*) + LD="${LD-ld} -m elf32ppclinux" + ;; + s390x-*linux*) + LD="${LD-ld} -m elf_s390" + ;; + sparc64-*linux*) + LD="${LD-ld} -m elf32_sparc" + ;; + esac + ;; + *64-bit*) + case $host in + x86_64-*kfreebsd*-gnu) + LD="${LD-ld} -m elf_x86_64_fbsd" + ;; + x86_64-*linux*) + LD="${LD-ld} -m elf_x86_64" + ;; + ppc*-*linux*|powerpc*-*linux*) + LD="${LD-ld} -m elf64ppc" + ;; + s390*-*linux*|s390*-*tpf*) + LD="${LD-ld} -m elf64_s390" + ;; + sparc*-*linux*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; + +*-*-sco3.2v5*) + # On SCO OpenServer 5, we need -belf to get full-featured binaries. + SAVE_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -belf" + AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, + [AC_LANG_PUSH(C) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) + AC_LANG_POP]) + if test x"$lt_cv_cc_needs_belf" != x"yes"; then + # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf + CFLAGS="$SAVE_CFLAGS" + fi + ;; +*-*solaris*) + # Find out which ABI we are using. + echo 'int i;' > conftest.$ac_ext + if AC_TRY_EVAL(ac_compile); then + case `/usr/bin/file conftest.o` in + *64-bit*) + case $lt_cv_prog_gnu_ld in + yes*) + case $host in + i?86-*-solaris*) + LD="${LD-ld} -m elf_x86_64" + ;; + sparc*-*-solaris*) + LD="${LD-ld} -m elf64_sparc" + ;; + esac + # GNU ld 2.21 introduced _sol2 emulations. Use them if available. + if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then + LD="${LD-ld}_sol2" + fi + ;; + *) + if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then + LD="${LD-ld} -64" + fi + ;; + esac + ;; + esac + fi + rm -rf conftest* + ;; +esac + +need_locks="$enable_libtool_lock" +])# _LT_ENABLE_LOCK + + +# _LT_PROG_AR +# ----------- +m4_defun([_LT_PROG_AR], +[AC_CHECK_TOOLS(AR, [ar], false) +: ${AR=ar} +: ${AR_FLAGS=cru} +_LT_DECL([], [AR], [1], [The archiver]) +_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) + +AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], + [lt_cv_ar_at_file=no + AC_COMPILE_IFELSE([AC_LANG_PROGRAM], + [echo conftest.$ac_objext > conftest.lst + lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -eq 0; then + # Ensure the archiver fails upon bogus file names. + rm -f conftest.$ac_objext libconftest.a + AC_TRY_EVAL([lt_ar_try]) + if test "$ac_status" -ne 0; then + lt_cv_ar_at_file=@ + fi + fi + rm -f conftest.* libconftest.a + ]) + ]) + +if test "x$lt_cv_ar_at_file" = xno; then + archiver_list_spec= +else + archiver_list_spec=$lt_cv_ar_at_file +fi +_LT_DECL([], [archiver_list_spec], [1], + [How to feed a file listing to the archiver]) +])# _LT_PROG_AR + + +# _LT_CMD_OLD_ARCHIVE +# ------------------- +m4_defun([_LT_CMD_OLD_ARCHIVE], +[_LT_PROG_AR + +AC_CHECK_TOOL(STRIP, strip, :) +test -z "$STRIP" && STRIP=: +_LT_DECL([], [STRIP], [1], [A symbol stripping program]) + +AC_CHECK_TOOL(RANLIB, ranlib, :) +test -z "$RANLIB" && RANLIB=: +_LT_DECL([], [RANLIB], [1], + [Commands used to install an old-style archive]) + +# Determine commands to create old-style static archives. +old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' +old_postinstall_cmds='chmod 644 $oldlib' +old_postuninstall_cmds= + +if test -n "$RANLIB"; then + case $host_os in + openbsd*) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" + ;; + *) + old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" + ;; + esac + old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" +fi + +case $host_os in + darwin*) + lock_old_archive_extraction=yes ;; + *) + lock_old_archive_extraction=no ;; +esac +_LT_DECL([], [old_postinstall_cmds], [2]) +_LT_DECL([], [old_postuninstall_cmds], [2]) +_LT_TAGDECL([], [old_archive_cmds], [2], + [Commands used to build an old-style archive]) +_LT_DECL([], [lock_old_archive_extraction], [0], + [Whether to use a lock for old archive extraction]) +])# _LT_CMD_OLD_ARCHIVE + + +# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------------------- +# Check whether the given compiler option works +AC_DEFUN([_LT_COMPILER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + lt_compiler_flag="$3" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + # The option is referenced via a variable to avoid confusing sed. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>conftest.err) + ac_status=$? + cat conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s "$ac_outfile"; then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings other than the usual output. + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + fi + $RM conftest* +]) + +if test x"[$]$2" = xyes; then + m4_if([$5], , :, [$5]) +else + m4_if([$6], , :, [$6]) +fi +])# _LT_COMPILER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) + + +# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, +# [ACTION-SUCCESS], [ACTION-FAILURE]) +# ---------------------------------------------------- +# Check whether the given linker option works +AC_DEFUN([_LT_LINKER_OPTION], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_SED])dnl +AC_CACHE_CHECK([$1], [$2], + [$2=no + save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $3" + echo "$lt_simple_link_test_code" > conftest.$ac_ext + if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then + # The linker can only warn and ignore the option if not recognized + # So say no if there are warnings + if test -s conftest.err; then + # Append any errors to the config.log. + cat conftest.err 1>&AS_MESSAGE_LOG_FD + $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp + $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 + if diff conftest.exp conftest.er2 >/dev/null; then + $2=yes + fi + else + $2=yes + fi + fi + $RM -r conftest* + LDFLAGS="$save_LDFLAGS" +]) + +if test x"[$]$2" = xyes; then + m4_if([$4], , :, [$4]) +else + m4_if([$5], , :, [$5]) +fi +])# _LT_LINKER_OPTION + +# Old name: +AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) + + +# LT_CMD_MAX_LEN +#--------------- +AC_DEFUN([LT_CMD_MAX_LEN], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +# find the maximum length of command line arguments +AC_MSG_CHECKING([the maximum length of command line arguments]) +AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl + i=0 + teststring="ABCD" + + case $build_os in + msdosdjgpp*) + # On DJGPP, this test can blow up pretty badly due to problems in libc + # (any single argument exceeding 2000 bytes causes a buffer overrun + # during glob expansion). Even if it were fixed, the result of this + # check would be larger than it should be. + lt_cv_sys_max_cmd_len=12288; # 12K is about right + ;; + + gnu*) + # Under GNU Hurd, this test is not required because there is + # no limit to the length of command line arguments. + # Libtool will interpret -1 as no limit whatsoever + lt_cv_sys_max_cmd_len=-1; + ;; + + cygwin* | mingw* | cegcc*) + # On Win9x/ME, this test blows up -- it succeeds, but takes + # about 5 minutes as the teststring grows exponentially. + # Worse, since 9x/ME are not pre-emptively multitasking, + # you end up with a "frozen" computer, even though with patience + # the test eventually succeeds (with a max line length of 256k). + # Instead, let's just punt: use the minimum linelength reported by + # all of the supported platforms: 8192 (on NT/2K/XP). + lt_cv_sys_max_cmd_len=8192; + ;; + + mint*) + # On MiNT this can take a long time and run out of memory. + lt_cv_sys_max_cmd_len=8192; + ;; + + amigaos*) + # On AmigaOS with pdksh, this test takes hours, literally. + # So we just punt and use a minimum line length of 8192. + lt_cv_sys_max_cmd_len=8192; + ;; + + netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) + # This has been around since 386BSD, at least. Likely further. + if test -x /sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` + elif test -x /usr/sbin/sysctl; then + lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` + else + lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs + fi + # And add a safety zone + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + ;; + + interix*) + # We know the value 262144 and hardcode it with a safety zone (like BSD) + lt_cv_sys_max_cmd_len=196608 + ;; + + os2*) + # The test takes a long time on OS/2. + lt_cv_sys_max_cmd_len=8192 + ;; + + osf*) + # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure + # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not + # nice to cause kernel panics so lets avoid the loop below. + # First set a reasonable default. + lt_cv_sys_max_cmd_len=16384 + # + if test -x /sbin/sysconfig; then + case `/sbin/sysconfig -q proc exec_disable_arg_limit` in + *1*) lt_cv_sys_max_cmd_len=-1 ;; + esac + fi + ;; + sco3.2v5*) + lt_cv_sys_max_cmd_len=102400 + ;; + sysv5* | sco5v6* | sysv4.2uw2*) + kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` + if test -n "$kargmax"; then + lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` + else + lt_cv_sys_max_cmd_len=32768 + fi + ;; + *) + lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` + if test -n "$lt_cv_sys_max_cmd_len"; then + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` + else + # Make teststring a little bigger before we do anything with it. + # a 1K string should be a reasonable start. + for i in 1 2 3 4 5 6 7 8 ; do + teststring=$teststring$teststring + done + SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} + # If test is not a shell built-in, we'll probably end up computing a + # maximum length that is only half of the actual maximum length, but + # we can't tell. + while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ + = "X$teststring$teststring"; } >/dev/null 2>&1 && + test $i != 17 # 1/2 MB should be enough + do + i=`expr $i + 1` + teststring=$teststring$teststring + done + # Only check the string length outside the loop. + lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` + teststring= + # Add a significant safety factor because C++ compilers can tack on + # massive amounts of additional arguments before passing them to the + # linker. It appears as though 1/2 is a usable value. + lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` + fi + ;; + esac +]) +if test -n $lt_cv_sys_max_cmd_len ; then + AC_MSG_RESULT($lt_cv_sys_max_cmd_len) +else + AC_MSG_RESULT(none) +fi +max_cmd_len=$lt_cv_sys_max_cmd_len +_LT_DECL([], [max_cmd_len], [0], + [What is the maximum length of a command?]) +])# LT_CMD_MAX_LEN + +# Old name: +AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) + + +# _LT_HEADER_DLFCN +# ---------------- +m4_defun([_LT_HEADER_DLFCN], +[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl +])# _LT_HEADER_DLFCN + + +# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, +# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) +# ---------------------------------------------------------------- +m4_defun([_LT_TRY_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "$cross_compiling" = yes; then : + [$4] +else + lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 + lt_status=$lt_dlunknown + cat > conftest.$ac_ext <<_LT_EOF +[#line $LINENO "configure" +#include "confdefs.h" + +#if HAVE_DLFCN_H +#include +#endif + +#include + +#ifdef RTLD_GLOBAL +# define LT_DLGLOBAL RTLD_GLOBAL +#else +# ifdef DL_GLOBAL +# define LT_DLGLOBAL DL_GLOBAL +# else +# define LT_DLGLOBAL 0 +# endif +#endif + +/* We may have to define LT_DLLAZY_OR_NOW in the command line if we + find out it does not work in some platform. */ +#ifndef LT_DLLAZY_OR_NOW +# ifdef RTLD_LAZY +# define LT_DLLAZY_OR_NOW RTLD_LAZY +# else +# ifdef DL_LAZY +# define LT_DLLAZY_OR_NOW DL_LAZY +# else +# ifdef RTLD_NOW +# define LT_DLLAZY_OR_NOW RTLD_NOW +# else +# ifdef DL_NOW +# define LT_DLLAZY_OR_NOW DL_NOW +# else +# define LT_DLLAZY_OR_NOW 0 +# endif +# endif +# endif +# endif +#endif + +/* When -fvisbility=hidden is used, assume the code has been annotated + correspondingly for the symbols needed. */ +#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) +int fnord () __attribute__((visibility("default"))); +#endif + +int fnord () { return 42; } +int main () +{ + void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); + int status = $lt_dlunknown; + + if (self) + { + if (dlsym (self,"fnord")) status = $lt_dlno_uscore; + else + { + if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; + else puts (dlerror ()); + } + /* dlclose (self); */ + } + else + puts (dlerror ()); + + return status; +}] +_LT_EOF + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then + (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null + lt_status=$? + case x$lt_status in + x$lt_dlno_uscore) $1 ;; + x$lt_dlneed_uscore) $2 ;; + x$lt_dlunknown|x*) $3 ;; + esac + else : + # compilation failed + $3 + fi +fi +rm -fr conftest* +])# _LT_TRY_DLOPEN_SELF + + +# LT_SYS_DLOPEN_SELF +# ------------------ +AC_DEFUN([LT_SYS_DLOPEN_SELF], +[m4_require([_LT_HEADER_DLFCN])dnl +if test "x$enable_dlopen" != xyes; then + enable_dlopen=unknown + enable_dlopen_self=unknown + enable_dlopen_self_static=unknown +else + lt_cv_dlopen=no + lt_cv_dlopen_libs= + + case $host_os in + beos*) + lt_cv_dlopen="load_add_on" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ;; + + mingw* | pw32* | cegcc*) + lt_cv_dlopen="LoadLibrary" + lt_cv_dlopen_libs= + ;; + + cygwin*) + lt_cv_dlopen="dlopen" + lt_cv_dlopen_libs= + ;; + + darwin*) + # if libdl is installed we need to link against it + AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ + lt_cv_dlopen="dyld" + lt_cv_dlopen_libs= + lt_cv_dlopen_self=yes + ]) + ;; + + *) + AC_CHECK_FUNC([shl_load], + [lt_cv_dlopen="shl_load"], + [AC_CHECK_LIB([dld], [shl_load], + [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], + [AC_CHECK_FUNC([dlopen], + [lt_cv_dlopen="dlopen"], + [AC_CHECK_LIB([dl], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], + [AC_CHECK_LIB([svld], [dlopen], + [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], + [AC_CHECK_LIB([dld], [dld_link], + [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) + ]) + ]) + ]) + ]) + ]) + ;; + esac + + if test "x$lt_cv_dlopen" != xno; then + enable_dlopen=yes + else + enable_dlopen=no + fi + + case $lt_cv_dlopen in + dlopen) + save_CPPFLAGS="$CPPFLAGS" + test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" + + save_LDFLAGS="$LDFLAGS" + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" + + save_LIBS="$LIBS" + LIBS="$lt_cv_dlopen_libs $LIBS" + + AC_CACHE_CHECK([whether a program can dlopen itself], + lt_cv_dlopen_self, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, + lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) + ]) + + if test "x$lt_cv_dlopen_self" = xyes; then + wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" + AC_CACHE_CHECK([whether a statically linked program can dlopen itself], + lt_cv_dlopen_self_static, [dnl + _LT_TRY_DLOPEN_SELF( + lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, + lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) + ]) + fi + + CPPFLAGS="$save_CPPFLAGS" + LDFLAGS="$save_LDFLAGS" + LIBS="$save_LIBS" + ;; + esac + + case $lt_cv_dlopen_self in + yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; + *) enable_dlopen_self=unknown ;; + esac + + case $lt_cv_dlopen_self_static in + yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; + *) enable_dlopen_self_static=unknown ;; + esac +fi +_LT_DECL([dlopen_support], [enable_dlopen], [0], + [Whether dlopen is supported]) +_LT_DECL([dlopen_self], [enable_dlopen_self], [0], + [Whether dlopen of programs is supported]) +_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], + [Whether dlopen of statically linked programs is supported]) +])# LT_SYS_DLOPEN_SELF + +# Old name: +AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) + + +# _LT_COMPILER_C_O([TAGNAME]) +# --------------------------- +# Check to see if options -c and -o are simultaneously supported by compiler. +# This macro does not hard code the compiler like AC_PROG_CC_C_O. +m4_defun([_LT_COMPILER_C_O], +[m4_require([_LT_DECL_SED])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no + $RM -r conftest 2>/dev/null + mkdir conftest + cd conftest + mkdir out + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + lt_compiler_flag="-o out/conftest2.$ac_objext" + # Insert the option either (1) after the last *FLAGS variable, or + # (2) before a word containing "conftest.", or (3) at the end. + # Note that $ac_compile itself does not contain backslashes and begins + # with a dollar sign (not a hyphen), so the echo should work correctly. + lt_compile=`echo "$ac_compile" | $SED \ + -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ + -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ + -e 's:$: $lt_compiler_flag:'` + (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$lt_compile" 2>out/conftest.err) + ac_status=$? + cat out/conftest.err >&AS_MESSAGE_LOG_FD + echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD + if (exit $ac_status) && test -s out/conftest2.$ac_objext + then + # The compiler can only warn and ignore the option if not recognized + # So say no if there are warnings + $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp + $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 + if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then + _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + fi + fi + chmod u+w . 2>&AS_MESSAGE_LOG_FD + $RM conftest* + # SGI C++ compiler will create directory out/ii_files/ for + # template instantiation + test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files + $RM out/* && rmdir out + cd .. + $RM -r conftest + $RM conftest* +]) +_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], + [Does compiler simultaneously support -c and -o options?]) +])# _LT_COMPILER_C_O + + +# _LT_COMPILER_FILE_LOCKS([TAGNAME]) +# ---------------------------------- +# Check to see if we can do hard links to lock some files if needed +m4_defun([_LT_COMPILER_FILE_LOCKS], +[m4_require([_LT_ENABLE_LOCK])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +_LT_COMPILER_C_O([$1]) + +hard_links="nottested" +if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then + # do not overwrite the value of need_locks provided by the user + AC_MSG_CHECKING([if we can lock with hard links]) + hard_links=yes + $RM conftest* + ln conftest.a conftest.b 2>/dev/null && hard_links=no + touch conftest.a + ln conftest.a conftest.b 2>&5 || hard_links=no + ln conftest.a conftest.b 2>/dev/null && hard_links=no + AC_MSG_RESULT([$hard_links]) + if test "$hard_links" = no; then + AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) + need_locks=warn + fi +else + need_locks=no +fi +_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) +])# _LT_COMPILER_FILE_LOCKS + + +# _LT_CHECK_OBJDIR +# ---------------- +m4_defun([_LT_CHECK_OBJDIR], +[AC_CACHE_CHECK([for objdir], [lt_cv_objdir], +[rm -f .libs 2>/dev/null +mkdir .libs 2>/dev/null +if test -d .libs; then + lt_cv_objdir=.libs +else + # MS-DOS does not allow filenames that begin with a dot. + lt_cv_objdir=_libs +fi +rmdir .libs 2>/dev/null]) +objdir=$lt_cv_objdir +_LT_DECL([], [objdir], [0], + [The name of the directory that contains temporary libtool files])dnl +m4_pattern_allow([LT_OBJDIR])dnl +AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", + [Define to the sub-directory in which libtool stores uninstalled libraries.]) +])# _LT_CHECK_OBJDIR + + +# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) +# -------------------------------------- +# Check hardcoding attributes. +m4_defun([_LT_LINKER_HARDCODE_LIBPATH], +[AC_MSG_CHECKING([how to hardcode library paths into programs]) +_LT_TAGVAR(hardcode_action, $1)= +if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || + test -n "$_LT_TAGVAR(runpath_var, $1)" || + test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then + + # We can hardcode non-existent directories. + if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && + # If the only mechanism to avoid hardcoding is shlibpath_var, we + # have to relink, otherwise we might link with an installed library + # when we should be linking with a yet-to-be-installed one + ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && + test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then + # Linking always hardcodes the temporary library directory. + _LT_TAGVAR(hardcode_action, $1)=relink + else + # We can link without hardcoding, and we can hardcode nonexisting dirs. + _LT_TAGVAR(hardcode_action, $1)=immediate + fi +else + # We cannot hardcode anything, or else we can only hardcode existing + # directories. + _LT_TAGVAR(hardcode_action, $1)=unsupported +fi +AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) + +if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || + test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then + # Fast installation is not supported + enable_fast_install=no +elif test "$shlibpath_overrides_runpath" = yes || + test "$enable_shared" = no; then + # Fast installation is not necessary + enable_fast_install=needless +fi +_LT_TAGDECL([], [hardcode_action], [0], + [How to hardcode a shared library path into an executable]) +])# _LT_LINKER_HARDCODE_LIBPATH + + +# _LT_CMD_STRIPLIB +# ---------------- +m4_defun([_LT_CMD_STRIPLIB], +[m4_require([_LT_DECL_EGREP]) +striplib= +old_striplib= +AC_MSG_CHECKING([whether stripping libraries is possible]) +if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then + test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" + test -z "$striplib" && striplib="$STRIP --strip-unneeded" + AC_MSG_RESULT([yes]) +else +# FIXME - insert some real tests, host_os isn't really good enough + case $host_os in + darwin*) + if test -n "$STRIP" ; then + striplib="$STRIP -x" + old_striplib="$STRIP -S" + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + fi + ;; + *) + AC_MSG_RESULT([no]) + ;; + esac +fi +_LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) +_LT_DECL([], [striplib], [1]) +])# _LT_CMD_STRIPLIB + + +# _LT_SYS_DYNAMIC_LINKER([TAG]) +# ----------------------------- +# PORTME Fill in your ld.so characteristics +m4_defun([_LT_SYS_DYNAMIC_LINKER], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_OBJDUMP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CHECK_SHELL_FEATURES])dnl +AC_MSG_CHECKING([dynamic linker characteristics]) +m4_if([$1], + [], [ +if test "$GCC" = yes; then + case $host_os in + darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; + *) lt_awk_arg="/^libraries:/" ;; + esac + case $host_os in + mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; + *) lt_sed_strip_eq="s,=/,/,g" ;; + esac + lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` + case $lt_search_path_spec in + *\;*) + # if the path contains ";" then we assume it to be the separator + # otherwise default to the standard path separator (i.e. ":") - it is + # assumed that no part of a normal pathname contains ";" but that should + # okay in the real world where ";" in dirpaths is itself problematic. + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` + ;; + *) + lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` + ;; + esac + # Ok, now we have the path, separated by spaces, we can step through it + # and add multilib dir if necessary. + lt_tmp_lt_search_path_spec= + lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` + for lt_sys_path in $lt_search_path_spec; do + if test -d "$lt_sys_path/$lt_multi_os_dir"; then + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" + else + test -d "$lt_sys_path" && \ + lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" + fi + done + lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' +BEGIN {RS=" "; FS="/|\n";} { + lt_foo=""; + lt_count=0; + for (lt_i = NF; lt_i > 0; lt_i--) { + if ($lt_i != "" && $lt_i != ".") { + if ($lt_i == "..") { + lt_count++; + } else { + if (lt_count == 0) { + lt_foo="/" $lt_i lt_foo; + } else { + lt_count--; + } + } + } + } + if (lt_foo != "") { lt_freq[[lt_foo]]++; } + if (lt_freq[[lt_foo]] == 1) { print lt_foo; } +}'` + # AWK program above erroneously prepends '/' to C:/dos/paths + # for these hosts. + case $host_os in + mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ + $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; + esac + sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` +else + sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" +fi]) +library_names_spec= +libname_spec='lib$name' +soname_spec= +shrext_cmds=".so" +postinstall_cmds= +postuninstall_cmds= +finish_cmds= +finish_eval= +shlibpath_var= +shlibpath_overrides_runpath=unknown +version_type=none +dynamic_linker="$host_os ld.so" +sys_lib_dlsearch_path_spec="/lib /usr/lib" +need_lib_prefix=unknown +hardcode_into_libs=no + +# when you set need_version to no, make sure it does not cause -set_version +# flags to be left without arguments +need_version=unknown + +case $host_os in +aix3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' + shlibpath_var=LIBPATH + + # AIX 3 has no versioning support, so we append a major version to the name. + soname_spec='${libname}${release}${shared_ext}$major' + ;; + +aix[[4-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + hardcode_into_libs=yes + if test "$host_cpu" = ia64; then + # AIX 5 supports IA64 + library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + else + # With GCC up to 2.95.x, collect2 would create an import file + # for dependence libraries. The import file would start with + # the line `#! .'. This would cause the generated library to + # depend on `.', always an invalid library. This was fixed in + # development snapshots of GCC prior to 3.0. + case $host_os in + aix4 | aix4.[[01]] | aix4.[[01]].*) + if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' + echo ' yes ' + echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then + : + else + can_build_shared=no + fi + ;; + esac + # AIX (on Power*) has no versioning support, so currently we can not hardcode correct + # soname into executable. Probably we can add versioning support to + # collect2, so additional links can be useful in future. + if test "$aix_use_runtimelinking" = yes; then + # If using run time linking (on AIX 4.2 or later) use lib.so + # instead of lib.a to let people know that these are not + # typical AIX shared libraries. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + else + # We preserve .a as extension for shared libraries through AIX4.2 + # and later when we are not doing run time linking. + library_names_spec='${libname}${release}.a $libname.a' + soname_spec='${libname}${release}${shared_ext}$major' + fi + shlibpath_var=LIBPATH + fi + ;; + +amigaos*) + case $host_cpu in + powerpc) + # Since July 2007 AmigaOS4 officially supports .so libraries. + # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + ;; + m68k) + library_names_spec='$libname.ixlibrary $libname.a' + # Create ${libname}_ixlibrary.a entries in /sys/libs. + finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' + ;; + esac + ;; + +beos*) + library_names_spec='${libname}${shared_ext}' + dynamic_linker="$host_os ld.so" + shlibpath_var=LIBRARY_PATH + ;; + +bsdi[[45]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" + sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" + # the default ld.so.conf also contains /usr/contrib/lib and + # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow + # libtool to hard-code these into programs + ;; + +cygwin* | mingw* | pw32* | cegcc*) + version_type=windows + shrext_cmds=".dll" + need_version=no + need_lib_prefix=no + + case $GCC,$cc_basename in + yes,*) + # gcc + library_names_spec='$libname.dll.a' + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname~ + chmod a+x \$dldir/$dlname~ + if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then + eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; + fi' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + + case $host_os in + cygwin*) + # Cygwin DLLs use 'cyg' prefix rather than 'lib' + soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) + ;; + mingw* | cegcc*) + # MinGW DLLs use traditional 'lib' prefix + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + pw32*) + # pw32 DLLs use 'pw' prefix rather than 'lib' + library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + ;; + esac + dynamic_linker='Win32 ld.exe' + ;; + + *,cl*) + # Native MSVC + libname_spec='$name' + soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' + library_names_spec='${libname}.dll.lib' + + case $build_os in + mingw*) + sys_lib_search_path_spec= + lt_save_ifs=$IFS + IFS=';' + for lt_path in $LIB + do + IFS=$lt_save_ifs + # Let DOS variable expansion print the short 8.3 style file name. + lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` + sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" + done + IFS=$lt_save_ifs + # Convert to MSYS style. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` + ;; + cygwin*) + # Convert to unix form, then to dos form, then back to unix form + # but this time dos style (no spaces!) so that the unix form looks + # like /cygdrive/c/PROGRA~1:/cygdr... + sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` + sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` + sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + ;; + *) + sys_lib_search_path_spec="$LIB" + if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then + # It is most probably a Windows format PATH. + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` + else + sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` + fi + # FIXME: find the short name or the path components, as spaces are + # common. (e.g. "Program Files" -> "PROGRA~1") + ;; + esac + + # DLL is installed to $(libdir)/../bin by postinstall_cmds + postinstall_cmds='base_file=`basename \${file}`~ + dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ + dldir=$destdir/`dirname \$dlpath`~ + test -d \$dldir || mkdir -p \$dldir~ + $install_prog $dir/$dlname \$dldir/$dlname' + postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ + dlpath=$dir/\$dldll~ + $RM \$dlpath' + shlibpath_overrides_runpath=yes + dynamic_linker='Win32 link.exe' + ;; + + *) + # Assume MSVC wrapper + library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' + dynamic_linker='Win32 ld.exe' + ;; + esac + # FIXME: first we should search . and the directory the executable is in + shlibpath_var=PATH + ;; + +darwin* | rhapsody*) + dynamic_linker="$host_os dyld" + version_type=darwin + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' + soname_spec='${libname}${release}${major}$shared_ext' + shlibpath_overrides_runpath=yes + shlibpath_var=DYLD_LIBRARY_PATH + shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' +m4_if([$1], [],[ + sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) + sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' + ;; + +dgux*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +freebsd* | dragonfly*) + # DragonFly does not have aout. When/if they implement a new + # versioning mechanism, adjust this. + if test -x /usr/bin/objformat; then + objformat=`/usr/bin/objformat` + else + case $host_os in + freebsd[[23]].*) objformat=aout ;; + *) objformat=elf ;; + esac + fi + version_type=freebsd-$objformat + case $version_type in + freebsd-elf*) + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + need_version=no + need_lib_prefix=no + ;; + freebsd-*) + library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' + need_version=yes + ;; + esac + shlibpath_var=LD_LIBRARY_PATH + case $host_os in + freebsd2.*) + shlibpath_overrides_runpath=yes + ;; + freebsd3.[[01]]* | freebsdelf3.[[01]]*) + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ + freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + *) # from 4.6 on, and DragonFly + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + esac + ;; + +gnu*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +haiku*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + dynamic_linker="$host_os runtime_loader" + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LIBRARY_PATH + shlibpath_overrides_runpath=yes + sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' + hardcode_into_libs=yes + ;; + +hpux9* | hpux10* | hpux11*) + # Give a soname corresponding to the major version so that dld.sl refuses to + # link against other versions. + version_type=sunos + need_lib_prefix=no + need_version=no + case $host_cpu in + ia64*) + shrext_cmds='.so' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.so" + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + if test "X$HPUX_IA64_MODE" = X32; then + sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" + else + sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" + fi + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + hppa*64*) + shrext_cmds='.sl' + hardcode_into_libs=yes + dynamic_linker="$host_os dld.sl" + shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH + shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" + sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec + ;; + *) + shrext_cmds='.sl' + dynamic_linker="$host_os dld.sl" + shlibpath_var=SHLIB_PATH + shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + ;; + esac + # HP-UX runs *really* slowly unless shared libraries are mode 555, ... + postinstall_cmds='chmod 555 $lib' + # or fails outright, so override atomically: + install_override_mode=555 + ;; + +interix[[3-9]]*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +irix5* | irix6* | nonstopux*) + case $host_os in + nonstopux*) version_type=nonstopux ;; + *) + if test "$lt_cv_prog_gnu_ld" = yes; then + version_type=linux # correct to gnu/linux during the next big refactor + else + version_type=irix + fi ;; + esac + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' + case $host_os in + irix5* | nonstopux*) + libsuff= shlibsuff= + ;; + *) + case $LD in # libtool.m4 will add one of these switches to LD + *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") + libsuff= shlibsuff= libmagic=32-bit;; + *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") + libsuff=32 shlibsuff=N32 libmagic=N32;; + *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") + libsuff=64 shlibsuff=64 libmagic=64-bit;; + *) libsuff= shlibsuff= libmagic=never-match;; + esac + ;; + esac + shlibpath_var=LD_LIBRARY${shlibsuff}_PATH + shlibpath_overrides_runpath=no + sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" + sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" + hardcode_into_libs=yes + ;; + +# No shared lib support for Linux oldld, aout, or coff. +linux*oldld* | linux*aout* | linux*coff*) + dynamic_linker=no + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + + # Some binutils ld are patched to set DT_RUNPATH + AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], + [lt_cv_shlibpath_overrides_runpath=no + save_LDFLAGS=$LDFLAGS + save_libdir=$libdir + eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ + LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" + AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], + [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], + [lt_cv_shlibpath_overrides_runpath=yes])]) + LDFLAGS=$save_LDFLAGS + libdir=$save_libdir + ]) + shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath + + # This implies no fast_install, which is unacceptable. + # Some rework will be needed to allow for fast_install + # before this can be enabled. + hardcode_into_libs=yes + + # Add ABI-specific directories to the system library path. + sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /lib /usr/lib" + + # Append ld.so.conf contents to the search path + if test -f /etc/ld.so.conf; then + lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` + sys_lib_dlsearch_path_spec="$sys_lib_dlsearch_path_spec $lt_ld_extra" + + fi + + # We used to test for /lib/ld.so.1 and disable shared libraries on + # powerpc, because MkLinux only supported shared libraries with the + # GNU dynamic linker. Since this was broken with cross compilers, + # most powerpc-linux boxes support dynamic linking these days and + # people can always --disable-shared, the test was removed, and we + # assume the GNU/Linux dynamic linker is in use. + dynamic_linker='GNU/Linux ld.so' + ;; + +netbsd*) + version_type=sunos + need_lib_prefix=no + need_version=no + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + dynamic_linker='NetBSD (a.out) ld.so' + else + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + dynamic_linker='NetBSD ld.elf_so' + fi + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + ;; + +newsos6) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + ;; + +*nto* | *qnx*) + version_type=qnx + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + dynamic_linker='ldqnx.so' + ;; + +openbsd*) + version_type=sunos + sys_lib_dlsearch_path_spec="/usr/lib" + need_lib_prefix=no + # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. + case $host_os in + openbsd3.3 | openbsd3.3.*) need_version=yes ;; + *) need_version=no ;; + esac + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' + shlibpath_var=LD_LIBRARY_PATH + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + case $host_os in + openbsd2.[[89]] | openbsd2.[[89]].*) + shlibpath_overrides_runpath=no + ;; + *) + shlibpath_overrides_runpath=yes + ;; + esac + else + shlibpath_overrides_runpath=yes + fi + ;; + +os2*) + libname_spec='$name' + shrext_cmds=".dll" + need_lib_prefix=no + library_names_spec='$libname${shared_ext} $libname.a' + dynamic_linker='OS/2 ld.exe' + shlibpath_var=LIBPATH + ;; + +osf3* | osf4* | osf5*) + version_type=osf + need_lib_prefix=no + need_version=no + soname_spec='${libname}${release}${shared_ext}$major' + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" + sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" + ;; + +rdos*) + dynamic_linker=no + ;; + +solaris*) + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + # ldd complains unless libraries are executable + postinstall_cmds='chmod +x $lib' + ;; + +sunos4*) + version_type=sunos + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' + finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + if test "$with_gnu_ld" = yes; then + need_lib_prefix=no + fi + need_version=yes + ;; + +sysv4 | sysv4.3*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + case $host_vendor in + sni) + shlibpath_overrides_runpath=no + need_lib_prefix=no + runpath_var=LD_RUN_PATH + ;; + siemens) + need_lib_prefix=no + ;; + motorola) + need_lib_prefix=no + need_version=no + shlibpath_overrides_runpath=no + sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' + ;; + esac + ;; + +sysv4*MP*) + if test -d /usr/nec ;then + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' + soname_spec='$libname${shared_ext}.$major' + shlibpath_var=LD_LIBRARY_PATH + fi + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + version_type=freebsd-elf + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=yes + hardcode_into_libs=yes + if test "$with_gnu_ld" = yes; then + sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' + else + sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' + case $host_os in + sco3.2v5*) + sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" + ;; + esac + fi + sys_lib_dlsearch_path_spec='/usr/lib' + ;; + +tpf*) + # TPF is a cross-target only. Preferred cross-host = GNU/Linux. + version_type=linux # correct to gnu/linux during the next big refactor + need_lib_prefix=no + need_version=no + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + shlibpath_var=LD_LIBRARY_PATH + shlibpath_overrides_runpath=no + hardcode_into_libs=yes + ;; + +uts4*) + version_type=linux # correct to gnu/linux during the next big refactor + library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' + soname_spec='${libname}${release}${shared_ext}$major' + shlibpath_var=LD_LIBRARY_PATH + ;; + +*) + dynamic_linker=no + ;; +esac +AC_MSG_RESULT([$dynamic_linker]) +test "$dynamic_linker" = no && can_build_shared=no + +variables_saved_for_relink="PATH $shlibpath_var $runpath_var" +if test "$GCC" = yes; then + variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" +fi + +if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then + sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" +fi +if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then + sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" +fi + +_LT_DECL([], [variables_saved_for_relink], [1], + [Variables whose values should be saved in libtool wrapper scripts and + restored at link time]) +_LT_DECL([], [need_lib_prefix], [0], + [Do we need the "lib" prefix for modules?]) +_LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) +_LT_DECL([], [version_type], [0], [Library versioning type]) +_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) +_LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) +_LT_DECL([], [shlibpath_overrides_runpath], [0], + [Is shlibpath searched before the hard-coded library search path?]) +_LT_DECL([], [libname_spec], [1], [Format of library name prefix]) +_LT_DECL([], [library_names_spec], [1], + [[List of archive names. First name is the real one, the rest are links. + The last name is the one that the linker finds with -lNAME]]) +_LT_DECL([], [soname_spec], [1], + [[The coded name of the library, if different from the real name]]) +_LT_DECL([], [install_override_mode], [1], + [Permission mode override for installation of shared libraries]) +_LT_DECL([], [postinstall_cmds], [2], + [Command to use after installation of a shared archive]) +_LT_DECL([], [postuninstall_cmds], [2], + [Command to use after uninstallation of a shared archive]) +_LT_DECL([], [finish_cmds], [2], + [Commands used to finish a libtool library installation in a directory]) +_LT_DECL([], [finish_eval], [1], + [[As "finish_cmds", except a single script fragment to be evaled but + not shown]]) +_LT_DECL([], [hardcode_into_libs], [0], + [Whether we should hardcode library paths into libraries]) +_LT_DECL([], [sys_lib_search_path_spec], [2], + [Compile-time system search path for libraries]) +_LT_DECL([], [sys_lib_dlsearch_path_spec], [2], + [Run-time system search path for libraries]) +])# _LT_SYS_DYNAMIC_LINKER + + +# _LT_PATH_TOOL_PREFIX(TOOL) +# -------------------------- +# find a file program which can recognize shared library +AC_DEFUN([_LT_PATH_TOOL_PREFIX], +[m4_require([_LT_DECL_EGREP])dnl +AC_MSG_CHECKING([for $1]) +AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, +[case $MAGIC_CMD in +[[\\/*] | ?:[\\/]*]) + lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. + ;; +*) + lt_save_MAGIC_CMD="$MAGIC_CMD" + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR +dnl $ac_dummy forces splitting on constant user-supplied paths. +dnl POSIX.2 word splitting is done only on the output of word expansions, +dnl not every word. This closes a longstanding sh security hole. + ac_dummy="m4_if([$2], , $PATH, [$2])" + for ac_dir in $ac_dummy; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f $ac_dir/$1; then + lt_cv_path_MAGIC_CMD="$ac_dir/$1" + if test -n "$file_magic_test_file"; then + case $deplibs_check_method in + "file_magic "*) + file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` + MAGIC_CMD="$lt_cv_path_MAGIC_CMD" + if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | + $EGREP "$file_magic_regex" > /dev/null; then + : + else + cat <<_LT_EOF 1>&2 + +*** Warning: the command libtool uses to detect shared libraries, +*** $file_magic_cmd, produces output that libtool cannot recognize. +*** The result is that libtool may fail to recognize shared libraries +*** as such. This will affect the creation of libtool libraries that +*** depend on shared libraries, but programs linked with such libtool +*** libraries will work regardless of this problem. Nevertheless, you +*** may want to report the problem to your system manager and/or to +*** bug-libtool@gnu.org + +_LT_EOF + fi ;; + esac + fi + break + fi + done + IFS="$lt_save_ifs" + MAGIC_CMD="$lt_save_MAGIC_CMD" + ;; +esac]) +MAGIC_CMD="$lt_cv_path_MAGIC_CMD" +if test -n "$MAGIC_CMD"; then + AC_MSG_RESULT($MAGIC_CMD) +else + AC_MSG_RESULT(no) +fi +_LT_DECL([], [MAGIC_CMD], [0], + [Used to examine libraries when file_magic_cmd begins with "file"])dnl +])# _LT_PATH_TOOL_PREFIX + +# Old name: +AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) + + +# _LT_PATH_MAGIC +# -------------- +# find a file program which can recognize a shared library +m4_defun([_LT_PATH_MAGIC], +[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) +if test -z "$lt_cv_path_MAGIC_CMD"; then + if test -n "$ac_tool_prefix"; then + _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) + else + MAGIC_CMD=: + fi +fi +])# _LT_PATH_MAGIC + + +# LT_PATH_LD +# ---------- +# find the pathname to the GNU or non-GNU linker +AC_DEFUN([LT_PATH_LD], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PROG_ECHO_BACKSLASH])dnl + +AC_ARG_WITH([gnu-ld], + [AS_HELP_STRING([--with-gnu-ld], + [assume the C compiler uses GNU ld @<:@default=no@:>@])], + [test "$withval" = no || with_gnu_ld=yes], + [with_gnu_ld=no])dnl + +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by $CC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]]* | ?:[[\\/]]*) + re_direlt='/[[^/]][[^/]]*/\.\./' + # Canonicalize the pathname of ld + ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` + while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do + ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(lt_cv_path_LD, +[if test -z "$LD"; then + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + lt_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some variants of GNU ld only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then + lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' + lt_cv_file_magic_cmd='func_win32_libid' + else + # Keep this pattern in sync with the one in func_win32_libid. + lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' + lt_cv_file_magic_cmd='$OBJDUMP -f' + fi + ;; + +cegcc*) + # use the weaker test based on 'objdump'. See mingw*. + lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' + lt_cv_file_magic_cmd='$OBJDUMP -f' + ;; + +darwin* | rhapsody*) + lt_cv_deplibs_check_method=pass_all + ;; + +freebsd* | dragonfly*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + case $host_cpu in + i*86 ) + # Not sure whether the presence of OpenBSD here was a mistake. + # Let's accept both of them until this is cleared up. + lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` + ;; + esac + else + lt_cv_deplibs_check_method=pass_all + fi + ;; + +gnu*) + lt_cv_deplibs_check_method=pass_all + ;; + +haiku*) + lt_cv_deplibs_check_method=pass_all + ;; + +hpux10.20* | hpux11*) + lt_cv_file_magic_cmd=/usr/bin/file + case $host_cpu in + ia64*) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' + lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so + ;; + hppa*64*) + [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] + lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl + ;; + *) + lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' + lt_cv_file_magic_test_file=/usr/lib/libc.sl + ;; + esac + ;; + +interix[[3-9]]*) + # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' + ;; + +irix5* | irix6* | nonstopux*) + case $LD in + *-32|*"-32 ") libmagic=32-bit;; + *-n32|*"-n32 ") libmagic=N32;; + *-64|*"-64 ") libmagic=64-bit;; + *) libmagic=never-match;; + esac + lt_cv_deplibs_check_method=pass_all + ;; + +# This must be glibc/ELF. +linux* | k*bsd*-gnu | kopensolaris*-gnu) + lt_cv_deplibs_check_method=pass_all + ;; + +netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' + fi + ;; + +newos6*) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' + lt_cv_file_magic_cmd=/usr/bin/file + lt_cv_file_magic_test_file=/usr/lib/libnls.so + ;; + +*nto* | *qnx*) + lt_cv_deplibs_check_method=pass_all + ;; + +openbsd*) + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' + else + lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' + fi + ;; + +osf3* | osf4* | osf5*) + lt_cv_deplibs_check_method=pass_all + ;; + +rdos*) + lt_cv_deplibs_check_method=pass_all + ;; + +solaris*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) + lt_cv_deplibs_check_method=pass_all + ;; + +sysv4 | sysv4.3*) + case $host_vendor in + motorola) + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' + lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` + ;; + ncr) + lt_cv_deplibs_check_method=pass_all + ;; + sequent) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' + ;; + sni) + lt_cv_file_magic_cmd='/bin/file' + lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" + lt_cv_file_magic_test_file=/lib/libc.so + ;; + siemens) + lt_cv_deplibs_check_method=pass_all + ;; + pc) + lt_cv_deplibs_check_method=pass_all + ;; + esac + ;; + +tpf*) + lt_cv_deplibs_check_method=pass_all + ;; +esac +]) + +file_magic_glob= +want_nocaseglob=no +if test "$build" = "$host"; then + case $host_os in + mingw* | pw32*) + if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then + want_nocaseglob=yes + else + file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` + fi + ;; + esac +fi + +file_magic_cmd=$lt_cv_file_magic_cmd +deplibs_check_method=$lt_cv_deplibs_check_method +test -z "$deplibs_check_method" && deplibs_check_method=unknown + +_LT_DECL([], [deplibs_check_method], [1], + [Method to check whether dependent libraries are shared objects]) +_LT_DECL([], [file_magic_cmd], [1], + [Command to use when deplibs_check_method = "file_magic"]) +_LT_DECL([], [file_magic_glob], [1], + [How to find potential files when deplibs_check_method = "file_magic"]) +_LT_DECL([], [want_nocaseglob], [1], + [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) +])# _LT_CHECK_MAGIC_METHOD + + +# LT_PATH_NM +# ---------- +# find the pathname to a BSD- or MS-compatible name lister +AC_DEFUN([LT_PATH_NM], +[AC_REQUIRE([AC_PROG_CC])dnl +AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, +[if test -n "$NM"; then + # Let the user override the test. + lt_cv_path_NM="$NM" +else + lt_nm_to_check="${ac_tool_prefix}nm" + if test -n "$ac_tool_prefix" && test "$build" = "$host"; then + lt_nm_to_check="$lt_nm_to_check nm" + fi + for lt_tmp_nm in $lt_nm_to_check; do + lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do + IFS="$lt_save_ifs" + test -z "$ac_dir" && ac_dir=. + tmp_nm="$ac_dir/$lt_tmp_nm" + if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then + # Check to see if the nm accepts a BSD-compat flag. + # Adding the `sed 1q' prevents false positives on HP-UX, which says: + # nm: unknown option "B" ignored + # Tru64's nm complains that /dev/null is an invalid object file + case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in + */dev/null* | *'Invalid file or object type'*) + lt_cv_path_NM="$tmp_nm -B" + break + ;; + *) + case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in + */dev/null*) + lt_cv_path_NM="$tmp_nm -p" + break + ;; + *) + lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but + continue # so that we can try to find one that supports BSD flags + ;; + esac + ;; + esac + fi + done + IFS="$lt_save_ifs" + done + : ${lt_cv_path_NM=no} +fi]) +if test "$lt_cv_path_NM" != "no"; then + NM="$lt_cv_path_NM" +else + # Didn't find any BSD compatible name lister, look for dumpbin. + if test -n "$DUMPBIN"; then : + # Let the user override the test. + else + AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) + case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in + *COFF*) + DUMPBIN="$DUMPBIN -symbols" + ;; + *) + DUMPBIN=: + ;; + esac + fi + AC_SUBST([DUMPBIN]) + if test "$DUMPBIN" != ":"; then + NM="$DUMPBIN" + fi +fi +test -z "$NM" && NM=nm +AC_SUBST([NM]) +_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl + +AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], + [lt_cv_nm_interface="BSD nm" + echo "int some_variable = 0;" > conftest.$ac_ext + (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) + (eval "$ac_compile" 2>conftest.err) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) + (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) + cat conftest.err >&AS_MESSAGE_LOG_FD + (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) + cat conftest.out >&AS_MESSAGE_LOG_FD + if $GREP 'External.*some_variable' conftest.out > /dev/null; then + lt_cv_nm_interface="MS dumpbin" + fi + rm -f conftest*]) +])# LT_PATH_NM + +# Old names: +AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) +AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_PROG_NM], []) +dnl AC_DEFUN([AC_PROG_NM], []) + +# _LT_CHECK_SHAREDLIB_FROM_LINKLIB +# -------------------------------- +# how to determine the name of the shared library +# associated with a specific link library. +# -- PORTME fill in with the dynamic library characteristics +m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], +[m4_require([_LT_DECL_EGREP]) +m4_require([_LT_DECL_OBJDUMP]) +m4_require([_LT_DECL_DLLTOOL]) +AC_CACHE_CHECK([how to associate runtime and link libraries], +lt_cv_sharedlib_from_linklib_cmd, +[lt_cv_sharedlib_from_linklib_cmd='unknown' + +case $host_os in +cygwin* | mingw* | pw32* | cegcc*) + # two different shell functions defined in ltmain.sh + # decide which to use based on capabilities of $DLLTOOL + case `$DLLTOOL --help 2>&1` in + *--identify-strict*) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib + ;; + *) + lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback + ;; + esac + ;; +*) + # fallback: assume linklib IS sharedlib + lt_cv_sharedlib_from_linklib_cmd="$ECHO" + ;; +esac +]) +sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd +test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO + +_LT_DECL([], [sharedlib_from_linklib_cmd], [1], + [Command to associate shared and link libraries]) +])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB + + +# _LT_PATH_MANIFEST_TOOL +# ---------------------- +# locate the manifest tool +m4_defun([_LT_PATH_MANIFEST_TOOL], +[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) +test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt +AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], + [lt_cv_path_mainfest_tool=no + echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD + $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out + cat conftest.err >&AS_MESSAGE_LOG_FD + if $GREP 'Manifest Tool' conftest.out > /dev/null; then + lt_cv_path_mainfest_tool=yes + fi + rm -f conftest*]) +if test "x$lt_cv_path_mainfest_tool" != xyes; then + MANIFEST_TOOL=: +fi +_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl +])# _LT_PATH_MANIFEST_TOOL + + +# LT_LIB_M +# -------- +# check for math library +AC_DEFUN([LT_LIB_M], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +LIBM= +case $host in +*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) + # These system don't have libm, or don't need it + ;; +*-ncr-sysv4.3*) + AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") + AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") + ;; +*) + AC_CHECK_LIB(m, cos, LIBM="-lm") + ;; +esac +AC_SUBST([LIBM]) +])# LT_LIB_M + +# Old name: +AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_CHECK_LIBM], []) + + +# _LT_COMPILER_NO_RTTI([TAGNAME]) +# ------------------------------- +m4_defun([_LT_COMPILER_NO_RTTI], +[m4_require([_LT_TAG_COMPILER])dnl + +_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + +if test "$GCC" = yes; then + case $cc_basename in + nvcc*) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; + *) + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; + esac + + _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], + lt_cv_prog_compiler_rtti_exceptions, + [-fno-rtti -fno-exceptions], [], + [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) +fi +_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], + [Compiler flag to turn off builtin functions]) +])# _LT_COMPILER_NO_RTTI + + +# _LT_CMD_GLOBAL_SYMBOLS +# ---------------------- +m4_defun([_LT_CMD_GLOBAL_SYMBOLS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_PROG_CC])dnl +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([LT_PATH_NM])dnl +AC_REQUIRE([LT_PATH_LD])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_TAG_COMPILER])dnl + +# Check for command to grab the raw symbol name followed by C symbol from nm. +AC_MSG_CHECKING([command to parse $NM output from $compiler object]) +AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], +[ +# These are sane defaults that work on at least a few old systems. +# [They come from Ultrix. What could be older than Ultrix?!! ;)] + +# Character class describing NM global symbol codes. +symcode='[[BCDEGRST]]' + +# Regexp to match symbols that can be accessed directly from C. +sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' + +# Define system-specific variables. +case $host_os in +aix*) + symcode='[[BCDT]]' + ;; +cygwin* | mingw* | pw32* | cegcc*) + symcode='[[ABCDGISTW]]' + ;; +hpux*) + if test "$host_cpu" = ia64; then + symcode='[[ABCDEGRST]]' + fi + ;; +irix* | nonstopux*) + symcode='[[BCDEGRST]]' + ;; +osf*) + symcode='[[BCDEGQRST]]' + ;; +solaris*) + symcode='[[BDRT]]' + ;; +sco3.2v5*) + symcode='[[DT]]' + ;; +sysv4.2uw2*) + symcode='[[DT]]' + ;; +sysv5* | sco5v6* | unixware* | OpenUNIX*) + symcode='[[ABDT]]' + ;; +sysv4) + symcode='[[DFNSTU]]' + ;; +esac + +# If we're using GNU nm, then use its standard symbol codes. +case `$NM -V 2>&1` in +*GNU* | *'with BFD'*) + symcode='[[ABCDGIRSTW]]' ;; +esac + +# Transform an extracted symbol line into a proper C declaration. +# Some systems (esp. on ia64) link data and code symbols differently, +# so use this general approach. +lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" + +# Transform an extracted symbol line into symbol name and symbol address +lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" +lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" + +# Handle CRLF in mingw tool chain +opt_cr= +case $build_os in +mingw*) + opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp + ;; +esac + +# Try without a prefix underscore, then with it. +for ac_symprfx in "" "_"; do + + # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. + symxfrm="\\1 $ac_symprfx\\2 \\2" + + # Write the raw and C identifiers. + if test "$lt_cv_nm_interface" = "MS dumpbin"; then + # Fake it for dumpbin and say T for any non-static function + # and D for any global variable. + # Also find C++ and __fastcall symbols from MSVC++, + # which start with @ or ?. + lt_cv_sys_global_symbol_pipe="$AWK ['"\ +" {last_section=section; section=\$ 3};"\ +" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ +" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ +" \$ 0!~/External *\|/{next};"\ +" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ +" {if(hide[section]) next};"\ +" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ +" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ +" s[1]~/^[@?]/{print s[1], s[1]; next};"\ +" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ +" ' prfx=^$ac_symprfx]" + else + lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" + fi + lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" + + # Check to see that the pipe works correctly. + pipe_works=no + + rm -f conftest* + cat > conftest.$ac_ext <<_LT_EOF +#ifdef __cplusplus +extern "C" { +#endif +char nm_test_var; +void nm_test_func(void); +void nm_test_func(void){} +#ifdef __cplusplus +} +#endif +int main(){nm_test_var='a';nm_test_func();return(0);} +_LT_EOF + + if AC_TRY_EVAL(ac_compile); then + # Now try to grab the symbols. + nlist=conftest.nm + if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then + # Try sorting and uniquifying the output. + if sort "$nlist" | uniq > "$nlist"T; then + mv -f "$nlist"T "$nlist" + else + rm -f "$nlist"T + fi + + # Make sure that we snagged all the symbols we need. + if $GREP ' nm_test_var$' "$nlist" >/dev/null; then + if $GREP ' nm_test_func$' "$nlist" >/dev/null; then + cat <<_LT_EOF > conftest.$ac_ext +/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ +#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) +/* DATA imports from DLLs on WIN32 con't be const, because runtime + relocations are performed -- see ld's documentation on pseudo-relocs. */ +# define LT@&t@_DLSYM_CONST +#elif defined(__osf__) +/* This system does not cope well with relocations in const data. */ +# define LT@&t@_DLSYM_CONST +#else +# define LT@&t@_DLSYM_CONST const +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +_LT_EOF + # Now generate the symbol file. + eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' + + cat <<_LT_EOF >> conftest.$ac_ext + +/* The mapping between symbol names and symbols. */ +LT@&t@_DLSYM_CONST struct { + const char *name; + void *address; +} +lt__PROGRAM__LTX_preloaded_symbols[[]] = +{ + { "@PROGRAM@", (void *) 0 }, +_LT_EOF + $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext + cat <<\_LT_EOF >> conftest.$ac_ext + {0, (void *) 0} +}; + +/* This works around a problem in FreeBSD linker */ +#ifdef FREEBSD_WORKAROUND +static const void *lt_preloaded_setup() { + return lt__PROGRAM__LTX_preloaded_symbols; +} +#endif + +#ifdef __cplusplus +} +#endif +_LT_EOF + # Now try linking the two files. + mv conftest.$ac_objext conftstm.$ac_objext + lt_globsym_save_LIBS=$LIBS + lt_globsym_save_CFLAGS=$CFLAGS + LIBS="conftstm.$ac_objext" + CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" + if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then + pipe_works=yes + fi + LIBS=$lt_globsym_save_LIBS + CFLAGS=$lt_globsym_save_CFLAGS + else + echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD + fi + else + echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD + fi + else + echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD + cat conftest.$ac_ext >&5 + fi + rm -rf conftest* conftst* + + # Do not use the global_symbol_pipe unless it works. + if test "$pipe_works" = yes; then + break + else + lt_cv_sys_global_symbol_pipe= + fi +done +]) +if test -z "$lt_cv_sys_global_symbol_pipe"; then + lt_cv_sys_global_symbol_to_cdecl= +fi +if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then + AC_MSG_RESULT(failed) +else + AC_MSG_RESULT(ok) +fi + +# Response file support. +if test "$lt_cv_nm_interface" = "MS dumpbin"; then + nm_file_list_spec='@' +elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then + nm_file_list_spec='@' +fi + +_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], + [Take the output of nm and produce a listing of raw symbols and C names]) +_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], + [Transform the output of nm in a proper C declaration]) +_LT_DECL([global_symbol_to_c_name_address], + [lt_cv_sys_global_symbol_to_c_name_address], [1], + [Transform the output of nm in a C name address pair]) +_LT_DECL([global_symbol_to_c_name_address_lib_prefix], + [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], + [Transform the output of nm in a C name address pair when lib prefix is needed]) +_LT_DECL([], [nm_file_list_spec], [1], + [Specify filename containing input files for $NM]) +]) # _LT_CMD_GLOBAL_SYMBOLS + + +# _LT_COMPILER_PIC([TAGNAME]) +# --------------------------- +m4_defun([_LT_COMPILER_PIC], +[m4_require([_LT_TAG_COMPILER])dnl +_LT_TAGVAR(lt_prog_compiler_wl, $1)= +_LT_TAGVAR(lt_prog_compiler_pic, $1)= +_LT_TAGVAR(lt_prog_compiler_static, $1)= + +m4_if([$1], [CXX], [ + # C++ specific cases for pic, static, wl, etc. + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + *djgpp*) + # DJGPP does not support shared libraries at all + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + else + case $host_os in + aix[[4-9]]*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + chorus*) + case $cc_basename in + cxch68*) + # Green Hills C++ Compiler + # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" + ;; + esac + ;; + mingw* | cygwin* | os2* | pw32* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + dgux*) + case $cc_basename in + ec++*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + ghcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + freebsd* | dragonfly*) + # FreeBSD uses GNU C++ + ;; + hpux9* | hpux10* | hpux11*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + if test "$host_cpu" != ia64; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + fi + ;; + aCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + ;; + *) + ;; + esac + ;; + interix*) + # This is c89, which is MS Visual C++ (no shared libs) + # Anyone wants to do a port? + ;; + irix5* | irix6* | nonstopux*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + # CC pic flag -KPIC is the default. + ;; + *) + ;; + esac + ;; + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # KAI C++ Compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + ecpc* ) + # old Intel C++ for x86_64 which still supported -KPIC. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + icpc* ) + # Intel C++, used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + cxx*) + # Compaq C++ + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) + # IBM XL 8.0, 9.0 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + esac + ;; + esac + ;; + lynxos*) + ;; + m88k*) + ;; + mvs*) + case $cc_basename in + cxx*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' + ;; + *) + ;; + esac + ;; + netbsd*) + ;; + *qnx* | *nto*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' + ;; + RCC*) + # Rational C++ 2.4.1 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + cxx*) + # Digital/Compaq C++ + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # Make sure the PIC flag is empty. It appears that all Alpha + # Linux and Compaq Tru64 Unix objects are PIC. + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + *) + ;; + esac + ;; + psos*) + ;; + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + ;; + *) + ;; + esac + ;; + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + lcc*) + # Lucid + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + ;; + *) + ;; + esac + ;; + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + case $cc_basename in + CC*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + ;; + *) + ;; + esac + ;; + vxworks*) + ;; + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +], +[ + if test "$GCC" = yes; then + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + + case $host_os in + aix*) + # All AIX code is PIC. + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + m68k) + # FIXME: we need at least 68020 code to build shared libraries, but + # adding the `-m68020' flag to GCC prevents building anything better, + # like `-m68040'. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' + ;; + esac + ;; + + beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) + # PIC is the default for these OSes. + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + # Although the cygwin gcc ignores -fPIC, still need this for old-style + # (--disable-auto-import) libraries + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + darwin* | rhapsody*) + # PIC is the default on this platform + # Common symbols not allowed in MH_DYLIB files + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' + ;; + + haiku*) + # PIC is the default for Haiku. + # The "-static" flag exists, but is broken. + _LT_TAGVAR(lt_prog_compiler_static, $1)= + ;; + + hpux*) + # PIC is the default for 64-bit PA HP-UX, but not for 32-bit + # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag + # sets the default TLS model and affects inlining. + case $host_cpu in + hppa*64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + ;; + + interix[[3-9]]*) + # Interix 3.x gcc -fpic/-fPIC options generate broken code. + # Instead, we relocate shared libraries at runtime. + ;; + + msdosdjgpp*) + # Just because we use GCC doesn't mean we suddenly get shared libraries + # on systems that don't support them. + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + enable_shared=no + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic + fi + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + ;; + esac + + case $cc_basename in + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' + if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" + fi + ;; + esac + else + # PORTME Check for flag to pass linker flags through the system compiler. + case $host_os in + aix*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + if test "$host_cpu" = ia64; then + # AIX 5 now supports IA64 processor + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + else + _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' + fi + ;; + + mingw* | cygwin* | pw32* | os2* | cegcc*) + # This hack is so that the source file can tell whether it is being + # built for inclusion in a dll (and should export symbols for example). + m4_if([$1], [GCJ], [], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) + ;; + + hpux9* | hpux10* | hpux11*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but + # not for PA HP-UX. + case $host_cpu in + hppa*64*|ia64*) + # +Z the default + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' + ;; + esac + # Is there a better lt_prog_compiler_static that works with the bundled CC? + _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' + ;; + + irix5* | irix6* | nonstopux*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # PIC (with -KPIC) is the default. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + # old Intel for x86_64 which still supported -KPIC. + ecc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # icc used to be incompatible with GCC. + # ICC 10 doesn't accept -KPIC any more. + icc* | ifort*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + # Lahey Fortran 8.1. + lf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' + _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' + ;; + nagfor*) + # NAG Fortran compiler + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group compilers (*not* the Pentium gcc compiler, + # which looks to be a dead project) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + ccc*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All Alpha code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + xl* | bgxl* | bgf* | mpixl*) + # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) + # Sun Fortran 8.3 passes all unrecognized flags to the linker + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='' + ;; + *Sun\ F* | *Sun*Fortran*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + ;; + *Sun\ C*) + # Sun C 5.9 + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + ;; + *Intel*\ [[CF]]*Compiler*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' + ;; + *Portland\ Group*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + esac + ;; + esac + ;; + + newsos6) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *nto* | *qnx*) + # QNX uses GNU C++, but need to define -shared option too, otherwise + # it will coredump. + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' + ;; + + osf3* | osf4* | osf5*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + # All OSF/1 code is PIC. + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + rdos*) + _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' + ;; + + solaris*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + case $cc_basename in + f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; + *) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; + esac + ;; + + sunos4*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4 | sysv4.2uw2* | sysv4.3*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + sysv4*MP*) + if test -d /usr/nec ;then + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + fi + ;; + + sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + unicos*) + _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + + uts4*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' + _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' + ;; + + *) + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no + ;; + esac + fi +]) +case $host_os in + # For platforms which do not support PIC, -DPIC is meaningless: + *djgpp*) + _LT_TAGVAR(lt_prog_compiler_pic, $1)= + ;; + *) + _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" + ;; +esac + +AC_CACHE_CHECK([for $compiler option to produce PIC], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], + [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) +_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) + +# +# Check to make sure the PIC flag actually works. +# +if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then + _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], + [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], + [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], + [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in + "" | " "*) ;; + *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; + esac], + [_LT_TAGVAR(lt_prog_compiler_pic, $1)= + _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) +fi +_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], + [Additional compiler flags for building library objects]) + +_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], + [How to pass a linker flag through the compiler]) +# +# Check to make sure the static flag actually works. +# +wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" +_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], + _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), + $lt_tmp_static_flag, + [], + [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) +_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], + [Compiler flag to prevent dynamic linking]) +])# _LT_COMPILER_PIC + + +# _LT_LINKER_SHLIBS([TAGNAME]) +# ---------------------------- +# See if the linker supports building shared libraries. +m4_defun([_LT_LINKER_SHLIBS], +[AC_REQUIRE([LT_PATH_LD])dnl +AC_REQUIRE([LT_PATH_NM])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_DECL_SED])dnl +m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl +m4_require([_LT_TAG_COMPILER])dnl +AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) +m4_if([$1], [CXX], [ + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + case $host_os in + aix[[4-9]]*) + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global defined + # symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + ;; + pw32*) + _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" + ;; + cygwin* | mingw* | cegcc*) + case $cc_basename in + cl*) + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + ;; + esac + ;; + *) + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + ;; + esac +], [ + runpath_var= + _LT_TAGVAR(allow_undefined_flag, $1)= + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(archive_cmds, $1)= + _LT_TAGVAR(archive_expsym_cmds, $1)= + _LT_TAGVAR(compiler_needs_object, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(hardcode_automatic, $1)=no + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(hardcode_libdir_separator, $1)= + _LT_TAGVAR(hardcode_minus_L, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported + _LT_TAGVAR(inherit_rpath, $1)=no + _LT_TAGVAR(link_all_deplibs, $1)=unknown + _LT_TAGVAR(module_cmds, $1)= + _LT_TAGVAR(module_expsym_cmds, $1)= + _LT_TAGVAR(old_archive_from_new_cmds, $1)= + _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= + _LT_TAGVAR(thread_safe_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + # include_expsyms should be a list of space-separated symbols to be *always* + # included in the symbol list + _LT_TAGVAR(include_expsyms, $1)= + # exclude_expsyms can be an extended regexp of symbols to exclude + # it will be wrapped by ` (' and `)$', so one must not match beginning or + # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', + # as well as any symbol that contains `d'. + _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] + # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out + # platforms (ab)use it in PIC code, but their linkers get confused if + # the symbol is explicitly referenced. Since portable code cannot + # rely on this symbol name, it's probably fine to never include it in + # preloaded symbol tables. + # Exclude shared library initialization/finalization symbols. +dnl Note also adjust exclude_expsyms for C++ above. + extract_expsyms_cmds= + + case $host_os in + cygwin* | mingw* | pw32* | cegcc*) + # FIXME: the MSVC++ port hasn't been tested in a loooong time + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + if test "$GCC" != yes; then + with_gnu_ld=no + fi + ;; + interix*) + # we just hope/assume this is gcc and not c89 (= MSVC++) + with_gnu_ld=yes + ;; + openbsd*) + with_gnu_ld=no + ;; + esac + + _LT_TAGVAR(ld_shlibs, $1)=yes + + # On some targets, GNU ld is compatible enough with the native linker + # that we're better off using the native interface for both. + lt_use_gnu_ld_interface=no + if test "$with_gnu_ld" = yes; then + case $host_os in + aix*) + # The AIX port of GNU ld has always aspired to compatibility + # with the native linker. However, as the warning in the GNU ld + # block says, versions before 2.19.5* couldn't really create working + # shared libraries, regardless of the interface used. + case `$LD -v 2>&1` in + *\ \(GNU\ Binutils\)\ 2.19.5*) ;; + *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; + *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + ;; + *) + lt_use_gnu_ld_interface=yes + ;; + esac + fi + + if test "$lt_use_gnu_ld_interface" = yes; then + # If archive_cmds runs LD, not CC, wlarc should be empty + wlarc='${wl}' + + # Set some defaults for GNU ld with shared library support. These + # are reset later if shared libraries are not supported. Putting them + # here allows them to be overridden if necessary. + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + # ancient GNU ld didn't support --whole-archive et. al. + if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + supports_anon_versioning=no + case `$LD -v 2>&1` in + *GNU\ gold*) supports_anon_versioning=yes ;; + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 + *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... + *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... + *\ 2.11.*) ;; # other 2.11 versions + *) supports_anon_versioning=yes ;; + esac + + # See if GNU ld supports shared libraries. + case $host_os in + aix[[3-9]]*) + # On AIX/PPC, the GNU linker is very broken + if test "$host_cpu" != ia64; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: the GNU linker, at least up to release 2.19, is reported +*** to be unable to reliably create shared libraries on AIX. +*** Therefore, libtool is disabling shared libraries support. If you +*** really care for shared libraries, you may want to install binutils +*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. +*** You will then need to restart the configuration process. + +_LT_EOF + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' + _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + + gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) + tmp_diet=no + if test "$host_os" = linux-dietlibc; then + case $cc_basename in + diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) + esac + fi + if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ + && test "$tmp_diet" = no + then + tmp_addflag=' $pic_flag' + tmp_sharedflag='-shared' + case $cc_basename,$host_cpu in + pgcc*) # Portland Group C compiler + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag' + ;; + pgf77* | pgf90* | pgf95* | pgfortran*) + # Portland Group f77 and f90 compilers + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + tmp_addflag=' $pic_flag -Mnomain' ;; + ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 + tmp_addflag=' -i_dynamic' ;; + efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 + tmp_addflag=' -i_dynamic -nofor_main' ;; + ifc* | ifort*) # Intel Fortran compiler + tmp_addflag=' -nofor_main' ;; + lf95*) # Lahey Fortran 8.1 + _LT_TAGVAR(whole_archive_flag_spec, $1)= + tmp_sharedflag='--shared' ;; + xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) + tmp_sharedflag='-qmkshrobj' + tmp_addflag= ;; + nvcc*) # Cuda Compiler Driver 2.2 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + ;; + esac + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) # Sun C 5.9 + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + tmp_sharedflag='-G' ;; + *Sun\ F*) # Sun Fortran 8.3 + tmp_sharedflag='-G' ;; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + + case $cc_basename in + xlf* | bgf* | bgxlf* | mpixlf*) + # IBM XL Fortran 10.1 on PPC cannot create shared libs itself + _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' + fi + ;; + esac + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' + wlarc= + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + fi + ;; + + solaris*) + if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: The releases 2.8.* of the GNU linker cannot reliably +*** create shared libraries on Solaris systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.9.1 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) + case `$LD -v 2>&1` in + *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) + _LT_TAGVAR(ld_shlibs, $1)=no + cat <<_LT_EOF 1>&2 + +*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not +*** reliably create shared libraries on SCO systems. Therefore, libtool +*** is disabling shared libraries support. We urge you to upgrade GNU +*** binutils to release 2.16.91.0.3 or newer. Another option is to modify +*** your PATH or compiler configuration so that the native linker is +*** used, and then restart. + +_LT_EOF + ;; + *) + # For security reasons, it is highly recommended that you always + # use absolute paths for naming shared libraries, and exclude the + # DT_RUNPATH tag from executables and libraries. But doing so + # requires that you compile everything twice, which is a pain. + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + sunos4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + + if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then + runpath_var= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= + _LT_TAGVAR(export_dynamic_flag_spec, $1)= + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + # PORTME fill in a description of your system's linker (not GNU ld) + case $host_os in + aix3*) + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' + # Note: this linker hardcodes the directories in LIBPATH if there + # are no directories specified by -L. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then + # Neither direct hardcoding nor static linking is supported with a + # broken collect2. + _LT_TAGVAR(hardcode_direct, $1)=unsupported + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + # If we're using GNU nm, then we don't want the "-C" option. + # -C means demangle to AIX nm, but means don't demangle with GNU nm + # Also, AIX nm treats weak defined symbols like other global + # defined symbols, whereas GNU nm marks them as "W". + if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + else + _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' + fi + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then + aix_use_runtimelinking=yes + break + fi + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GCC" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + ;; + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + amigaos*) + case $host_cpu in + powerpc) + # see comment about AmigaOS4 .so support + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='' + ;; + m68k) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + ;; + + bsdi[[45]]*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic + ;; + + cygwin* | mingw* | pw32* | cegcc*) + # When not using gcc, we currently assume that we are using + # Microsoft Visual C++. + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + case $cc_basename in + cl*) + # Native MSVC + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' + _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # Assume MSVC wrapper + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' + # The linker will automatically build a .lib file if we build a DLL. + _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + # FIXME: Should let the user specify the lib program. + _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + ;; + esac + ;; + + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor + # support. Future versions do this automatically, but an explicit c++rt0.o + # does not break anything, and helps significantly (at the cost of a little + # extra space). + freebsd2.2*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # Unfortunately, older versions of FreeBSD 2 do not have this feature. + freebsd2.*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + # FreeBSD 3 and greater uses gcc -shared to do shared libraries. + freebsd* | dragonfly*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + hpux9*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + + hpux10*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + fi + ;; + + hpux11*) + if test "$GCC" = yes && test "$with_gnu_ld" = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + else + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + m4_if($1, [], [ + # Older versions of the 11.00 compiler do not understand -b yet + # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) + _LT_LINKER_OPTION([if $CC understands -b], + _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], + [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], + [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) + ;; + esac + fi + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + + # hardcode_minus_L: Not really in the search PATH, + # but as the default location of the library. + _LT_TAGVAR(hardcode_minus_L, $1)=yes + ;; + esac + fi + ;; + + irix5* | irix6* | nonstopux*) + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + # Try to use the -exported_symbol ld option, if it does not + # work, assume that -exports_file does not work either and + # implicitly export all symbols. + # This should be the same for all languages, so no per-tag cache variable. + AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], + [lt_cv_irix_exported_symbol], + [save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" + AC_LINK_IFELSE( + [AC_LANG_SOURCE( + [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], + [C++], [[int foo (void) { return 0; }]], + [Fortran 77], [[ + subroutine foo + end]], + [Fortran], [[ + subroutine foo + end]])])], + [lt_cv_irix_exported_symbol=yes], + [lt_cv_irix_exported_symbol=no]) + LDFLAGS="$save_LDFLAGS"]) + if test "$lt_cv_irix_exported_symbol" = yes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' + fi + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out + else + _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + newsos6) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *nto* | *qnx*) + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + else + case $host_os in + openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + ;; + esac + fi + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + os2*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' + _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' + ;; + + osf3*) + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + osf4* | osf5*) # as osf3* with the addition of -msym flag + if test "$GCC" = yes; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + else + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ + $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' + + # Both c and cxx compiler support -rpath directly + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)='no' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + ;; + + solaris*) + _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' + if test "$GCC" = yes; then + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + else + case `$CC -V 2>&1` in + *"Compilers 5.0"*) + wlarc='' + _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' + ;; + *) + wlarc='${wl}' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' + ;; + esac + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. GCC discards it without `$wl', + # but is careful enough not to reorder. + # Supported since Solaris 2.6 (maybe 2.5.1?) + if test "$GCC" = yes; then + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + fi + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + sunos4*) + if test "x$host_vendor" = xsequent; then + # Use $CC to link under sequent, because it throws in some extra .o + # files that make .init and .fini sections work. + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' + fi + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4) + case $host_vendor in + sni) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? + ;; + siemens) + ## LD is ld it makes a PLAMLIB + ## CC just makes a GrossModule. + _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' + _LT_TAGVAR(hardcode_direct, $1)=no + ;; + motorola) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie + ;; + esac + runpath_var='LD_RUN_PATH' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + sysv4.3*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' + ;; + + sysv4*MP*) + if test -d /usr/nec; then + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var=LD_RUN_PATH + hardcode_runpath_var=yes + _LT_TAGVAR(ld_shlibs, $1)=yes + fi + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + if test "$GCC" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + fi + ;; + + uts4*) + _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + + *) + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + if test x$host_vendor = xsni; then + case $host in + sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' + ;; + esac + fi + fi +]) +AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) +test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + +_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld + +_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl +_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl +_LT_DECL([], [extract_expsyms_cmds], [2], + [The commands to extract the exported symbol list from a shared archive]) + +# +# Do we need to explicitly link libc? +# +case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in +x|xyes) + # Assume -lc should be added + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + + if test "$enable_shared" = yes && test "$GCC" = yes; then + case $_LT_TAGVAR(archive_cmds, $1) in + *'~'*) + # FIXME: we may have to deal with multi-command sequences. + ;; + '$CC '*) + # Test whether the compiler implicitly links with -lc since on some + # systems, -lgcc has to come before -lc. If gcc already passes -lc + # to ld, don't add -lc before -lgcc. + AC_CACHE_CHECK([whether -lc should be explicitly linked in], + [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), + [$RM conftest* + echo "$lt_simple_compile_test_code" > conftest.$ac_ext + + if AC_TRY_EVAL(ac_compile) 2>conftest.err; then + soname=conftest + lib=conftest + libobjs=conftest.$ac_objext + deplibs= + wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) + pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) + compiler_flags=-v + linker_flags=-v + verstring= + output_objdir=. + libname=conftest + lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) + _LT_TAGVAR(allow_undefined_flag, $1)= + if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) + then + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no + else + lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes + fi + _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag + else + cat conftest.err 1>&5 + fi + $RM conftest* + ]) + _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) + ;; + esac + fi + ;; +esac + +_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], + [Whether or not to add -lc for building shared libraries]) +_LT_TAGDECL([allow_libtool_libs_with_static_runtimes], + [enable_shared_with_static_runtimes], [0], + [Whether or not to disallow shared libs when runtime libs are static]) +_LT_TAGDECL([], [export_dynamic_flag_spec], [1], + [Compiler flag to allow reflexive dlopens]) +_LT_TAGDECL([], [whole_archive_flag_spec], [1], + [Compiler flag to generate shared objects directly from archives]) +_LT_TAGDECL([], [compiler_needs_object], [1], + [Whether the compiler copes with passing no objects directly]) +_LT_TAGDECL([], [old_archive_from_new_cmds], [2], + [Create an old-style archive from a shared archive]) +_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], + [Create a temporary old-style archive to link instead of a shared archive]) +_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) +_LT_TAGDECL([], [archive_expsym_cmds], [2]) +_LT_TAGDECL([], [module_cmds], [2], + [Commands used to build a loadable module if different from building + a shared archive.]) +_LT_TAGDECL([], [module_expsym_cmds], [2]) +_LT_TAGDECL([], [with_gnu_ld], [1], + [Whether we are building with GNU ld or not]) +_LT_TAGDECL([], [allow_undefined_flag], [1], + [Flag that allows shared libraries with undefined symbols to be built]) +_LT_TAGDECL([], [no_undefined_flag], [1], + [Flag that enforces no undefined symbols]) +_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], + [Flag to hardcode $libdir into a binary during linking. + This must work even if $libdir does not exist]) +_LT_TAGDECL([], [hardcode_libdir_separator], [1], + [Whether we need a single "-rpath" flag with a separated argument]) +_LT_TAGDECL([], [hardcode_direct], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary]) +_LT_TAGDECL([], [hardcode_direct_absolute], [0], + [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes + DIR into the resulting binary and the resulting library dependency is + "absolute", i.e impossible to change by setting ${shlibpath_var} if the + library is relocated]) +_LT_TAGDECL([], [hardcode_minus_L], [0], + [Set to "yes" if using the -LDIR flag during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_shlibpath_var], [0], + [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR + into the resulting binary]) +_LT_TAGDECL([], [hardcode_automatic], [0], + [Set to "yes" if building a shared library automatically hardcodes DIR + into the library and all subsequent libraries and executables linked + against it]) +_LT_TAGDECL([], [inherit_rpath], [0], + [Set to yes if linker adds runtime paths of dependent libraries + to runtime path list]) +_LT_TAGDECL([], [link_all_deplibs], [0], + [Whether libtool must link a program against all its dependency libraries]) +_LT_TAGDECL([], [always_export_symbols], [0], + [Set to "yes" if exported symbols are required]) +_LT_TAGDECL([], [export_symbols_cmds], [2], + [The commands to list exported symbols]) +_LT_TAGDECL([], [exclude_expsyms], [1], + [Symbols that should not be listed in the preloaded symbols]) +_LT_TAGDECL([], [include_expsyms], [1], + [Symbols that must always be exported]) +_LT_TAGDECL([], [prelink_cmds], [2], + [Commands necessary for linking programs (against libraries) with templates]) +_LT_TAGDECL([], [postlink_cmds], [2], + [Commands necessary for finishing linking programs]) +_LT_TAGDECL([], [file_list_spec], [1], + [Specify filename containing input files]) +dnl FIXME: Not yet implemented +dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], +dnl [Compiler flag to generate thread safe objects]) +])# _LT_LINKER_SHLIBS + + +# _LT_LANG_C_CONFIG([TAG]) +# ------------------------ +# Ensure that the configuration variables for a C compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_C_CONFIG], +[m4_require([_LT_DECL_EGREP])dnl +lt_save_CC="$CC" +AC_LANG_PUSH(C) + +# Source file extension for C test sources. +ac_ext=c + +# Object file extension for compiled C test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="int some_variable = 0;" + +# Code to be used in simple link tests +lt_simple_link_test_code='int main(){return(0);}' + +_LT_TAG_COMPILER +# Save the default compiler, since it gets overwritten when the other +# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. +compiler_DEFAULT=$CC + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + LT_SYS_DLOPEN_SELF + _LT_CMD_STRIPLIB + + # Report which library types will actually be built + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_CONFIG($1) +fi +AC_LANG_POP +CC="$lt_save_CC" +])# _LT_LANG_C_CONFIG + + +# _LT_LANG_CXX_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a C++ compiler are suitably +# defined. These variables are subsequently used by _LT_CONFIG to write +# the compiler configuration to `libtool'. +m4_defun([_LT_LANG_CXX_CONFIG], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +m4_require([_LT_DECL_EGREP])dnl +m4_require([_LT_PATH_MANIFEST_TOOL])dnl +if test -n "$CXX" && ( test "X$CXX" != "Xno" && + ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || + (test "X$CXX" != "Xg++"))) ; then + AC_PROG_CXXCPP +else + _lt_caught_CXX_error=yes +fi + +AC_LANG_PUSH(C++) +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(compiler_needs_object, $1)=no +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for C++ test sources. +ac_ext=cpp + +# Object file extension for compiled C++ test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the CXX compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_caught_CXX_error" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="int some_variable = 0;" + + # Code to be used in simple link tests + lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC=$CC + lt_save_CFLAGS=$CFLAGS + lt_save_LD=$LD + lt_save_GCC=$GCC + GCC=$GXX + lt_save_with_gnu_ld=$with_gnu_ld + lt_save_path_LD=$lt_cv_path_LD + if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then + lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx + else + $as_unset lt_cv_prog_gnu_ld + fi + if test -n "${lt_cv_path_LDCXX+set}"; then + lt_cv_path_LD=$lt_cv_path_LDCXX + else + $as_unset lt_cv_path_LD + fi + test -z "${LDCXX+set}" || LD=$LDCXX + CC=${CXX-"c++"} + CFLAGS=$CXXFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + # We don't want -fno-exception when compiling C++ code, so set the + # no_builtin_flag separately + if test "$GXX" = yes; then + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' + else + _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= + fi + + if test "$GXX" = yes; then + # Set up default GNU C++ configuration + + LT_PATH_LD + + # Check if GNU C++ uses GNU ld as the underlying linker, since the + # archiving commands below assume that GNU ld is being used. + if test "$with_gnu_ld" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # If archive_cmds runs LD, not CC, wlarc should be empty + # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to + # investigate it a little bit more. (MM) + wlarc='${wl}' + + # ancient GNU ld didn't support --whole-archive et. al. + if eval "`$CC -print-prog-name=ld` --help 2>&1" | + $GREP 'no-whole-archive' > /dev/null; then + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + else + _LT_TAGVAR(whole_archive_flag_spec, $1)= + fi + else + with_gnu_ld=no + wlarc= + + # A generic and very simple default shared library creation + # command for GNU C++ for the case where it uses the native + # linker, instead of GNU ld. If possible, this setting should + # overridden to take advantage of the native linker features on + # the platform it is being used on. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + fi + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + GXX=no + with_gnu_ld=no + wlarc= + fi + + # PORTME: fill in a description of your system's C++ link characteristics + AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) + _LT_TAGVAR(ld_shlibs, $1)=yes + case $host_os in + aix3*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aix[[4-9]]*) + if test "$host_cpu" = ia64; then + # On IA64, the linker does run time linking by default, so we don't + # have to do anything special. + aix_use_runtimelinking=no + exp_sym_flag='-Bexport' + no_entry_flag="" + else + aix_use_runtimelinking=no + + # Test if we are trying to use run time linking or normal + # AIX style linking. If -brtl is somewhere in LDFLAGS, we + # need to do runtime linking. + case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) + for ld_flag in $LDFLAGS; do + case $ld_flag in + *-brtl*) + aix_use_runtimelinking=yes + break + ;; + esac + done + ;; + esac + + exp_sym_flag='-bexport' + no_entry_flag='-bnoentry' + fi + + # When large executables or shared objects are built, AIX ld can + # have problems creating the table of contents. If linking a library + # or program results in "error TOC overflow" add -mminimal-toc to + # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not + # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. + + _LT_TAGVAR(archive_cmds, $1)='' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' + + if test "$GXX" = yes; then + case $host_os in aix4.[[012]]|aix4.[[012]].*) + # We only want to do this on AIX 4.2 and lower, the check + # below for broken collect2 doesn't work under 4.3+ + collect2name=`${CC} -print-prog-name=collect2` + if test -f "$collect2name" && + strings "$collect2name" | $GREP resolve_lib_name >/dev/null + then + # We have reworked collect2 + : + else + # We have old collect2 + _LT_TAGVAR(hardcode_direct, $1)=unsupported + # It fails to find uninstalled libraries when the uninstalled + # path is not listed in the libpath. Setting hardcode_minus_L + # to unsupported forces relinking + _LT_TAGVAR(hardcode_minus_L, $1)=yes + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)= + fi + esac + shared_flag='-shared' + if test "$aix_use_runtimelinking" = yes; then + shared_flag="$shared_flag "'${wl}-G' + fi + else + # not using gcc + if test "$host_cpu" = ia64; then + # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release + # chokes on -Wl,-G. The following line is correct: + shared_flag='-G' + else + if test "$aix_use_runtimelinking" = yes; then + shared_flag='${wl}-G' + else + shared_flag='${wl}-bM:SRE' + fi + fi + fi + + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' + # It seems that -bexpall does not export symbols beginning with + # underscore (_), so it is better to generate a list of symbols to + # export. + _LT_TAGVAR(always_export_symbols, $1)=yes + if test "$aix_use_runtimelinking" = yes; then + # Warning - without using the other runtime loading flags (-brtl), + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(allow_undefined_flag, $1)='-berok' + # Determine the default libpath from the value encoded in an empty + # executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" + else + if test "$host_cpu" = ia64; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' + _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" + else + # Determine the default libpath from the value encoded in an + # empty executable. + _LT_SYS_MODULE_PATH_AIX([$1]) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" + # Warning - without using the other run time loading flags, + # -berok will link without error, but may produce a broken library. + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' + if test "$with_gnu_ld" = yes; then + # We only use this code for GNU lds that support --whole-archive. + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + else + # Exported symbols can be pulled into shared objects from archives + _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' + fi + _LT_TAGVAR(archive_cmds_need_lc, $1)=yes + # This is similar to how AIX traditionally builds its shared + # libraries. + _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' + fi + fi + ;; + + beos*) + if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + # Joseph Beckenbach says some releases of gcc + # support --undefined. This deserves some investigation. FIXME + _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + chorus*) + case $cc_basename in + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + cygwin* | mingw* | pw32* | cegcc*) + case $GXX,$cc_basename in + ,cl* | no,cl*) + # Native MSVC + # hardcode_libdir_flag_spec is actually meaningless, as there is + # no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=yes + _LT_TAGVAR(file_list_spec, $1)='@' + # Tell ltmain to make .lib files, not .a files. + libext=lib + # Tell ltmain to make .dll files, not .so files. + shrext_cmds=".dll" + # FIXME: Setting linknames here is a bad hack. + _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; + else + $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; + fi~ + $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ + linknames=' + # The linker will not automatically build a static lib if we build a DLL. + # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + # Don't use ranlib + _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' + _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ + lt_tool_outputfile="@TOOL_OUTPUT@"~ + case $lt_outputfile in + *.exe|*.EXE) ;; + *) + lt_outputfile="$lt_outputfile.exe" + lt_tool_outputfile="$lt_tool_outputfile.exe" + ;; + esac~ + func_to_tool_file "$lt_outputfile"~ + if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then + $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; + $RM "$lt_outputfile.manifest"; + fi' + ;; + *) + # g++ + # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, + # as there is no search path for DLLs. + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' + _LT_TAGVAR(allow_undefined_flag, $1)=unsupported + _LT_TAGVAR(always_export_symbols, $1)=no + _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes + + if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + # If the export-symbols file already is a .def file (1st line + # is EXPORTS), use it as is; otherwise, prepend... + _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then + cp $export_symbols $output_objdir/$soname.def; + else + echo EXPORTS > $output_objdir/$soname.def; + cat $export_symbols >> $output_objdir/$soname.def; + fi~ + $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + darwin* | rhapsody*) + _LT_DARWIN_LINKER_FEATURES($1) + ;; + + dgux*) + case $cc_basename in + ec++*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + ghcx*) + # Green Hills C++ Compiler + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + freebsd2.*) + # C++ shared libraries reported to be fairly broken before + # switch to ELF + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + freebsd-elf*) + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + ;; + + freebsd* | dragonfly*) + # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF + # conventions + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + gnu*) + ;; + + haiku*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + + hpux9*) + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + hpux10*|hpux11*) + if test $with_gnu_ld = no; then + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + case $host_cpu in + hppa*64*|ia64*) + ;; + *) + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + ;; + esac + fi + case $host_cpu in + hppa*64*|ia64*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + ;; + *) + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, + # but as the default + # location of the library. + ;; + esac + + case $cc_basename in + CC*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + aCC*) + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes; then + if test $with_gnu_ld = no; then + case $host_cpu in + hppa*64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + ia64*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + ;; + esac + fi + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + interix[[3-9]]*) + _LT_TAGVAR(hardcode_direct, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. + # Instead, shared libraries are loaded at an image base (0x10000000 by + # default) and relocated if they conflict, which is a slow very memory + # consuming and fragmenting process. To avoid this, we pick a random, + # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link + # time. Moving up from 0x10000000 also allows more sbrk(2) space. + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' + ;; + irix5* | irix6*) + case $cc_basename in + CC*) + # SGI C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + + # Archives containing C++ object files must be created using + # "CC -ar", where "CC" is the IRIX C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' + ;; + *) + if test "$GXX" = yes; then + if test "$with_gnu_ld" = no; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + else + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' + fi + fi + _LT_TAGVAR(link_all_deplibs, $1)=yes + ;; + esac + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + _LT_TAGVAR(inherit_rpath, $1)=yes + ;; + + linux* | k*bsd*-gnu | kopensolaris*-gnu) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + + # Archives containing C++ object files must be created using + # "CC -Bstatic", where "CC" is the KAI C++ compiler. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' + ;; + icpc* | ecpc* ) + # Intel C++ + with_gnu_ld=yes + # version 8.0 and above of icpc choke on multiply defined symbols + # if we add $predep_objects and $postdep_objects, however 7.1 and + # earlier do not add the objects themselves. + case `$CC -V 2>&1` in + *"Version 7."*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + *) # Version 8.0 or newer + tmp_idyn= + case $host_cpu in + ia64*) tmp_idyn=' -i_dynamic';; + esac + _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' + ;; + esac + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' + ;; + pgCC* | pgcpp*) + # Portland Group C++ compiler + case `$CC -V` in + *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) + _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ + compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' + _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ + $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ + $RANLIB $oldlib' + _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ + rm -rf $tpldir~ + $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ + $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + *) # Version 6 and above use weak symbols + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + ;; + cxx*) + # Compaq C++ + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' + + runpath_var=LD_RUN_PATH + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' + ;; + xl* | mpixl* | bgxl*) + # IBM XL 8.0 on PPC, with GNU ld + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' + _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' + if test "x$supports_anon_versioning" = xyes; then + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ + cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ + echo "local: *; };" >> $output_objdir/$libname.ver~ + $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' + fi + ;; + *) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' + _LT_TAGVAR(compiler_needs_object, $1)=yes + + # Not sure whether something based on + # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 + # would be better. + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + esac + ;; + esac + ;; + + lynxos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + m88k*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + mvs*) + case $cc_basename in + cxx*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + netbsd*) + if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' + wlarc= + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + fi + # Workaround some broken pre-1.5 toolchains + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' + ;; + + *nto* | *qnx*) + _LT_TAGVAR(ld_shlibs, $1)=yes + ;; + + openbsd2*) + # C++ shared libraries are fairly broken + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + openbsd*) + if test -f /usr/libexec/ld.so; then + _LT_TAGVAR(hardcode_direct, $1)=yes + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_direct_absolute, $1)=yes + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' + _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' + fi + output_verbose_link_cmd=func_echo_all + else + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + + osf3* | osf4* | osf5*) + case $cc_basename in + KCC*) + # Kuck and Associates, Inc. (KAI) C++ Compiler + + # KCC will only create a shared library if the output file + # ends with ".so" (or ".sl" for HP-UX), so rename the library + # to its proper name (with version) after linking. + _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Archives containing C++ object files must be created using + # the KAI C++ compiler. + case $host in + osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; + *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; + esac + ;; + RCC*) + # Rational C++ 2.4.1 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + cxx*) + case $host in + osf3*) + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + ;; + *) + _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' + _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ + echo "-hidden">> $lib.exp~ + $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ + $RM $lib.exp' + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + # + # There doesn't appear to be a way to prevent this compiler from + # explicitly linking system object files so we need to strip them + # from the output so that they don't get included in the library + # dependencies. + output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' + ;; + *) + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' + case $host in + osf3*) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' + ;; + esac + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=: + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + + else + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + fi + ;; + esac + ;; + + psos*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + sunos4*) + case $cc_basename in + CC*) + # Sun C++ 4.x + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + lcc*) + # Lucid + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + solaris*) + case $cc_basename in + CC* | sunCC*) + # Sun C++ 4.2, 5.x and Centerline C++ + _LT_TAGVAR(archive_cmds_need_lc,$1)=yes + _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' + _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + # The compiler driver will combine and reorder linker options, + # but understands `-z linker_flag'. + # Supported since Solaris 2.6 (maybe 2.5.1?) + _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' + ;; + esac + _LT_TAGVAR(link_all_deplibs, $1)=yes + + output_verbose_link_cmd='func_echo_all' + + # Archives containing C++ object files must be created using + # "CC -xar", where "CC" is the Sun C++ compiler. This is + # necessary to make sure instantiated templates are included + # in the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' + ;; + gcx*) + # Green Hills C++ Compiler + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + + # The C++ compiler must be used to create the archive. + _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' + ;; + *) + # GNU C++ compiler with Solaris linker + if test "$GXX" = yes && test "$with_gnu_ld" = no; then + _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' + if $CC --version | $GREP -v '^2\.7' > /dev/null; then + _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + else + # g++ 2.7 appears to require `-G' NOT `-shared' on this + # platform. + _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' + _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ + $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' + + # Commands to make compiler produce verbose output that lists + # what "hidden" libraries, object files and flags are used when + # linking a shared library. + output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' + fi + + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' + case $host_os in + solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; + *) + _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' + ;; + esac + fi + ;; + esac + ;; + + sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + sysv5* | sco3.2v5* | sco5v6*) + # Note: We can NOT use -z defs as we might desire, because we do not + # link with -lc, and that would cause any symbols used from libc to + # always be unresolved, which means just about no library would + # ever link correctly. If we're not using GNU ld we use -z text + # though, which does catch some bad symbols but isn't as heavy-handed + # as -z defs. + _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' + _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' + _LT_TAGVAR(archive_cmds_need_lc, $1)=no + _LT_TAGVAR(hardcode_shlibpath_var, $1)=no + _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' + _LT_TAGVAR(hardcode_libdir_separator, $1)=':' + _LT_TAGVAR(link_all_deplibs, $1)=yes + _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' + runpath_var='LD_RUN_PATH' + + case $cc_basename in + CC*) + _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ + '"$_LT_TAGVAR(old_archive_cmds, $1)" + _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ + '"$_LT_TAGVAR(reload_cmds, $1)" + ;; + *) + _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' + ;; + esac + ;; + + tandem*) + case $cc_basename in + NCC*) + # NonStop-UX NCC 3.20 + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + ;; + + vxworks*) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + + *) + # FIXME: insert proper C++ library support + _LT_TAGVAR(ld_shlibs, $1)=no + ;; + esac + + AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) + test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no + + _LT_TAGVAR(GCC, $1)="$GXX" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS + LDCXX=$LD + LD=$lt_save_LD + GCC=$lt_save_GCC + with_gnu_ld=$lt_save_with_gnu_ld + lt_cv_path_LDCXX=$lt_cv_path_LD + lt_cv_path_LD=$lt_save_path_LD + lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld + lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld +fi # test "$_lt_caught_CXX_error" != yes + +AC_LANG_POP +])# _LT_LANG_CXX_CONFIG + + +# _LT_FUNC_STRIPNAME_CNF +# ---------------------- +# func_stripname_cnf prefix suffix name +# strip PREFIX and SUFFIX off of NAME. +# PREFIX and SUFFIX must not contain globbing or regex special +# characters, hashes, percent signs, but SUFFIX may contain a leading +# dot (in which case that matches only a dot). +# +# This function is identical to the (non-XSI) version of func_stripname, +# except this one can be used by m4 code that may be executed by configure, +# rather than the libtool script. +m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl +AC_REQUIRE([_LT_DECL_SED]) +AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) +func_stripname_cnf () +{ + case ${2} in + .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; + *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; + esac +} # func_stripname_cnf +])# _LT_FUNC_STRIPNAME_CNF + +# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) +# --------------------------------- +# Figure out "hidden" library dependencies from verbose +# compiler output when linking a shared library. +# Parse the compiler output and extract the necessary +# objects, libraries and library flags. +m4_defun([_LT_SYS_HIDDEN_LIBDEPS], +[m4_require([_LT_FILEUTILS_DEFAULTS])dnl +AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl +# Dependencies to place before and after the object being linked: +_LT_TAGVAR(predep_objects, $1)= +_LT_TAGVAR(postdep_objects, $1)= +_LT_TAGVAR(predeps, $1)= +_LT_TAGVAR(postdeps, $1)= +_LT_TAGVAR(compiler_lib_search_path, $1)= + +dnl we can't use the lt_simple_compile_test_code here, +dnl because it contains code intended for an executable, +dnl not a library. It's possible we should let each +dnl tag define a new lt_????_link_test_code variable, +dnl but it's only used here... +m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF +int a; +void foo (void) { a = 0; } +_LT_EOF +], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF +class Foo +{ +public: + Foo (void) { a = 0; } +private: + int a; +}; +_LT_EOF +], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer*4 a + a=0 + return + end +_LT_EOF +], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF + subroutine foo + implicit none + integer a + a=0 + return + end +_LT_EOF +], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF +public class foo { + private int a; + public void bar (void) { + a = 0; + } +}; +_LT_EOF +], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF +package foo +func foo() { +} +_LT_EOF +]) + +_lt_libdeps_save_CFLAGS=$CFLAGS +case "$CC $CFLAGS " in #( +*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; +*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; +*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; +esac + +dnl Parse the compiler output and extract the necessary +dnl objects, libraries and library flags. +if AC_TRY_EVAL(ac_compile); then + # Parse the compiler output and extract the necessary + # objects, libraries and library flags. + + # Sentinel used to keep track of whether or not we are before + # the conftest object file. + pre_test_object_deps_done=no + + for p in `eval "$output_verbose_link_cmd"`; do + case ${prev}${p} in + + -L* | -R* | -l*) + # Some compilers place space between "-{L,R}" and the path. + # Remove the space. + if test $p = "-L" || + test $p = "-R"; then + prev=$p + continue + fi + + # Expand the sysroot to ease extracting the directories later. + if test -z "$prev"; then + case $p in + -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; + -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; + -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; + esac + fi + case $p in + =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; + esac + if test "$pre_test_object_deps_done" = no; then + case ${prev} in + -L | -R) + # Internal compiler library paths should come after those + # provided the user. The postdeps already come after the + # user supplied libs so there is no need to process them. + if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then + _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" + else + _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" + fi + ;; + # The "-l" case would never come before the object being + # linked, so don't bother handling this case. + esac + else + if test -z "$_LT_TAGVAR(postdeps, $1)"; then + _LT_TAGVAR(postdeps, $1)="${prev}${p}" + else + _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" + fi + fi + prev= + ;; + + *.lto.$objext) ;; # Ignore GCC LTO objects + *.$objext) + # This assumes that the test object file only shows up + # once in the compiler output. + if test "$p" = "conftest.$objext"; then + pre_test_object_deps_done=yes + continue + fi + + if test "$pre_test_object_deps_done" = no; then + if test -z "$_LT_TAGVAR(predep_objects, $1)"; then + _LT_TAGVAR(predep_objects, $1)="$p" + else + _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" + fi + else + if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then + _LT_TAGVAR(postdep_objects, $1)="$p" + else + _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" + fi + fi + ;; + + *) ;; # Ignore the rest. + + esac + done + + # Clean up. + rm -f a.out a.exe +else + echo "libtool.m4: error: problem compiling $1 test program" +fi + +$RM -f confest.$objext +CFLAGS=$_lt_libdeps_save_CFLAGS + +# PORTME: override above test on systems where it is broken +m4_if([$1], [CXX], +[case $host_os in +interix[[3-9]]*) + # Interix 3.5 installs completely hosed .la files for C++, so rather than + # hack all around it, let's just trust "g++" to DTRT. + _LT_TAGVAR(predep_objects,$1)= + _LT_TAGVAR(postdep_objects,$1)= + _LT_TAGVAR(postdeps,$1)= + ;; + +linux*) + case `$CC -V 2>&1 | sed 5q` in + *Sun\ C*) + # Sun C++ 5.9 + + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; + +solaris*) + case $cc_basename in + CC* | sunCC*) + # The more standards-conforming stlport4 library is + # incompatible with the Cstd library. Avoid specifying + # it if it's in CXXFLAGS. Ignore libCrun as + # -library=stlport4 depends on it. + case " $CXX $CXXFLAGS " in + *" -library=stlport4 "*) + solaris_use_stlport4=yes + ;; + esac + + # Adding this requires a known-good setup of shared libraries for + # Sun compiler versions before 5.6, else PIC objects from an old + # archive will be linked into the output, leading to subtle bugs. + if test "$solaris_use_stlport4" != yes; then + _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' + fi + ;; + esac + ;; +esac +]) + +case " $_LT_TAGVAR(postdeps, $1) " in +*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; +esac + _LT_TAGVAR(compiler_lib_search_dirs, $1)= +if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then + _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` +fi +_LT_TAGDECL([], [compiler_lib_search_dirs], [1], + [The directories searched by this compiler when creating a shared library]) +_LT_TAGDECL([], [predep_objects], [1], + [Dependencies to place before and after the objects being linked to + create a shared library]) +_LT_TAGDECL([], [postdep_objects], [1]) +_LT_TAGDECL([], [predeps], [1]) +_LT_TAGDECL([], [postdeps], [1]) +_LT_TAGDECL([], [compiler_lib_search_path], [1], + [The library search path used internally by the compiler when linking + a shared library]) +])# _LT_SYS_HIDDEN_LIBDEPS + + +# _LT_LANG_F77_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for a Fortran 77 compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_F77_CONFIG], +[AC_LANG_PUSH(Fortran 77) +if test -z "$F77" || test "X$F77" = "Xno"; then + _lt_disable_F77=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for f77 test sources. +ac_ext=f + +# Object file extension for compiled f77 test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the F77 compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_F77" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${F77-"f77"} + CFLAGS=$FFLAGS + compiler=$CC + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + GCC=$G77 + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$G77" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC="$lt_save_CC" + CFLAGS="$lt_save_CFLAGS" +fi # test "$_lt_disable_F77" != yes + +AC_LANG_POP +])# _LT_LANG_F77_CONFIG + + +# _LT_LANG_FC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for a Fortran compiler are +# suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_FC_CONFIG], +[AC_LANG_PUSH(Fortran) + +if test -z "$FC" || test "X$FC" = "Xno"; then + _lt_disable_FC=yes +fi + +_LT_TAGVAR(archive_cmds_need_lc, $1)=no +_LT_TAGVAR(allow_undefined_flag, $1)= +_LT_TAGVAR(always_export_symbols, $1)=no +_LT_TAGVAR(archive_expsym_cmds, $1)= +_LT_TAGVAR(export_dynamic_flag_spec, $1)= +_LT_TAGVAR(hardcode_direct, $1)=no +_LT_TAGVAR(hardcode_direct_absolute, $1)=no +_LT_TAGVAR(hardcode_libdir_flag_spec, $1)= +_LT_TAGVAR(hardcode_libdir_separator, $1)= +_LT_TAGVAR(hardcode_minus_L, $1)=no +_LT_TAGVAR(hardcode_automatic, $1)=no +_LT_TAGVAR(inherit_rpath, $1)=no +_LT_TAGVAR(module_cmds, $1)= +_LT_TAGVAR(module_expsym_cmds, $1)= +_LT_TAGVAR(link_all_deplibs, $1)=unknown +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds +_LT_TAGVAR(no_undefined_flag, $1)= +_LT_TAGVAR(whole_archive_flag_spec, $1)= +_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no + +# Source file extension for fc test sources. +ac_ext=${ac_fc_srcext-f} + +# Object file extension for compiled fc test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# No sense in running all these tests if we already determined that +# the FC compiler isn't working. Some variables (like enable_shared) +# are currently assumed to apply to all compilers on this platform, +# and will be corrupted by setting them based on a non-working compiler. +if test "$_lt_disable_FC" != yes; then + # Code to be used in simple compile tests + lt_simple_compile_test_code="\ + subroutine t + return + end +" + + # Code to be used in simple link tests + lt_simple_link_test_code="\ + program t + end +" + + # ltmain only uses $CC for tagged configurations so make sure $CC is set. + _LT_TAG_COMPILER + + # save warnings/boilerplate of simple test code + _LT_COMPILER_BOILERPLATE + _LT_LINKER_BOILERPLATE + + # Allow CC to be a program name with arguments. + lt_save_CC="$CC" + lt_save_GCC=$GCC + lt_save_CFLAGS=$CFLAGS + CC=${FC-"f95"} + CFLAGS=$FCFLAGS + compiler=$CC + GCC=$ac_cv_fc_compiler_gnu + + _LT_TAGVAR(compiler, $1)=$CC + _LT_CC_BASENAME([$compiler]) + + if test -n "$compiler"; then + AC_MSG_CHECKING([if libtool supports shared libraries]) + AC_MSG_RESULT([$can_build_shared]) + + AC_MSG_CHECKING([whether to build shared libraries]) + test "$can_build_shared" = "no" && enable_shared=no + + # On AIX, shared libraries and static libraries use the same namespace, and + # are all built from PIC. + case $host_os in + aix3*) + test "$enable_shared" = yes && enable_static=no + if test -n "$RANLIB"; then + archive_cmds="$archive_cmds~\$RANLIB \$lib" + postinstall_cmds='$RANLIB $lib' + fi + ;; + aix[[4-9]]*) + if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then + test "$enable_shared" = yes && enable_static=no + fi + ;; + esac + AC_MSG_RESULT([$enable_shared]) + + AC_MSG_CHECKING([whether to build static libraries]) + # Make sure either enable_shared or enable_static is yes. + test "$enable_shared" = yes || enable_static=yes + AC_MSG_RESULT([$enable_static]) + + _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" + _LT_TAGVAR(LD, $1)="$LD" + + ## CAVEAT EMPTOR: + ## There is no encapsulation within the following macros, do not change + ## the running order or otherwise move them around unless you know exactly + ## what you are doing... + _LT_SYS_HIDDEN_LIBDEPS($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_SYS_DYNAMIC_LINKER($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) + fi # test -n "$compiler" + + GCC=$lt_save_GCC + CC=$lt_save_CC + CFLAGS=$lt_save_CFLAGS +fi # test "$_lt_disable_FC" != yes + +AC_LANG_POP +])# _LT_LANG_FC_CONFIG + + +# _LT_LANG_GCJ_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Java Compiler compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GCJ_CONFIG], +[AC_REQUIRE([LT_PROG_GCJ])dnl +AC_LANG_SAVE + +# Source file extension for Java test sources. +ac_ext=java + +# Object file extension for compiled Java test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="class foo {}" + +# Code to be used in simple link tests +lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GCJ-"gcj"} +CFLAGS=$GCJFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# GCJ did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GCJ_CONFIG + + +# _LT_LANG_GO_CONFIG([TAG]) +# -------------------------- +# Ensure that the configuration variables for the GNU Go compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_GO_CONFIG], +[AC_REQUIRE([LT_PROG_GO])dnl +AC_LANG_SAVE + +# Source file extension for Go test sources. +ac_ext=go + +# Object file extension for compiled Go test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code="package main; func main() { }" + +# Code to be used in simple link tests +lt_simple_link_test_code='package main; func main() { }' + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC=$CC +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC=yes +CC=${GOC-"gccgo"} +CFLAGS=$GOFLAGS +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_TAGVAR(LD, $1)="$LD" +_LT_CC_BASENAME([$compiler]) + +# Go did not exist at the time GCC didn't implicitly link libc in. +_LT_TAGVAR(archive_cmds_need_lc, $1)=no + +_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds +_LT_TAGVAR(reload_flag, $1)=$reload_flag +_LT_TAGVAR(reload_cmds, $1)=$reload_cmds + +## CAVEAT EMPTOR: +## There is no encapsulation within the following macros, do not change +## the running order or otherwise move them around unless you know exactly +## what you are doing... +if test -n "$compiler"; then + _LT_COMPILER_NO_RTTI($1) + _LT_COMPILER_PIC($1) + _LT_COMPILER_C_O($1) + _LT_COMPILER_FILE_LOCKS($1) + _LT_LINKER_SHLIBS($1) + _LT_LINKER_HARDCODE_LIBPATH($1) + + _LT_CONFIG($1) +fi + +AC_LANG_RESTORE + +GCC=$lt_save_GCC +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_GO_CONFIG + + +# _LT_LANG_RC_CONFIG([TAG]) +# ------------------------- +# Ensure that the configuration variables for the Windows resource compiler +# are suitably defined. These variables are subsequently used by _LT_CONFIG +# to write the compiler configuration to `libtool'. +m4_defun([_LT_LANG_RC_CONFIG], +[AC_REQUIRE([LT_PROG_RC])dnl +AC_LANG_SAVE + +# Source file extension for RC test sources. +ac_ext=rc + +# Object file extension for compiled RC test sources. +objext=o +_LT_TAGVAR(objext, $1)=$objext + +# Code to be used in simple compile tests +lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' + +# Code to be used in simple link tests +lt_simple_link_test_code="$lt_simple_compile_test_code" + +# ltmain only uses $CC for tagged configurations so make sure $CC is set. +_LT_TAG_COMPILER + +# save warnings/boilerplate of simple test code +_LT_COMPILER_BOILERPLATE +_LT_LINKER_BOILERPLATE + +# Allow CC to be a program name with arguments. +lt_save_CC="$CC" +lt_save_CFLAGS=$CFLAGS +lt_save_GCC=$GCC +GCC= +CC=${RC-"windres"} +CFLAGS= +compiler=$CC +_LT_TAGVAR(compiler, $1)=$CC +_LT_CC_BASENAME([$compiler]) +_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes + +if test -n "$compiler"; then + : + _LT_CONFIG($1) +fi + +GCC=$lt_save_GCC +AC_LANG_RESTORE +CC=$lt_save_CC +CFLAGS=$lt_save_CFLAGS +])# _LT_LANG_RC_CONFIG + + +# LT_PROG_GCJ +# ----------- +AC_DEFUN([LT_PROG_GCJ], +[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], + [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], + [AC_CHECK_TOOL(GCJ, gcj,) + test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" + AC_SUBST(GCJFLAGS)])])[]dnl +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_GCJ], []) + + +# LT_PROG_GO +# ---------- +AC_DEFUN([LT_PROG_GO], +[AC_CHECK_TOOL(GOC, gccgo,) +]) + + +# LT_PROG_RC +# ---------- +AC_DEFUN([LT_PROG_RC], +[AC_CHECK_TOOL(RC, windres,) +]) + +# Old name: +AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_RC], []) + + +# _LT_DECL_EGREP +# -------------- +# If we don't have a new enough Autoconf to choose the best grep +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_EGREP], +[AC_REQUIRE([AC_PROG_EGREP])dnl +AC_REQUIRE([AC_PROG_FGREP])dnl +test -z "$GREP" && GREP=grep +_LT_DECL([], [GREP], [1], [A grep program that handles long lines]) +_LT_DECL([], [EGREP], [1], [An ERE matcher]) +_LT_DECL([], [FGREP], [1], [A literal string matcher]) +dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too +AC_SUBST([GREP]) +]) + + +# _LT_DECL_OBJDUMP +# -------------- +# If we don't have a new enough Autoconf to choose the best objdump +# available, choose the one first in the user's PATH. +m4_defun([_LT_DECL_OBJDUMP], +[AC_CHECK_TOOL(OBJDUMP, objdump, false) +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) +AC_SUBST([OBJDUMP]) +]) + +# _LT_DECL_DLLTOOL +# ---------------- +# Ensure DLLTOOL variable is set. +m4_defun([_LT_DECL_DLLTOOL], +[AC_CHECK_TOOL(DLLTOOL, dlltool, false) +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program]) +AC_SUBST([DLLTOOL]) +]) + +# _LT_DECL_SED +# ------------ +# Check for a fully-functional sed program, that truncates +# as few characters as possible. Prefer GNU sed if found. +m4_defun([_LT_DECL_SED], +[AC_PROG_SED +test -z "$SED" && SED=sed +Xsed="$SED -e 1s/^X//" +_LT_DECL([], [SED], [1], [A sed program that does not truncate output]) +_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], + [Sed that helps us avoid accidentally triggering echo(1) options like -n]) +])# _LT_DECL_SED + +m4_ifndef([AC_PROG_SED], [ +############################################################ +# NOTE: This macro has been submitted for inclusion into # +# GNU Autoconf as AC_PROG_SED. When it is available in # +# a released version of Autoconf we should remove this # +# macro and use it instead. # +############################################################ + +m4_defun([AC_PROG_SED], +[AC_MSG_CHECKING([for a sed that does not truncate output]) +AC_CACHE_VAL(lt_cv_path_SED, +[# Loop through the user's path and test for sed and gsed. +# Then use that list of sed's as ones to test for truncation. +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for lt_ac_prog in sed gsed; do + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then + lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" + fi + done + done +done +IFS=$as_save_IFS +lt_ac_max=0 +lt_ac_count=0 +# Add /usr/xpg4/bin/sed as it is typically found on Solaris +# along with /bin/sed that truncates output. +for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do + test ! -f $lt_ac_sed && continue + cat /dev/null > conftest.in + lt_ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >conftest.in + # Check for GNU sed and select it if it is found. + if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then + lt_cv_path_SED=$lt_ac_sed + break + fi + while true; do + cat conftest.in conftest.in >conftest.tmp + mv conftest.tmp conftest.in + cp conftest.in conftest.nl + echo >>conftest.nl + $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break + cmp -s conftest.out conftest.nl || break + # 10000 chars as input seems more than enough + test $lt_ac_count -gt 10 && break + lt_ac_count=`expr $lt_ac_count + 1` + if test $lt_ac_count -gt $lt_ac_max; then + lt_ac_max=$lt_ac_count + lt_cv_path_SED=$lt_ac_sed + fi + done +done +]) +SED=$lt_cv_path_SED +AC_SUBST([SED]) +AC_MSG_RESULT([$SED]) +])#AC_PROG_SED +])#m4_ifndef + +# Old name: +AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([LT_AC_PROG_SED], []) + + +# _LT_CHECK_SHELL_FEATURES +# ------------------------ +# Find out whether the shell is Bourne or XSI compatible, +# or has some other useful features. +m4_defun([_LT_CHECK_SHELL_FEATURES], +[AC_MSG_CHECKING([whether the shell understands some XSI constructs]) +# Try some XSI features +xsi_shell=no +( _lt_dummy="a/b/c" + test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ + = c,a/b,b/c, \ + && eval 'test $(( 1 + 1 )) -eq 2 \ + && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ + && xsi_shell=yes +AC_MSG_RESULT([$xsi_shell]) +_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) + +AC_MSG_CHECKING([whether the shell understands "+="]) +lt_shell_append=no +( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ + >/dev/null 2>&1 \ + && lt_shell_append=yes +AC_MSG_RESULT([$lt_shell_append]) +_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) + +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + lt_unset=unset +else + lt_unset=false +fi +_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl + +# test EBCDIC or ASCII +case `echo X|tr X '\101'` in + A) # ASCII based system + # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr + lt_SP2NL='tr \040 \012' + lt_NL2SP='tr \015\012 \040\040' + ;; + *) # EBCDIC based system + lt_SP2NL='tr \100 \n' + lt_NL2SP='tr \r\n \100\100' + ;; +esac +_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl +_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl +])# _LT_CHECK_SHELL_FEATURES + + +# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) +# ------------------------------------------------------ +# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and +# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. +m4_defun([_LT_PROG_FUNCTION_REPLACE], +[dnl { +sed -e '/^$1 ()$/,/^} # $1 /c\ +$1 ()\ +{\ +m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) +} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") +test 0 -eq $? || _lt_function_replace_fail=: +]) + + +# _LT_PROG_REPLACE_SHELLFNS +# ------------------------- +# Replace existing portable implementations of several shell functions with +# equivalent extended shell implementations where those features are available.. +m4_defun([_LT_PROG_REPLACE_SHELLFNS], +[if test x"$xsi_shell" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl + case ${1} in + */*) func_dirname_result="${1%/*}${2}" ;; + * ) func_dirname_result="${3}" ;; + esac + func_basename_result="${1##*/}"]) + + _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl + # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are + # positional parameters, so assign one to ordinary parameter first. + func_stripname_result=${3} + func_stripname_result=${func_stripname_result#"${1}"} + func_stripname_result=${func_stripname_result%"${2}"}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl + func_split_long_opt_name=${1%%=*} + func_split_long_opt_arg=${1#*=}]) + + _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl + func_split_short_opt_arg=${1#??} + func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) + + _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl + case ${1} in + *.lo) func_lo2o_result=${1%.lo}.${objext} ;; + *) func_lo2o_result=${1} ;; + esac]) + + _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) + + _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) + + _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) +fi + +if test x"$lt_shell_append" = xyes; then + _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) + + _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl + func_quote_for_eval "${2}" +dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ + eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) + + # Save a `func_append' function call where possible by direct use of '+=' + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +else + # Save a `func_append' function call even when '+=' is not available + sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ + && mv -f "$cfgfile.tmp" "$cfgfile" \ + || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") + test 0 -eq $? || _lt_function_replace_fail=: +fi + +if test x"$_lt_function_replace_fail" = x":"; then + AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) +fi +]) + +# _LT_PATH_CONVERSION_FUNCTIONS +# ----------------------------- +# Determine which file name conversion functions should be used by +# func_to_host_file (and, implicitly, by func_to_host_path). These are needed +# for certain cross-compile configurations and native mingw. +m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +AC_REQUIRE([AC_CANONICAL_BUILD])dnl +AC_MSG_CHECKING([how to convert $build file names to $host format]) +AC_CACHE_VAL(lt_cv_to_host_file_cmd, +[case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 + ;; + esac + ;; + *-*-cygwin* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin + ;; + *-*-cygwin* ) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; + * ) # otherwise, assume *nix + lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin + ;; + esac + ;; + * ) # unhandled hosts (and "normal" native builds) + lt_cv_to_host_file_cmd=func_convert_file_noop + ;; +esac +]) +to_host_file_cmd=$lt_cv_to_host_file_cmd +AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) +_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], + [0], [convert $build file names to $host format])dnl + +AC_MSG_CHECKING([how to convert $build file names to toolchain format]) +AC_CACHE_VAL(lt_cv_to_tool_file_cmd, +[#assume ordinary cross tools, or native build. +lt_cv_to_tool_file_cmd=func_convert_file_noop +case $host in + *-*-mingw* ) + case $build in + *-*-mingw* ) # actually msys + lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 + ;; + esac + ;; +esac +]) +to_tool_file_cmd=$lt_cv_to_tool_file_cmd +AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) +_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], + [0], [convert $build files to toolchain format])dnl +])# _LT_PATH_CONVERSION_FUNCTIONS diff --git a/m4/ltoptions.m4 b/m4/ltoptions.m4 new file mode 100644 index 00000000..5d9acd8e --- /dev/null +++ b/m4/ltoptions.m4 @@ -0,0 +1,384 @@ +# Helper functions for option handling. -*- Autoconf -*- +# +# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 7 ltoptions.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) + + +# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) +# ------------------------------------------ +m4_define([_LT_MANGLE_OPTION], +[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) + + +# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) +# --------------------------------------- +# Set option OPTION-NAME for macro MACRO-NAME, and if there is a +# matching handler defined, dispatch to it. Other OPTION-NAMEs are +# saved as a flag. +m4_define([_LT_SET_OPTION], +[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl +m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), + _LT_MANGLE_DEFUN([$1], [$2]), + [m4_warning([Unknown $1 option `$2'])])[]dnl +]) + + +# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) +# ------------------------------------------------------------ +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +m4_define([_LT_IF_OPTION], +[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) + + +# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) +# ------------------------------------------------------- +# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME +# are set. +m4_define([_LT_UNLESS_OPTIONS], +[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), + [m4_define([$0_found])])])[]dnl +m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 +])[]dnl +]) + + +# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) +# ---------------------------------------- +# OPTION-LIST is a space-separated list of Libtool options associated +# with MACRO-NAME. If any OPTION has a matching handler declared with +# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about +# the unknown option and exit. +m4_defun([_LT_SET_OPTIONS], +[# Set options +m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), + [_LT_SET_OPTION([$1], _LT_Option)]) + +m4_if([$1],[LT_INIT],[ + dnl + dnl Simply set some default values (i.e off) if boolean options were not + dnl specified: + _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no + ]) + _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no + ]) + dnl + dnl If no reference was made to various pairs of opposing options, then + dnl we run the default mode handler for the pair. For example, if neither + dnl `shared' nor `disable-shared' was passed, we enable building of shared + dnl archives by default: + _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) + _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) + _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], + [_LT_ENABLE_FAST_INSTALL]) + ]) +])# _LT_SET_OPTIONS + + +## --------------------------------- ## +## Macros to handle LT_INIT options. ## +## --------------------------------- ## + +# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) +# ----------------------------------------- +m4_define([_LT_MANGLE_DEFUN], +[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) + + +# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) +# ----------------------------------------------- +m4_define([LT_OPTION_DEFINE], +[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl +])# LT_OPTION_DEFINE + + +# dlopen +# ------ +LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes +]) + +AU_DEFUN([AC_LIBTOOL_DLOPEN], +[_LT_SET_OPTION([LT_INIT], [dlopen]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `dlopen' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) + + +# win32-dll +# --------- +# Declare package support for building win32 dll's. +LT_OPTION_DEFINE([LT_INIT], [win32-dll], +[enable_win32_dll=yes + +case $host in +*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) + AC_CHECK_TOOL(AS, as, false) + AC_CHECK_TOOL(DLLTOOL, dlltool, false) + AC_CHECK_TOOL(OBJDUMP, objdump, false) + ;; +esac + +test -z "$AS" && AS=as +_LT_DECL([], [AS], [1], [Assembler program])dnl + +test -z "$DLLTOOL" && DLLTOOL=dlltool +_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl + +test -z "$OBJDUMP" && OBJDUMP=objdump +_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl +])# win32-dll + +AU_DEFUN([AC_LIBTOOL_WIN32_DLL], +[AC_REQUIRE([AC_CANONICAL_HOST])dnl +_LT_SET_OPTION([LT_INIT], [win32-dll]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `win32-dll' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) + + +# _LT_ENABLE_SHARED([DEFAULT]) +# ---------------------------- +# implement the --enable-shared flag, and supports the `shared' and +# `disable-shared' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_SHARED], +[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([shared], + [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], + [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_shared=yes ;; + no) enable_shared=no ;; + *) + enable_shared=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_shared=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) + + _LT_DECL([build_libtool_libs], [enable_shared], [0], + [Whether or not to build shared libraries]) +])# _LT_ENABLE_SHARED + +LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) +]) + +AC_DEFUN([AC_DISABLE_SHARED], +[_LT_SET_OPTION([LT_INIT], [disable-shared]) +]) + +AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) +AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_SHARED], []) +dnl AC_DEFUN([AM_DISABLE_SHARED], []) + + + +# _LT_ENABLE_STATIC([DEFAULT]) +# ---------------------------- +# implement the --enable-static flag, and support the `static' and +# `disable-static' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_STATIC], +[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([static], + [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], + [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_static=yes ;; + no) enable_static=no ;; + *) + enable_static=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_static=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_static=]_LT_ENABLE_STATIC_DEFAULT) + + _LT_DECL([build_old_libs], [enable_static], [0], + [Whether or not to build static libraries]) +])# _LT_ENABLE_STATIC + +LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) + +# Old names: +AC_DEFUN([AC_ENABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) +]) + +AC_DEFUN([AC_DISABLE_STATIC], +[_LT_SET_OPTION([LT_INIT], [disable-static]) +]) + +AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) +AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AM_ENABLE_STATIC], []) +dnl AC_DEFUN([AM_DISABLE_STATIC], []) + + + +# _LT_ENABLE_FAST_INSTALL([DEFAULT]) +# ---------------------------------- +# implement the --enable-fast-install flag, and support the `fast-install' +# and `disable-fast-install' LT_INIT options. +# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. +m4_define([_LT_ENABLE_FAST_INSTALL], +[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl +AC_ARG_ENABLE([fast-install], + [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], + [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], + [p=${PACKAGE-default} + case $enableval in + yes) enable_fast_install=yes ;; + no) enable_fast_install=no ;; + *) + enable_fast_install=no + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for pkg in $enableval; do + IFS="$lt_save_ifs" + if test "X$pkg" = "X$p"; then + enable_fast_install=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) + +_LT_DECL([fast_install], [enable_fast_install], [0], + [Whether or not to optimize for fast installation])dnl +])# _LT_ENABLE_FAST_INSTALL + +LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) +LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) + +# Old names: +AU_DEFUN([AC_ENABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `fast-install' option into LT_INIT's first parameter.]) +]) + +AU_DEFUN([AC_DISABLE_FAST_INSTALL], +[_LT_SET_OPTION([LT_INIT], [disable-fast-install]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you put +the `disable-fast-install' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) +dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) + + +# _LT_WITH_PIC([MODE]) +# -------------------- +# implement the --with-pic flag, and support the `pic-only' and `no-pic' +# LT_INIT options. +# MODE is either `yes' or `no'. If omitted, it defaults to `both'. +m4_define([_LT_WITH_PIC], +[AC_ARG_WITH([pic], + [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], + [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], + [lt_p=${PACKAGE-default} + case $withval in + yes|no) pic_mode=$withval ;; + *) + pic_mode=default + # Look at the argument we got. We use all the common list separators. + lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," + for lt_pkg in $withval; do + IFS="$lt_save_ifs" + if test "X$lt_pkg" = "X$lt_p"; then + pic_mode=yes + fi + done + IFS="$lt_save_ifs" + ;; + esac], + [pic_mode=default]) + +test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) + +_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl +])# _LT_WITH_PIC + +LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) +LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) + +# Old name: +AU_DEFUN([AC_LIBTOOL_PICMODE], +[_LT_SET_OPTION([LT_INIT], [pic-only]) +AC_DIAGNOSE([obsolete], +[$0: Remove this warning and the call to _LT_SET_OPTION when you +put the `pic-only' option into LT_INIT's first parameter.]) +]) + +dnl aclocal-1.4 backwards compatibility: +dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) + +## ----------------- ## +## LTDL_INIT Options ## +## ----------------- ## + +m4_define([_LTDL_MODE], []) +LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], + [m4_define([_LTDL_MODE], [nonrecursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [recursive], + [m4_define([_LTDL_MODE], [recursive])]) +LT_OPTION_DEFINE([LTDL_INIT], [subproject], + [m4_define([_LTDL_MODE], [subproject])]) + +m4_define([_LTDL_TYPE], []) +LT_OPTION_DEFINE([LTDL_INIT], [installable], + [m4_define([_LTDL_TYPE], [installable])]) +LT_OPTION_DEFINE([LTDL_INIT], [convenience], + [m4_define([_LTDL_TYPE], [convenience])]) diff --git a/m4/ltsugar.m4 b/m4/ltsugar.m4 new file mode 100644 index 00000000..9000a057 --- /dev/null +++ b/m4/ltsugar.m4 @@ -0,0 +1,123 @@ +# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. +# Written by Gary V. Vaughan, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 6 ltsugar.m4 + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) + + +# lt_join(SEP, ARG1, [ARG2...]) +# ----------------------------- +# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their +# associated separator. +# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier +# versions in m4sugar had bugs. +m4_define([lt_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) +m4_define([_lt_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) + + +# lt_car(LIST) +# lt_cdr(LIST) +# ------------ +# Manipulate m4 lists. +# These macros are necessary as long as will still need to support +# Autoconf-2.59 which quotes differently. +m4_define([lt_car], [[$1]]) +m4_define([lt_cdr], +[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], + [$#], 1, [], + [m4_dquote(m4_shift($@))])]) +m4_define([lt_unquote], $1) + + +# lt_append(MACRO-NAME, STRING, [SEPARATOR]) +# ------------------------------------------ +# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. +# Note that neither SEPARATOR nor STRING are expanded; they are appended +# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). +# No SEPARATOR is output if MACRO-NAME was previously undefined (different +# than defined and empty). +# +# This macro is needed until we can rely on Autoconf 2.62, since earlier +# versions of m4sugar mistakenly expanded SEPARATOR but not STRING. +m4_define([lt_append], +[m4_define([$1], + m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) + + + +# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) +# ---------------------------------------------------------- +# Produce a SEP delimited list of all paired combinations of elements of +# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list +# has the form PREFIXmINFIXSUFFIXn. +# Needed until we can rely on m4_combine added in Autoconf 2.62. +m4_define([lt_combine], +[m4_if(m4_eval([$# > 3]), [1], + [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl +[[m4_foreach([_Lt_prefix], [$2], + [m4_foreach([_Lt_suffix], + ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, + [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) + + +# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) +# ----------------------------------------------------------------------- +# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited +# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. +m4_define([lt_if_append_uniq], +[m4_ifdef([$1], + [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], + [lt_append([$1], [$2], [$3])$4], + [$5])], + [lt_append([$1], [$2], [$3])$4])]) + + +# lt_dict_add(DICT, KEY, VALUE) +# ----------------------------- +m4_define([lt_dict_add], +[m4_define([$1($2)], [$3])]) + + +# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) +# -------------------------------------------- +m4_define([lt_dict_add_subkey], +[m4_define([$1($2:$3)], [$4])]) + + +# lt_dict_fetch(DICT, KEY, [SUBKEY]) +# ---------------------------------- +m4_define([lt_dict_fetch], +[m4_ifval([$3], + m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), + m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) + + +# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) +# ----------------------------------------------------------------- +m4_define([lt_if_dict_fetch], +[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], + [$5], + [$6])]) + + +# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) +# -------------------------------------------------------------- +m4_define([lt_dict_filter], +[m4_if([$5], [], [], + [lt_join(m4_quote(m4_default([$4], [[, ]])), + lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), + [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl +]) diff --git a/m4/ltversion.m4 b/m4/ltversion.m4 new file mode 100644 index 00000000..07a8602d --- /dev/null +++ b/m4/ltversion.m4 @@ -0,0 +1,23 @@ +# ltversion.m4 -- version numbers -*- Autoconf -*- +# +# Copyright (C) 2004 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004 +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# @configure_input@ + +# serial 3337 ltversion.m4 +# This file is part of GNU Libtool + +m4_define([LT_PACKAGE_VERSION], [2.4.2]) +m4_define([LT_PACKAGE_REVISION], [1.3337]) + +AC_DEFUN([LTVERSION_VERSION], +[macro_version='2.4.2' +macro_revision='1.3337' +_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) +_LT_DECL(, macro_revision, 0) +]) diff --git a/m4/lt~obsolete.m4 b/m4/lt~obsolete.m4 new file mode 100644 index 00000000..c573da90 --- /dev/null +++ b/m4/lt~obsolete.m4 @@ -0,0 +1,98 @@ +# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- +# +# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. +# Written by Scott James Remnant, 2004. +# +# This file is free software; the Free Software Foundation gives +# unlimited permission to copy and/or distribute it, with or without +# modifications, as long as this notice is preserved. + +# serial 5 lt~obsolete.m4 + +# These exist entirely to fool aclocal when bootstrapping libtool. +# +# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) +# which have later been changed to m4_define as they aren't part of the +# exported API, or moved to Autoconf or Automake where they belong. +# +# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN +# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us +# using a macro with the same name in our local m4/libtool.m4 it'll +# pull the old libtool.m4 in (it doesn't see our shiny new m4_define +# and doesn't know about Autoconf macros at all.) +# +# So we provide this file, which has a silly filename so it's always +# included after everything else. This provides aclocal with the +# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything +# because those macros already exist, or will be overwritten later. +# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. +# +# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. +# Yes, that means every name once taken will need to remain here until +# we give up compatibility with versions before 1.7, at which point +# we need to keep only those names which we still refer to. + +# This is to help aclocal find these macros, as it can't see m4_define. +AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) + +m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) +m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) +m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) +m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) +m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) +m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) +m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) +m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) +m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) +m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) +m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) +m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) +m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) +m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) +m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) +m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) +m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) +m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) +m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) +m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) +m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) +m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) +m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) +m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) +m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) +m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) +m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) +m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) +m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) +m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) +m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) +m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) +m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) +m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) +m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) +m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) +m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) +m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) +m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) +m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) +m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) +m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) +m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) +m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) +m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) +m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) +m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) +m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) +m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) +m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) +m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) +m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) +m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) +m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) +m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) diff --git a/man/Makefile.am b/man/Makefile.am new file mode 100644 index 00000000..f0d7027f --- /dev/null +++ b/man/Makefile.am @@ -0,0 +1,7 @@ +# +# man/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# + +SUBDIRS = man3 diff --git a/man/Makefile.in b/man/Makefile.in new file mode 100644 index 00000000..b013ad33 --- /dev/null +++ b/man/Makefile.in @@ -0,0 +1,596 @@ +# Makefile.in generated by automake 1.11.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# man/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = man +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUG_DEFINES = @DEBUG_DEFINES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTPMS_VERSION = @LIBTPMS_VERSION@ +LIBTPMS_VERSION_INFO = @LIBTPMS_VERSION_INFO@ +LIBTPMS_VER_MAJOR = @LIBTPMS_VER_MAJOR@ +LIBTPMS_VER_MICRO = @LIBTPMS_VER_MICRO@ +LIBTPMS_VER_MINOR = @LIBTPMS_VER_MINOR@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = man3 +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign man/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign man/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/man/man3/Makefile.am b/man/man3/Makefile.am new file mode 100644 index 00000000..0063c2e2 --- /dev/null +++ b/man/man3/Makefile.am @@ -0,0 +1,46 @@ +# +# man/man3/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# + + +man3_PODS = \ + TPM_IO_Hash_Start.pod \ + TPM_IO_TpmEstablished_Get.pod \ + TPMLIB_DecodeBlob.pod \ + TPMLIB_GetTPMProperty.pod \ + TPMLIB_GetVersion.pod \ + TPMLIB_MainInit.pod \ + TPMLIB_Process.pod \ + TPMLIB_RegisterCallbacks.pod \ + TPMLIB_VolatileAll_Store.pod \ + TPM_Malloc.pod + +man3_MANS = \ + TPM_Free.3 \ + TPM_IO_Hash_Data.3 \ + TPM_IO_Hash_End.3 \ + TPMLIB_Terminate.3 \ + TPM_Realloc.3 + +man3_MANS += \ + TPM_IO_Hash_Start.3 \ + TPM_IO_TpmEstablished_Get.3 \ + TPMLIB_DecodeBlob.3 \ + TPMLIB_GetTPMProperty.3 \ + TPMLIB_GetVersion.3 \ + TPMLIB_MainInit.3 \ + TPMLIB_Process.3 \ + TPMLIB_RegisterCallbacks.3 \ + TPMLIB_VolatileAll_Store.3 \ + TPM_Malloc.3 + + +%.3 : %.pod + @pod2man -r "libtpms" \ + -c "" \ + -n $(basename $@) \ + --section=3 $< > $@ + +EXTRA_DIST = $(man3_MANS) $(man3_PODS) diff --git a/man/man3/Makefile.in b/man/man3/Makefile.in new file mode 100644 index 00000000..ba7d1346 --- /dev/null +++ b/man/man3/Makefile.in @@ -0,0 +1,512 @@ +# Makefile.in generated by automake 1.11.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# man/man3/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +subdir = man/man3 +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +man3dir = $(mandir)/man3 +am__installdirs = "$(DESTDIR)$(man3dir)" +NROFF = nroff +MANS = $(man3_MANS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUG_DEFINES = @DEBUG_DEFINES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTPMS_VERSION = @LIBTPMS_VERSION@ +LIBTPMS_VERSION_INFO = @LIBTPMS_VERSION_INFO@ +LIBTPMS_VER_MAJOR = @LIBTPMS_VER_MAJOR@ +LIBTPMS_VER_MICRO = @LIBTPMS_VER_MICRO@ +LIBTPMS_VER_MINOR = @LIBTPMS_VER_MINOR@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +man3_PODS = \ + TPM_IO_Hash_Start.pod \ + TPM_IO_TpmEstablished_Get.pod \ + TPMLIB_DecodeBlob.pod \ + TPMLIB_GetTPMProperty.pod \ + TPMLIB_GetVersion.pod \ + TPMLIB_MainInit.pod \ + TPMLIB_Process.pod \ + TPMLIB_RegisterCallbacks.pod \ + TPMLIB_VolatileAll_Store.pod \ + TPM_Malloc.pod + +man3_MANS = TPM_Free.3 TPM_IO_Hash_Data.3 TPM_IO_Hash_End.3 \ + TPMLIB_Terminate.3 TPM_Realloc.3 TPM_IO_Hash_Start.3 \ + TPM_IO_TpmEstablished_Get.3 TPMLIB_DecodeBlob.3 \ + TPMLIB_GetTPMProperty.3 TPMLIB_GetVersion.3 TPMLIB_MainInit.3 \ + TPMLIB_Process.3 TPMLIB_RegisterCallbacks.3 \ + TPMLIB_VolatileAll_Store.3 TPM_Malloc.3 +EXTRA_DIST = $(man3_MANS) $(man3_PODS) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign man/man3/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign man/man3/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man3: $(man3_MANS) + @$(NORMAL_INSTALL) + @list1='$(man3_MANS)'; \ + list2=''; \ + test -n "$(man3dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.3[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ + done; } + +uninstall-man3: + @$(NORMAL_UNINSTALL) + @list='$(man3_MANS)'; test -n "$(man3dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir) +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @list='$(MANS)'; if test -n "$$list"; then \ + list=`for p in $$list; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ + if test -n "$$list" && \ + grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ + echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ + grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ + echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ + echo " typically \`make maintainer-clean' will remove them" >&2; \ + exit 1; \ + else :; fi; \ + else :; fi + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(MANS) +installdirs: + for dir in "$(DESTDIR)$(man3dir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-man + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man3 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-man + +uninstall-man: uninstall-man3 + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-man3 \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + uninstall uninstall-am uninstall-man uninstall-man3 + + +%.3 : %.pod + @pod2man -r "libtpms" \ + -c "" \ + -n $(basename $@) \ + --section=3 $< > $@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/man/man3/TPMLIB_DecodeBlob.3 b/man/man3/TPMLIB_DecodeBlob.3 new file mode 100644 index 00000000..f5f441d2 --- /dev/null +++ b/man/man3/TPMLIB_DecodeBlob.3 @@ -0,0 +1,179 @@ +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "TPMLIB_DECODEBLOB 1" +.TH TPMLIB_DECODEBLOB 1 "2011-08-30" "libtpms-0.5.1" "libtpms documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +TPMLIB_DecodeBlob \- Decode a base64\-encode TPM blob +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB\s-1TPM_RESULT\s0 TPMLIB_DecodeBlob(const char\fR *\fIbuffer\fR\fB, + enum TPMLIB_BlobType\fR \fItype\fR\fB, + unsigned char\fR **\fIresult\fR\fB + size_t\fR *\fIresult_len\fR\fB);\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fB\f(BITPMLIB_DecodeBlob()\fB\fR function is used to decode a base64\-encoded +\&\s-1TPM\s0 state blob. The caller must pass what type of blob is expected to be +decoded and following that the function will look for the start and +end markers of the data. +.PP +The following types of blobs are supported along with their start and +end markers: +.IP "\fB\s-1BLOB_TYPE_INITSTATE\s0\fR" 4 +.IX Item "BLOB_TYPE_INITSTATE" +\&'\-\-\-\-\-BEGIN \s-1INITSTATE\-\-\-\-\-\s0' marks the beginning of the base64\-encoded blob. +.Sp +\&'\-\-\-\-\-END \s-1INITSTATE\-\-\-\-\-\s0' marks the end of the base64\-encoded blob. +.PP +This function is useful when passing state to the \s-1TPM\s0 inside the +callback that is invoked to get the \s-1TPM\s0's state blob. +See \fITPMLIB_RegisterCallbacks\fR(3). +.SH "ERRORS" +.IX Header "ERRORS" +.IP "\fB\s-1TPM_SUCCESS\s0\fR" 4 +.IX Item "TPM_SUCCESS" +The function completed sucessfully. +.IP "\fB\s-1TPM_SIZE\s0\fR" 4 +.IX Item "TPM_SIZE" +The size of a requested buffer exceeds the limit or the +system is out of memory. +.IP "\fB\s-1TPM_FAIL\s0\fR" 4 +.IX Item "TPM_FAIL" +An error occurred while attempting to decode the blob. +.PP +For a complete list of \s-1TPM\s0 error codes please consult the include file +\&\fBlibtpms/tpm_error.h\fR +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBTPMLIB_MainInit\fR(3), \fBTPMLIB_RegisterCallbacks\fR(3) diff --git a/man/man3/TPMLIB_DecodeBlob.pod b/man/man3/TPMLIB_DecodeBlob.pod new file mode 100644 index 00000000..d346f1f1 --- /dev/null +++ b/man/man3/TPMLIB_DecodeBlob.pod @@ -0,0 +1,66 @@ +=head1 NAME + +TPMLIB_DecodeBlob - Decode a base64-encode TPM blob + +=head1 SYNOPSIS + +B<#include > + +B<#include > + +B *IB<, + enum TPMLIB_BlobType> IB<, + unsigned char> **IB< + size_t> *IB<);> + +=head1 DESCRIPTION + +The B function is used to decode a base64-encoded +TPM state blob. The caller must pass what type of blob is expected to be +decoded and following that the function will look for the start and +end markers of the data. + +The following types of blobs are supported along with their start and +end markers: + +=over 4 + +=item B + +'-----BEGIN INITSTATE-----' marks the beginning of the base64-encoded blob. + +'-----END INITSTATE-----' marks the end of the base64-encoded blob. + +=back + +This function is useful when passing state to the TPM inside the +callback that is invoked to get the TPM's state blob. +See I(3). + +=head1 ERRORS + +=over 4 + +=item B + +The function completed sucessfully. + +=item B + +The size of a requested buffer exceeds the limit or the +system is out of memory. + +=item B + +An error occurred while attempting to decode the blob. + +=back + +For a complete list of TPM error codes please consult the include file +B + +=head1 SEE ALSO + +B(3), B(3) + +=cut diff --git a/man/man3/TPMLIB_GetTPMProperty.3 b/man/man3/TPMLIB_GetTPMProperty.3 new file mode 100644 index 00000000..cf75528f --- /dev/null +++ b/man/man3/TPMLIB_GetTPMProperty.3 @@ -0,0 +1,247 @@ +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "TPMLIB_GETTPMPROPERTY 1" +.TH TPMLIB_GETTPMPROPERTY 1 "2011-03-24" "libtpms-0.5.1" "libtpms documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +TPMLIB_GetTPMProperty \- Get a runtime property of the TPM +.SH "LIBRARY" +.IX Header "LIBRARY" +\&\s-1TPM\s0 library (libtpms, \-ltpms) +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fB#include +.PP +\&\fB\s-1TPM_RESULT\s0 TPMLIB_GetTPMProperty(enum TPMLIB_TPMProperty, int *result);\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fB\f(BITPMLIB_GetTPMProperty()\fB\fR call is used to retrieve run-time parameters +of the \s-1TPM\s0 such as the number of authorization sessions it can hold or +the maximum sizes of the permanent state, savestate or volatile state blobs. +.PP +This function can be called before or after the \s-1TPM\s0 has been created. +The current implementation of libtpms will return the same value before +and after the \s-1TPM\s0 was started. +.PP +The following properties have been defined: +.IP "\fB\s-1TPMPROP_TPM_RSA_KEY_LENGTH_MAX\s0\fR" 4 +.IX Item "TPMPROP_TPM_RSA_KEY_LENGTH_MAX" +The maximum size of an \s-1RSA\s0 key. +.IP "\fB\s-1TPMPROP_TPM_BUFFER_MAX\s0\fR" 4 +.IX Item "TPMPROP_TPM_BUFFER_MAX" +The maximum sizes of the \s-1TPM\s0 command and result buffers. +.IP "\fB\s-1TPMPROP_TPM_KEY_HANDLES\s0\fR" 4 +.IX Item "TPMPROP_TPM_KEY_HANDLES" +The number of key slots. +.IP "\fB\s-1TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES\s0\fR" 4 +.IX Item "TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES" +The number of owner-evict keys. +.IP "\fB\s-1TPMPROP_TPM_MIN_AUTH_SESSIONS\s0\fR" 4 +.IX Item "TPMPROP_TPM_MIN_AUTH_SESSIONS" +The number of authorization sessions. +.IP "\fB\s-1TPMPROP_TPM_MIN_TRANS_SESSIONS\s0\fR" 4 +.IX Item "TPMPROP_TPM_MIN_TRANS_SESSIONS" +The number of transport sessions. +.IP "\fB\s-1TPMPROP_TPM_MIN_DAA_SESSIONS\s0\fR" 4 +.IX Item "TPMPROP_TPM_MIN_DAA_SESSIONS" +The number of \s-1DAA\s0 sessions. +.IP "\fB\s-1TPMPROP_TPM_MIN_SESSION_LIST\s0\fR" 4 +.IX Item "TPMPROP_TPM_MIN_SESSION_LIST" +The size of the session list. +.IP "\fB\s-1TPMPROP_TPM_MIN_COUNTERS\s0\fR" 4 +.IX Item "TPMPROP_TPM_MIN_COUNTERS" +The number of monotonic counters. +.IP "\fB\s-1TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN\s0\fR" 4 +.IX Item "TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN" +The number of family entries. +.IP "\fB\s-1TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN\s0\fR" 4 +.IX Item "TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN" +The number of delegate entries. +.IP "\fB\s-1TPMPROP_TPM_SPACE_SAFETY_MARGIN\s0\fR" 4 +.IX Item "TPMPROP_TPM_SPACE_SAFETY_MARGIN" +The space saftey margin used for the worst-case sizes of the savestate and +volatile state blobs. This safety marging is not used for the size of the +permanent data blob. +.IP "\fB\s-1TPMPROP_TPM_MAX_NV_SPACE\s0\fR" 4 +.IX Item "TPMPROP_TPM_MAX_NV_SPACE" +The maximum size of the permanent data blob. +.IP "\fB\s-1TPMPROP_TPM_MAX_SAVESTATE_SPACE\s0\fR" 4 +.IX Item "TPMPROP_TPM_MAX_SAVESTATE_SPACE" +The maximum size of the savestate blob (includes the space safety margin). +.IP "\fB\s-1TPMPROP_TPM_MAX_VOLATILESTATE_SPACE\s0\fR" 4 +.IX Item "TPMPROP_TPM_MAX_VOLATILESTATE_SPACE" +The maximum size of the volatile state blob (includes the space saferty +margin). +.SH "ERRORS" +.IX Header "ERRORS" +.IP "\fB\s-1TPM_SUCCESS\s0\fR" 4 +.IX Item "TPM_SUCCESS" +The function completed sucessfully. +.IP "\fB\s-1TPM_FAIL\s0\fR" 4 +.IX Item "TPM_FAIL" +An undefined property was queried. +.PP +For a complete list of \s-1TPM\s0 error codes please consult the include file +\&\fBlibtpms/tpm_error.h\fR +.SH "EXAMPLE" +.IX Header "EXAMPLE" +.Vb 1 +\& #include +\& +\& #include +\& #include +\& +\& int main(void) { +\& TPM_RESULT res; +\& int result; +\& int rc = 0; +\& +\& if (TPMLIB_MainInit() != TPM_SUCCESS) { +\& fprintf(stderr, "Could not start the TPM.\en"); +\& return 1; +\& } +\& +\& if (TPMLIB_GetTPMProperty(TPMPROP_TPM_RSA_KEY_LENGTH_MAX, &result) +\& != TPM_SUCCESS) { +\& fprintf(stderr, "Could not read the max. size of RSA keys.\en"); +\& goto err_exit; +\& } +\& +\& fprintf(stdout, "Max. size of RSA keys: %d\en", result); +\& +\& err_exit: +\& TPMLIB_Terminate(); +\& +\& return 0; +\& } +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBTPMLIB_MainInit\fR(3), \fBTPMLIB_Terminate\fR(3), +\&\fBTPMLIB_Process\fR(3), \fBTPMLIB_RegisterCallbacks\fR(3), \fBTPMLIB_GetVersion\fR(3) diff --git a/man/man3/TPMLIB_GetTPMProperty.pod b/man/man3/TPMLIB_GetTPMProperty.pod new file mode 100644 index 00000000..f971ec0c --- /dev/null +++ b/man/man3/TPMLIB_GetTPMProperty.pod @@ -0,0 +1,147 @@ +=head1 NAME + +TPMLIB_GetTPMProperty - Get a runtime property of the TPM + +=head1 LIBRARY + +TPM library (libtpms, -ltpms) + +=head1 SYNOPSIS + +B<#include > + +B + +=head1 DESCRIPTION + +The B call is used to retrieve run-time parameters +of the TPM such as the number of authorization sessions it can hold or +the maximum sizes of the permanent state, savestate or volatile state blobs. + +This function can be called before or after the TPM has been created. +The current implementation of libtpms will return the same value before +and after the TPM was started. + +The following properties have been defined: + +=over 4 + +=item B + +The maximum size of an RSA key. + +=item B + +The maximum sizes of the TPM command and result buffers. + +=item B + +The number of key slots. + +=item B + +The number of owner-evict keys. + +=item B + +The number of authorization sessions. + +=item B + +The number of transport sessions. + +=item B + +The number of DAA sessions. + +=item B + +The size of the session list. + +=item B + +The number of monotonic counters. + +=item B + +The number of family entries. + +=item B + +The number of delegate entries. + +=item B + +The space saftey margin used for the worst-case sizes of the savestate and +volatile state blobs. This safety marging is not used for the size of the +permanent data blob. + +=item B + +The maximum size of the permanent data blob. + +=item B + +The maximum size of the savestate blob (includes the space safety margin). + +=item B + +The maximum size of the volatile state blob (includes the space saferty +margin). + +=back + +=head1 ERRORS + +=over 4 + +=item B + +The function completed sucessfully. + +=item B + +An undefined property was queried. + +=back + +For a complete list of TPM error codes please consult the include file +B + +=head1 EXAMPLE + + #include + + #include + #include + + int main(void) { + TPM_RESULT res; + int result; + int rc = 0; + + if (TPMLIB_MainInit() != TPM_SUCCESS) { + fprintf(stderr, "Could not start the TPM.\n"); + return 1; + } + + if (TPMLIB_GetTPMProperty(TPMPROP_TPM_RSA_KEY_LENGTH_MAX, &result) + != TPM_SUCCESS) { + fprintf(stderr, "Could not read the max. size of RSA keys.\n"); + goto err_exit; + } + + fprintf(stdout, "Max. size of RSA keys: %d\n", result); + + err_exit: + TPMLIB_Terminate(); + + return 0; + } + +=head1 SEE ALSO + +B(3), B(3), +B(3), B(3), B(3) + +=cut diff --git a/man/man3/TPMLIB_GetVersion.3 b/man/man3/TPMLIB_GetVersion.3 new file mode 100644 index 00000000..2cc3910e --- /dev/null +++ b/man/man3/TPMLIB_GetVersion.3 @@ -0,0 +1,157 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.if n .na +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "TPMLIB_GETVERSION 1" +.TH TPMLIB_GETVERSION 1 "2011-03-09" "libtpms-0.5.1" "libtpms documentation" +.SH "NAME" +TPMLIB_GetVersion \- Get the version of the TPM library +.SH "LIBRARY" +.IX Header "LIBRARY" +\&\s-1TPM\s0 library (libtpms, \-ltpms) +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fB#include +.PP +\&\fBuint32_t TPMLIB_GetVersion(void);\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fB\f(BITPMLIB_GetVersion()\fB\fR function returns the libtpms library version. +The \s-1TPM\s0 library version is formatted as follows: +.PP +.Vb 3 +\& Bits 0 - 7 : revision of the library +\& Bits 8 -15 : minor version number of the library +\& Bits 16-23 : major version number of the library +.Ve +.PP +V0.5.1 is therefore represented as 0x00000501. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBTPMLIB_MainInit\fR(3), \fBTPMLIB_Terminate\fR(3) diff --git a/man/man3/TPMLIB_GetVersion.pod b/man/man3/TPMLIB_GetVersion.pod new file mode 100644 index 00000000..3a5a4764 --- /dev/null +++ b/man/man3/TPMLIB_GetVersion.pod @@ -0,0 +1,30 @@ +=head1 NAME + +TPMLIB_GetVersion - Get the version of the TPM library + +=head1 LIBRARY + +TPM library (libtpms, -ltpms) + +=head1 SYNOPSIS + +B<#include > + +B + +=head1 DESCRIPTION + +The B function returns the libtpms library version. +The TPM library version is formatted as follows: + + Bits 0 - 7 : revision of the library + Bits 8 -15 : minor version number of the library + Bits 16-23 : major version number of the library + +V0.5.1 is therefore represented as 0x00000501. + +=head1 SEE ALSO + +B(3), B(3) + +=cut diff --git a/man/man3/TPMLIB_MainInit.3 b/man/man3/TPMLIB_MainInit.3 new file mode 100644 index 00000000..f0fe2b59 --- /dev/null +++ b/man/man3/TPMLIB_MainInit.3 @@ -0,0 +1,211 @@ +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "TPMLIB_MAININIT 1" +.TH TPMLIB_MAININIT 1 "2011-08-30" "libtpms-0.5.1" "libtpms documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +TPMLIB_MainInit \- Initialize the TPM +.PP +TPMLIB_Terminate \- Terminate the TPM +.SH "LIBRARY" +.IX Header "LIBRARY" +\&\s-1TPM\s0 library (libtpms, \-ltpms) +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB\s-1TPM_RESULT\s0 TPMLIB_MainInit(void);\fR +.PP +\&\fB\s-1TPM_RESULT\s0 TPMLIB_Terminate(void);\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fB\f(BITPMLIB_MainInit()\fB\fR and \fB\f(BITPMLIB_Terminate()\fB\fR functions are used +to initialize and terminate the \s-1TPM\s0 respectively. The \fB\f(BITPMLIB_MainInit()\fB\fR +function must be called before the \s-1TPM\s0 processes any \s-1TPM\s0 command. +The \fB\f(BITPMLIB_Terminate()\fB\fR function is called to free all the internal +resources (memory allocations) the \s-1TPM\s0 has used and must be called after +the last \s-1TPM\s0 command was processed by the \s-1TPM\s0. The \fB\f(BITPMLIB_MainInit()\fB\fR +function can then be called again. +.SH "ERRORS" +.IX Header "ERRORS" +.IP "\fB\s-1TPM_SUCCESS\s0\fR" 4 +.IX Item "TPM_SUCCESS" +The function completed sucessfully. +.IP "\fB\s-1TPM_FAIL\s0\fR" 4 +.IX Item "TPM_FAIL" +General failure. +.PP +For a complete list of \s-1TPM\s0 error codes please consult the include file +\&\fBlibtpms/tpm_error.h\fR +.SH "EXAMPLE" +.IX Header "EXAMPLE" +.Vb 1 +\& #include +\& +\& #include +\& #include +\& #include +\& +\& int main(void) { +\& TPM_RESULT res; +\& unsigned char *respbuffer = NULL; +\& uint32_t resp_size = 0; +\& uint32_t respbufsize = 0; +\& unsigned char *command; +\& uint32_t command_size; +\& +\& [...] +\& +\& if (TPMLIB_MainInit() != TPM_SUCCESS) { +\& fprintf(stderr, "Could not start the TPM.\en"); +\& return 1; +\& } +\& +\& [...] +\& /* build TPM command */ +\& [...] +\& +\& res = TPMLIB_Process(&respbuffer, &resp_size, +\& &respbufsize, +\& command, command_size); +\& [...] +\& +\& TPMLIB_Terminate(); +\& +\& return 0; +\& } +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBTPMLIB_Process\fR(3), \fBTPMLIB_RegisterCallbacks\fR(3), \fBTPMLIB_GetVersion\fR(3) +\&\fBTPMLIB_GetTPMProperty\fR(3), \fBTPMLIB_DecodeBlob\fR(3) diff --git a/man/man3/TPMLIB_MainInit.pod b/man/man3/TPMLIB_MainInit.pod new file mode 100644 index 00000000..2f38e974 --- /dev/null +++ b/man/man3/TPMLIB_MainInit.pod @@ -0,0 +1,92 @@ +=head1 NAME + +TPMLIB_MainInit - Initialize the TPM + +TPMLIB_Terminate - Terminate the TPM + +=head1 LIBRARY + +TPM library (libtpms, -ltpms) + +=head1 SYNOPSIS + +B<#include > + +B<#include > + +B<#include > + +B + +B + +=head1 DESCRIPTION + +The B and B functions are used +to initialize and terminate the TPM respectively. The B +function must be called before the TPM processes any TPM command. +The B function is called to free all the internal +resources (memory allocations) the TPM has used and must be called after +the last TPM command was processed by the TPM. The B +function can then be called again. + +=head1 ERRORS + +=over 4 + +=item B + +The function completed sucessfully. + +=item B + +General failure. + +=back + +For a complete list of TPM error codes please consult the include file +B + +=head1 EXAMPLE + + #include + + #include + #include + #include + + int main(void) { + TPM_RESULT res; + unsigned char *respbuffer = NULL; + uint32_t resp_size = 0; + uint32_t respbufsize = 0; + unsigned char *command; + uint32_t command_size; + + [...] + + if (TPMLIB_MainInit() != TPM_SUCCESS) { + fprintf(stderr, "Could not start the TPM.\n"); + return 1; + } + + [...] + /* build TPM command */ + [...] + + res = TPMLIB_Process(&respbuffer, &resp_size, + &respbufsize, + command, command_size); + [...] + + TPMLIB_Terminate(); + + return 0; + } + +=head1 SEE ALSO + +B(3), B(3), B(3) +B(3), B(3) + +=cut diff --git a/man/man3/TPMLIB_Process.3 b/man/man3/TPMLIB_Process.3 new file mode 100644 index 00000000..c1451792 --- /dev/null +++ b/man/man3/TPMLIB_Process.3 @@ -0,0 +1,227 @@ +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "TPMLIB_PROCESS 1" +.TH TPMLIB_PROCESS 1 "2011-02-17" "libtpms-0.5.1" "libtpms documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +TPMLIB_Process \- process a TPM command +.SH "LIBRARY" +.IX Header "LIBRARY" +\&\s-1TPM\s0 library (libtpms, \-ltpms) +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB\s-1TPM_RESULT\s0 TPMLIB_Process(unsigned char\fR **\fIrespbuffer\fR\fB, + uint32_t\fR *\fIresp_size\fR\fB, + uint32_t\fR *\fIrespbufsize\fR\fB, + unsigned char\fR *\fIcommand\fR\fB, + uint32_t\fR \fIcommand_size\fR\fB);\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fB\f(BITPMLIB_Process()\fB\fR function is used to send \s-1TPM\s0 commands to the \s-1TPM\s0 +and receive the results. +.PP +The \fIcommand\fR parameter provides the buffer for the \s-1TPM\s0 command and +the \fIcommand_size\fR the number of valid \s-1TPM\s0 command bytes within that buffer. +.PP +The \fIrespbuffer\fR is a pointer to a buffer where the \s-1TPM\s0 will return its +result. If no buffer is given (\fIrespbuffer\fR is \s-1NULL\s0), the \s-1TPM\s0 will +allocate a buffer. The parameter \fIresp_size\fR returns the number of valid +\&\s-1TPM\s0 response bytes in the buffer. The number of valid bytes in the response +is guranteed to not exceed the maximum I/O buffer size. Use the +\&\fI\fITPMLIB_GetTPMProperty()\fI\fR \s-1API\s0 and parameter \fI\s-1TPMPROP_TPM_BUFFER_MAX\s0\fR for +getting the maximum size. +The user must indicate the size of a provided buffer with the \fIrespbufsize\fR +parameter. If the buffer is not big enough for the response, the \s-1TPM\s0 will +free the provided buffer and allocate one of sufficient size and adapt +\&\fIrespbufsize\fR. The returned buffer is only subject to size restrictions +as explained for \fI\fITPM_Malloc()\fI\fR. +.SH "ERRORS" +.IX Header "ERRORS" +.IP "\fB\s-1TPM_SUCCESS\s0\fR" 4 +.IX Item "TPM_SUCCESS" +The function completed sucessfully. +.IP "\fB\s-1TPM_FAIL\s0\fR" 4 +.IX Item "TPM_FAIL" +General failure. +.PP +For a complete list of \s-1TPM\s0 error codes please consult the include file +\&\fBlibtpms/tpm_error.h\fR +.SH "EXAMPLE" +.IX Header "EXAMPLE" +.Vb 1 +\& #include +\& +\& #include +\& #include +\& #include +\& +\& static unsigned char TPM_Startup_ST_CLEAR[] = { +\& 0x00, 0xC1, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x99, +\& 0x00, TPM_ST_CLEAR +\& }; +\& +\& int main(void) { +\& TPM_RESULT res; +\& unsigned char *respbuffer = NULL; +\& uint32_t resp_size = 0; +\& uint32_t respbufsize = 0; +\& unsigned char *command; +\& uint32_t command_size; +\& +\& [...] +\& +\& if (TPMLIB_MainInit() != TPM_SUCCESS) { +\& fprintf(stderr, "Could not start the TPM.\en"); +\& return 1; +\& } +\& +\& [...] +\& /* build TPM command */ +\& command = TPM_Startup_ST_CLEAR; +\& command_size = sizeof(TPM_Startup_ST_CLEAR); +\& [...] +\& +\& res = TPMLIB_Process(&respbuffer, &resp_size, +\& &respbufsize, +\& command, command_size); +\& [...] +\& +\& TPMLIB_Terminate(); +\& +\& return 0; +\& } +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBTPMLIB_MainInit\fR(3), \fBTPMLIB_Terminate\fR(3), \fBTPMLIB_RegisterCallbacks\fR(3) +\&\fBTPMLIB_GetTPMProperty\fR(3), \fBTPMLIB_Malloc\fR(3), \fBTPMLIB_Realloc\fR(3) diff --git a/man/man3/TPMLIB_Process.pod b/man/man3/TPMLIB_Process.pod new file mode 100644 index 00000000..913a7189 --- /dev/null +++ b/man/man3/TPMLIB_Process.pod @@ -0,0 +1,108 @@ +=head1 NAME + +TPMLIB_Process - process a TPM command + +=head1 LIBRARY + +TPM library (libtpms, -ltpms) + +=head1 SYNOPSIS + +B<#include > + +B<#include > + +B **IB<, + uint32_t> *IB<, + uint32_t> *IB<, + unsigned char> *IB<, + uint32_t> IB<);> + +=head1 DESCRIPTION + +The B function is used to send TPM commands to the TPM +and receive the results. + +The I parameter provides the buffer for the TPM command and +the I the number of valid TPM command bytes within that buffer. + +The I is a pointer to a buffer where the TPM will return its +result. If no buffer is given (I is NULL), the TPM will +allocate a buffer. The parameter I returns the number of valid +TPM response bytes in the buffer. The number of valid bytes in the response +is guranteed to not exceed the maximum I/O buffer size. Use the +I API and parameter I for +getting the maximum size. +The user must indicate the size of a provided buffer with the I +parameter. If the buffer is not big enough for the response, the TPM will +free the provided buffer and allocate one of sufficient size and adapt +I. The returned buffer is only subject to size restrictions +as explained for I. + +=head1 ERRORS + +=over 4 + +=item B + +The function completed sucessfully. + +=item B + +General failure. + +=back + +For a complete list of TPM error codes please consult the include file +B + +=head1 EXAMPLE + + #include + + #include + #include + #include + + static unsigned char TPM_Startup_ST_CLEAR[] = { + 0x00, 0xC1, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x99, + 0x00, TPM_ST_CLEAR + }; + + int main(void) { + TPM_RESULT res; + unsigned char *respbuffer = NULL; + uint32_t resp_size = 0; + uint32_t respbufsize = 0; + unsigned char *command; + uint32_t command_size; + + [...] + + if (TPMLIB_MainInit() != TPM_SUCCESS) { + fprintf(stderr, "Could not start the TPM.\n"); + return 1; + } + + [...] + /* build TPM command */ + command = TPM_Startup_ST_CLEAR; + command_size = sizeof(TPM_Startup_ST_CLEAR); + [...] + + res = TPMLIB_Process(&respbuffer, &resp_size, + &respbufsize, + command, command_size); + [...] + + TPMLIB_Terminate(); + + return 0; + } + +=head1 SEE ALSO + +B(3), B(3), B(3) +B(3), B(3), B(3) + +=cut diff --git a/man/man3/TPMLIB_RegisterCallbacks.3 b/man/man3/TPMLIB_RegisterCallbacks.3 new file mode 100644 index 00000000..8c5093ac --- /dev/null +++ b/man/man3/TPMLIB_RegisterCallbacks.3 @@ -0,0 +1,378 @@ +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "TPMLIB_REGISTERCALLBACKS 1" +.TH TPMLIB_REGISTERCALLBACKS 1 "2011-10-12" "libtpms-0.5.1" "libtpms documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +TPMLIB_RegisterCallbacks \- Register callbacks for implementing customized +behavior of certain functions +.SH "LIBRARY" +.IX Header "LIBRARY" +\&\s-1TPM\s0 library (libtpms, \-ltpms) +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB\s-1TPM_RESULT\s0 TPMLIB_RegisterCallbacks(struct tpmlibrary_callbacks *);\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fB\f(BITPMLIB_RegisterCallbacks()\fB\fR functions allows to register several +callback functions with libtpms that enable a user to implement customized +behavior of several library-internal functions. This feature will typically +be used if the behavior of the provided internal functions is not as needed. +An example would be that libtpms writes all data into files with certain names. +If, however, the data needs to be written into a special type of storage +the user will register callbacks with the library that are invoked when +the \s-1TPM\s0 needs to write, read or delete data from storage and the user may +then implement custom behavior in these functions. +.PP +The following shows the data structure used for registering the callbacks. +.PP +.Vb 10 +\& struct libtpms_callbacks { +\& int sizeOfStruct; +\& TPM_RESULT (*tpm_nvram_init)(void); +\& TPM_RESULT (*tpm_nvram_loaddata)(unsigned char **data, +\& uint32_t *length, +\& uint32_t tpm_number, +\& const char *name); +\& TPM_RESULT (*tpm_nvram_storedata)(const unsigned char *data, +\& uint32_t length, +\& uint32_t tpm_number, +\& const char *name); +\& TPM_RESULT (*tpm_nvram_deletename)(uint32_t tpm_number, +\& const char *name, +\& TPM_BOOL mustExist); +\& TPM_RESULT (*tpm_io_init)(void); +\& TPM_RESULT (*tpm_io_getlocality)(TPM_MODIFIER_INDICATOR *localityModifer, +\& uint32_t tpm_number); +\& TPM_RESULT (*tpm_io_getphysicalpresence)(TPM_BOOL *physicalPresence, +\& uint32_t tpm_number); +\& }; +.Ve +.PP +Currently 7 callbacks are supported. If a callback pointer in the above +structure is set to \s-1NULL\s0 the default library-internal implementation +of that function will be used. +.PP +If one of the callbacks in either the \fItpm_nvram\fR or \fItpm_io\fR group is +set, then all of the callbacks in the respective group should +be implemented. +.IP "\fBtpm_nvram_init\fR" 4 +.IX Item "tpm_nvram_init" +This function is called before any access to persitent storage is done. It +allows the user to perform initialization of access to persitent storage. +.Sp +Upon success this function should return \fB\s-1TPM_SUCCESS\s0\fR, a failure code +otherwise. +.Sp +The default implementation requires that the environment variable +\&\fI\s-1TPM_PATH\s0\fR is set and points to a directory where the \s-1TPM\s0's state +can be written to. If the variable is not set, it will return \fB\s-1TPM_FAIL\s0\fR +and the initialization of the \s-1TPM\s0 in \fB\f(BITPMLIB_MainInit()\fB\fR will fail. +.IP "\fBtpm_nvram_loaddata\fR" 4 +.IX Item "tpm_nvram_loaddata" +This function is called when the \s-1TPM\s0 wants to load state from persistent +storage. The implementing function must allocate a buffer (\fIdata\fR) +and return it to the \s-1TPM\s0 along with the length of the buffer (\fIlength\fR). +The \fItpm_number\fR is always 0 and can be ignored. +The \fIname\fR parameter is either one of \fB\s-1TPM_SAVESTATE_NAME\s0\fR, +\&\fB\s-1TPM_VOLATILESTATE_NAME\s0\fR, or \fB\s-1TPM_PERMANENT_ALL_NAME\s0\fR and indicates +which one of the 3 types of state is supposed to be loaded. +.Sp +Upon success this function should return \fB\s-1TPM_SUCCESS\s0\fR, a failure code +otherwise. +.Sp +The default implementation writes the \s-1TPM\s0's state into files in a directory +where the \fI\s-1TPM_PATH\s0\fR environment variable pointed to when +\&\fB\f(BITPMLIB_MainInit()\fB\fR was executed. Failure to write the \s-1TPM\s0's state into +files will put the \s-1TPM\s0 into failure mode. +.IP "\fBtpm_nvram_storedata\fR" 4 +.IX Item "tpm_nvram_storedata" +This function is called when the \s-1TPM\s0 wants to store state to persistent +storage. The \fIdata\fR and \fIlength\fR parameters provide the data to be +stored and the number of bytes. The implementing function must not +free the \fIdata\fR buffer. +The \fItpm_number\fR is always 0 and can be ignored. +The \fIname\fR parameter is either one of \fB\s-1TPM_SAVESTATE_NAME\s0\fR, +\&\fB\s-1TPM_VOLATILESTATE_NAME\s0\fR, or \fB\s-1TPM_PERMANENT_ALL_NAME\s0\fR and indicates +which one of the 3 types of state is supposed to be stored. +.Sp +Upon success this function should return \fB\s-1TPM_SUCCESS\s0\fR, a failure code +otherwise. +.Sp +The default implementation reads the \s-1TPM\s0's state from files in a directory +where the \fI\s-1TPM_PATH\s0\fR environment variable pointed to when +\&\fB\f(BITPMLIB_MainInit()\fB\fR was executed. Failure to read the \s-1TPM\s0's state from +files may put the \s-1TPM\s0 into failure mode. +.IP "\fBtpm_nvram_deletename\fR" 4 +.IX Item "tpm_nvram_deletename" +This function is called when the \s-1TPM\s0 wants to delete state on persistent +storage. +The \fItpm_number\fR is always 0 and can be ignored. +The \fIname\fR parameter is either one of \fB\s-1TPM_SAVESTATE_NAME\s0\fR, +\&\fB\s-1TPM_VOLATILESTATE_NAME\s0\fR, or \fB\s-1TPM_PERMANENT_ALL_NAME\s0\fR and indicates +which one of the 3 types of state is supposed to be deleted. +The \fImustExist\fR parameter indicates wheteher the given data must exist +and the implementing function should return \fB\s-1TPM_FAIL\s0\fR if the data did +not exist. +.Sp +Upon success this function should return \fB\s-1TPM_SUCCESS\s0\fR, a failure code +otherwise. +.Sp +The default implementation deletes the \s-1TPM\s0's state files in a directory +where the \fI\s-1TPM_PATH\s0\fR environment variable pointed to when +\&\fB\f(BITPMLIB_MainInit()\fB\fR was executed. Failure to delete the \s-1TPM\s0's state +files may put the \s-1TPM\s0 into failure mode. +.IP "\fBtpm_io_init\fR" 4 +.IX Item "tpm_io_init" +This function is called to initialize the \s-1IO\s0 subsystem of the \s-1TPM\s0. +.Sp +Upon success this function should return \fB\s-1TPM_SUCCESS\s0\fR, a failure code +otherwise. +.Sp +The default implementation simply returns \fB\s-1TPM_SUCCESS\s0\fR. +.IP "\fBtpm_io_getlocality\fR" 4 +.IX Item "tpm_io_getlocality" +This function is called when the \s-1TPM\s0 needs to determine the locality +under which a command is supposed to be executed. The implementing function +should return the number of the locality by writing it into the +\&\fBlocalityModifier\fR pointer. +.Sp +Upon success this function should return \fB\s-1TPM_SUCCESS\s0\fR, a failure code +otherwise. +.Sp +The default implementation returns 0 as the locality. +.IP "\fBtpm_io_getphysicalpresence\fR" 4 +.IX Item "tpm_io_getphysicalpresence" +This function is called when the \s-1TPM\s0 needs to determine whether physical +presence has been asserted. The implementing function should write either +\&\fB\s-1TRUE\s0\fR or \fB\s-1FALSE\s0\fR into the physicalPresence pointer. +.Sp +Upon success this function should return \fB\s-1TPM_SUCCESS\s0\fR, a failure code +otherwise. +.Sp +The default implementation returns \fB\s-1FALSE\s0\fR for physical presence. +.SH "RETURN VALUE" +.IX Header "RETURN VALUE" +Upon successful completion, \fB\f(BITPMLIB_MainInit()\fB\fR returns \fB\s-1TPM_SUCCESS\s0\fR, +an error value otherwise. +.SH "ERRORS" +.IX Header "ERRORS" +.IP "\fB\s-1TPM_SUCCESS\s0\fR" 4 +.IX Item "TPM_SUCCESS" +The function completed sucessfully. +.IP "\fB\s-1TPM_FAIL\s0\fR" 4 +.IX Item "TPM_FAIL" +General failure. +.PP +For a complete list of \s-1TPM\s0 error codes please consult the include file +\&\fBlibtpms/tpm_error.h\fR +.SH "EXAMPLE" +.IX Header "EXAMPLE" +.Vb 3 +\& #include +\& #include +\& #include +\& +\& static TPM_MODIFIER_INDICATOR locality; +\& +\& static TPM_RESULT mytpm_io_init(void) +\& { +\& return TPM_SUCCESS; +\& } +\& +\& static TPM_RESULT tpm_io_getlocality(TPM_MODIFIER_INDICATOR *locModif) +\& { +\& *locModif = locality; +\& +\& return TPM_SUCCESS: +\& } +\& +\& static TPM_RESULT mytpm_io_getphysicalpresence(TPM_BOOL *phyPres) +\& { +\& *physicalPresence = FALSE; +\& +\& return TPM_SUCCESS; +\& } +\& +\& int main(void) { +\& TPM_RESULT res; +\& unsigned char *respbuffer; +\& uint32_t resp_size; +\& uint32_t respbufsize; +\& unsigned char *command; +\& uint32_t command_size; +\& +\& struct libtpms_callbacks cbs = { +\& .sizeOfStruct = sizeof(struct libtpms_callbacks), +\& .tpm_nvram_init = NULL, +\& .tpm_nvram_loaddata = NULL, +\& .tpm_nvram_storedata = NULL, +\& .tpm_nvram_deletename = NULL, +\& .tpm_io_init = mytpm_io_init, +\& .tpm_io_getlocality = mytpm_io_getlocality, +\& .tpm_io_getphysicalpresence = mytpm_io_getphysicalpresence, +\& }; +\& +\& +\& [...] +\& +\& if (TPMLIB_RegisterCallbacks(cbs) != TPM_SUCCESS) { +\& fprintf(stderr, "Could not register the callbacks.\en"); +\& return 1; +\& } +\& +\& if (TPMLIB_MainInit()) != TPM_SUCCESS) { +\& fprintf(stderr, "Could not start the TPM.\en"); +\& return 1; +\& } +\& +\& [...] +\& /* build TPM command */ +\& [...] +\& +\& res = TPMLIB_Process(&respbuffer, &resp_size, +\& &respbufsize, +\& command, command_size); +\& [...] +\& +\& TPMLIB_Terminate(); +\& +\& return 0; +\& } +.Ve +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBTPMLIB_Process\fR(3), \fBTPMLIB_MainInit\fR(3), \fBTPMLIB_Terminate\fR(3), +\&\fBTPMLIB_DecodeBlobs\fR(3) diff --git a/man/man3/TPMLIB_RegisterCallbacks.pod b/man/man3/TPMLIB_RegisterCallbacks.pod new file mode 100644 index 00000000..e83314a2 --- /dev/null +++ b/man/man3/TPMLIB_RegisterCallbacks.pod @@ -0,0 +1,272 @@ + + +=head1 NAME + +TPMLIB_RegisterCallbacks - Register callbacks for implementing customized +behavior of certain functions + +=head1 LIBRARY + +TPM library (libtpms, -ltpms) + +=head1 SYNOPSIS + +B<#include > + +B<#include > + +B<#include > + +B + +=head1 DESCRIPTION + +The B functions allows to register several +callback functions with libtpms that enable a user to implement customized +behavior of several library-internal functions. This feature will typically +be used if the behavior of the provided internal functions is not as needed. +An example would be that libtpms writes all data into files with certain names. +If, however, the data needs to be written into a special type of storage +the user will register callbacks with the library that are invoked when +the TPM needs to write, read or delete data from storage and the user may +then implement custom behavior in these functions. + +The following shows the data structure used for registering the callbacks. + + struct libtpms_callbacks { + int sizeOfStruct; + TPM_RESULT (*tpm_nvram_init)(void); + TPM_RESULT (*tpm_nvram_loaddata)(unsigned char **data, + uint32_t *length, + uint32_t tpm_number, + const char *name); + TPM_RESULT (*tpm_nvram_storedata)(const unsigned char *data, + uint32_t length, + uint32_t tpm_number, + const char *name); + TPM_RESULT (*tpm_nvram_deletename)(uint32_t tpm_number, + const char *name, + TPM_BOOL mustExist); + TPM_RESULT (*tpm_io_init)(void); + TPM_RESULT (*tpm_io_getlocality)(TPM_MODIFIER_INDICATOR *localityModifer, + uint32_t tpm_number); + TPM_RESULT (*tpm_io_getphysicalpresence)(TPM_BOOL *physicalPresence, + uint32_t tpm_number); + }; + +Currently 7 callbacks are supported. If a callback pointer in the above +structure is set to NULL the default library-internal implementation +of that function will be used. + +If one of the callbacks in either the I or I group is +set, then all of the callbacks in the respective group should +be implemented. + +=over 4 + +=item B + +This function is called before any access to persitent storage is done. It +allows the user to perform initialization of access to persitent storage. + +Upon success this function should return B, a failure code +otherwise. + +The default implementation requires that the environment variable +I is set and points to a directory where the TPM's state +can be written to. If the variable is not set, it will return B +and the initialization of the TPM in B will fail. + +=item B + +This function is called when the TPM wants to load state from persistent +storage. The implementing function must allocate a buffer (I) +and return it to the TPM along with the length of the buffer (I). +The I is always 0 and can be ignored. +The I parameter is either one of B, +B, or B and indicates +which one of the 3 types of state is supposed to be loaded. + +Upon success this function should return B, a failure code +otherwise. + +The default implementation writes the TPM's state into files in a directory +where the I environment variable pointed to when +B was executed. Failure to write the TPM's state into +files will put the TPM into failure mode. + + +=item B + +This function is called when the TPM wants to store state to persistent +storage. The I and I parameters provide the data to be +stored and the number of bytes. The implementing function must not +free the I buffer. +The I is always 0 and can be ignored. +The I parameter is either one of B, +B, or B and indicates +which one of the 3 types of state is supposed to be stored. + +Upon success this function should return B, a failure code +otherwise. + +The default implementation reads the TPM's state from files in a directory +where the I environment variable pointed to when +B was executed. Failure to read the TPM's state from +files may put the TPM into failure mode. + +=item B + +This function is called when the TPM wants to delete state on persistent +storage. +The I is always 0 and can be ignored. +The I parameter is either one of B, +B, or B and indicates +which one of the 3 types of state is supposed to be deleted. +The I parameter indicates wheteher the given data must exist +and the implementing function should return B if the data did +not exist. + +Upon success this function should return B, a failure code +otherwise. + +The default implementation deletes the TPM's state files in a directory +where the I environment variable pointed to when +B was executed. Failure to delete the TPM's state +files may put the TPM into failure mode. + +=item B + +This function is called to initialize the IO subsystem of the TPM. + +Upon success this function should return B, a failure code +otherwise. + +The default implementation simply returns B. + +=item B + +This function is called when the TPM needs to determine the locality +under which a command is supposed to be executed. The implementing function +should return the number of the locality by writing it into the +B pointer. + +Upon success this function should return B, a failure code +otherwise. + +The default implementation returns 0 as the locality. + +=item B + +This function is called when the TPM needs to determine whether physical +presence has been asserted. The implementing function should write either +B or B into the physicalPresence pointer. + +Upon success this function should return B, a failure code +otherwise. + +The default implementation returns B for physical presence. + +=back + +=head1 RETURN VALUE + +Upon successful completion, B returns B, +an error value otherwise. + +=head1 ERRORS + +=over 4 + +=item B + +The function completed sucessfully. + +=item B + +General failure. + +=back + +For a complete list of TPM error codes please consult the include file +B + +=head1 EXAMPLE + + #include + #include + #include + + static TPM_MODIFIER_INDICATOR locality; + + static TPM_RESULT mytpm_io_init(void) + { + return TPM_SUCCESS; + } + + static TPM_RESULT tpm_io_getlocality(TPM_MODIFIER_INDICATOR *locModif) + { + *locModif = locality; + + return TPM_SUCCESS: + } + + static TPM_RESULT mytpm_io_getphysicalpresence(TPM_BOOL *phyPres) + { + *physicalPresence = FALSE; + + return TPM_SUCCESS; + } + + int main(void) { + TPM_RESULT res; + unsigned char *respbuffer; + uint32_t resp_size; + uint32_t respbufsize; + unsigned char *command; + uint32_t command_size; + + struct libtpms_callbacks cbs = { + .sizeOfStruct = sizeof(struct libtpms_callbacks), + .tpm_nvram_init = NULL, + .tpm_nvram_loaddata = NULL, + .tpm_nvram_storedata = NULL, + .tpm_nvram_deletename = NULL, + .tpm_io_init = mytpm_io_init, + .tpm_io_getlocality = mytpm_io_getlocality, + .tpm_io_getphysicalpresence = mytpm_io_getphysicalpresence, + }; + + + [...] + + if (TPMLIB_RegisterCallbacks(cbs) != TPM_SUCCESS) { + fprintf(stderr, "Could not register the callbacks.\n"); + return 1; + } + + if (TPMLIB_MainInit()) != TPM_SUCCESS) { + fprintf(stderr, "Could not start the TPM.\n"); + return 1; + } + + [...] + /* build TPM command */ + [...] + + res = TPMLIB_Process(&respbuffer, &resp_size, + &respbufsize, + command, command_size); + [...] + + TPMLIB_Terminate(); + + return 0; + } + +=head1 SEE ALSO + +B(3), B(3), B(3), +B(3) + +=cut diff --git a/man/man3/TPMLIB_Terminate.3 b/man/man3/TPMLIB_Terminate.3 new file mode 100644 index 00000000..83a9c84b --- /dev/null +++ b/man/man3/TPMLIB_Terminate.3 @@ -0,0 +1 @@ +.so man3/TPMLIB_MainInit.3 \ No newline at end of file diff --git a/man/man3/TPMLIB_VolatileAll_Store.3 b/man/man3/TPMLIB_VolatileAll_Store.3 new file mode 100644 index 00000000..dafbca1a --- /dev/null +++ b/man/man3/TPMLIB_VolatileAll_Store.3 @@ -0,0 +1,164 @@ +.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32 +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sh \" Subsection heading +.br +.if t .Sp +.ne 5 +.PP +\fB\\$1\fR +.PP +.. +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. | will give a +.\" real vertical bar. \*(C+ will give a nicer C++. Capital omega is used to +.\" do unbreakable dashes and therefore won't be available. \*(C` and \*(C' +.\" expand to `' in nroff, nothing in troff, for use with C<>. +.tr \(*W-|\(bv\*(Tr +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.if \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.\" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.hy 0 +.if n .na +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "TPMLIB_VOLATILEALL_STORE 1" +.TH TPMLIB_VOLATILEALL_STORE 1 "2011-03-09" "libtpms-0.5.1" "libtpms documentation" +.SH "NAME" +TPMLIB_VolatileAll_Store \- store all volatile state of the TPM in a buffer +.SH "LIBRARY" +.IX Header "LIBRARY" +\&\s-1TPM\s0 library (libtpms, \-ltpms) +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB\s-1TPM_RESULT\s0 TPMLIB_VolatileAll_Store(unsigned char **buffer, + uint32_t *buflen);\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fB\f(BITPMLIB_VolatileAll_Store()\fB\fR function is used to get the volatile +state of the \s-1TPM\s0. The function will allocate a \fIbuffer\fR and return +the number of bytes of state information in the \fIbuflen\fR variable. +.SH "ERRORS" +.IX Header "ERRORS" +.IP "\fB\s-1TPM_SUCCESS\s0\fR" 4 +.IX Item "TPM_SUCCESS" +The function completed sucessfully. +.IP "\fB\s-1TPM_FAIL\s0\fR" 4 +.IX Item "TPM_FAIL" +General failure. +.PP +For a complete list of \s-1TPM\s0 error codes please consult the include file +\&\fBlibtpms/tpm_error.h\fR +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBTPMLIB_MainInit\fR(3), \fBTPMLIB_Terminate\fR(3), \fBTPMLIB_RegisterCallbacks\fR(3) diff --git a/man/man3/TPMLIB_VolatileAll_Store.pod b/man/man3/TPMLIB_VolatileAll_Store.pod new file mode 100644 index 00000000..4d6e9de5 --- /dev/null +++ b/man/man3/TPMLIB_VolatileAll_Store.pod @@ -0,0 +1,45 @@ +=head1 NAME + +TPMLIB_VolatileAll_Store - store all volatile state of the TPM in a buffer + +=head1 LIBRARY + +TPM library (libtpms, -ltpms) + +=head1 SYNOPSIS + +B<#include > + +B<#include > + +B + +=head1 DESCRIPTION + +The B function is used to get the volatile +state of the TPM. The function will allocate a I and return +the number of bytes of state information in the I variable. + +=head1 ERRORS + +=over 4 + +=item B + +The function completed sucessfully. + +=item B + +General failure. + +=back + +For a complete list of TPM error codes please consult the include file +B + +=head1 SEE ALSO + +B(3), B(3), B(3) + +=cut diff --git a/man/man3/TPM_Free.3 b/man/man3/TPM_Free.3 new file mode 100644 index 00000000..d8bddfdd --- /dev/null +++ b/man/man3/TPM_Free.3 @@ -0,0 +1 @@ +.so man3/TPM_Malloc.3 diff --git a/man/man3/TPM_IO_Hash_Data.3 b/man/man3/TPM_IO_Hash_Data.3 new file mode 100644 index 00000000..f0f4e94a --- /dev/null +++ b/man/man3/TPM_IO_Hash_Data.3 @@ -0,0 +1 @@ +.so man3/TPM_IO_Hash_Start.3 \ No newline at end of file diff --git a/man/man3/TPM_IO_Hash_End.3 b/man/man3/TPM_IO_Hash_End.3 new file mode 100644 index 00000000..f0f4e94a --- /dev/null +++ b/man/man3/TPM_IO_Hash_End.3 @@ -0,0 +1 @@ +.so man3/TPM_IO_Hash_Start.3 \ No newline at end of file diff --git a/man/man3/TPM_IO_Hash_Start.3 b/man/man3/TPM_IO_Hash_Start.3 new file mode 100644 index 00000000..72c583b5 --- /dev/null +++ b/man/man3/TPM_IO_Hash_Start.3 @@ -0,0 +1,194 @@ +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "TPM_IO_HASH_START 1" +.TH TPM_IO_HASH_START 1 "2011-02-02" "libtpms-0.5.1" "libtpms documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +TPM_IO_Hash_Start \- indicate the beginging of a TPM TIS hash operation +.PP +TPM_IO_Hash_Data \- hash the provided data +.PP +TPM_IO_Hash_End \- indicate the end of a TPM TIS hash operation +.SH "LIBRARY" +.IX Header "LIBRARY" +\&\s-1TPM\s0 library (libtpms, \-ltpms) +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB\s-1TPM_RESULT\s0 TPM_IO_Hash_Start(void);\fR +.PP +\&\fB\s-1TPM_RESULT\s0 TPM_IO_Hash_Data(const unsigned char\fR *\fIdata\fR\fB, + uint32_t\fR \fIdata_length\fR\fB);\fR +.PP +\&\fB\s-1TPM_RESULT\s0 TPM_IO_Hash_End(void);\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fB\f(BITPM_IO_Hash_Start()\fB\fR function can be used by an implementation of the +\&\s-1TPM\s0 \s-1TIS\s0 hardware interface to indicate the beginning of a hash operation. +Following the \s-1TPM\s0 \s-1TIS\s0 interface specification it resets several PCRs and +terminates existing transport sessions. +The \fB\f(BITPM_IO_Hash_Data()\fB\fR function is used to send the data to be hashed to +the \s-1TPM\s0. +The \fB\f(BITPM_IO_Hash_End()\fB\fR function calculates the final hash and stores it +in the locality 4 \s-1PCR\s0. +The 3 functions must be called in the order they were explained. +.PP +The implementation of the above functions handles all TPM-internal actions +such as the setting and clearing of permanent flags and PCRs and the +calculation of the hash. Any functionality related to the \s-1TPM\s0's \s-1TIS\s0 interface +and the handling of flags, locality and state has to be implemented by the +caller. +.SH "ERRORS" +.IX Header "ERRORS" +.IP "\fB\s-1TPM_SUCCESS\s0\fR" 4 +.IX Item "TPM_SUCCESS" +The function completed sucessfully. +.IP "\fB\s-1TPM_FAIL\s0\fR" 4 +.IX Item "TPM_FAIL" +General failure. +.IP "\fB\s-1TPM_INVALID_POSTINIT\s0\fR" 4 +.IX Item "TPM_INVALID_POSTINIT" +The \fB\f(BITPM_IO_Hash_Start()\fB\fR function was called before the \s-1TPM\s0 received +a TPM_Startup command. +.IP "\fB\s-1TPM_SHA_THREAD\s0\fR" 4 +.IX Item "TPM_SHA_THREAD" +The \fB\f(BITPM_IO_Hash_Data()\fB\fR or \fB\f(BITPM_IO_Hash_End()\fB\fR functions were called before +the \fB\f(BITPM_IO_Hash_Start()\fB\fR function. +.PP +For a complete list of \s-1TPM\s0 error codes please consult the include file +\&\fBlibtpms/tpm_error.h\fR +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBTPMLIB_MainInit\fR(3), \fBTPMLIB_Terminate\fR(3), \fBTPMLIB_RegisterCallbacks\fR(3), +\&\fBTPMLIB_Process\fR(3) diff --git a/man/man3/TPM_IO_Hash_Start.pod b/man/man3/TPM_IO_Hash_Start.pod new file mode 100644 index 00000000..7d8b4339 --- /dev/null +++ b/man/man3/TPM_IO_Hash_Start.pod @@ -0,0 +1,78 @@ +=head1 NAME + +TPM_IO_Hash_Start - indicate the beginging of a TPM TIS hash operation + +TPM_IO_Hash_Data - hash the provided data + +TPM_IO_Hash_End - indicate the end of a TPM TIS hash operation + +=head1 LIBRARY + +TPM library (libtpms, -ltpms) + +=head1 SYNOPSIS + +B<#include > + +B<#include > + +B<#include > + +B + +B *IB<, + uint32_t> IB<);> + +B + +=head1 DESCRIPTION + +The B function can be used by an implementation of the +TPM TIS hardware interface to indicate the beginning of a hash operation. +Following the TPM TIS interface specification it resets several PCRs and +terminates existing transport sessions. +The B function is used to send the data to be hashed to +the TPM. +The B function calculates the final hash and stores it +in the locality 4 PCR. +The 3 functions must be called in the order they were explained. + +The implementation of the above functions handles all TPM-internal actions +such as the setting and clearing of permanent flags and PCRs and the +calculation of the hash. Any functionality related to the TPM's TIS interface +and the handling of flags, locality and state has to be implemented by the +caller. + +=head1 ERRORS + +=over 4 + +=item B + +The function completed sucessfully. + +=item B + +General failure. + +=item B + +The B function was called before the TPM received +a TPM_Startup command. + +=item B + +The B or B functions were called before +the B function. + +=back + +For a complete list of TPM error codes please consult the include file +B + +=head1 SEE ALSO + +B(3), B(3), B(3), +B(3) + +=cut diff --git a/man/man3/TPM_IO_TpmEstablished_Get.3 b/man/man3/TPM_IO_TpmEstablished_Get.3 new file mode 100644 index 00000000..7120197d --- /dev/null +++ b/man/man3/TPM_IO_TpmEstablished_Get.3 @@ -0,0 +1,165 @@ +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "TPM_IO_TPMESTABLISHED_GET 1" +.TH TPM_IO_TPMESTABLISHED_GET 1 "2011-02-17" "libtpms-0.5.1" "libtpms documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +TPM_IO_TpmEstablished_Get \- get the value of the TPMEstablished flag +.SH "LIBRARY" +.IX Header "LIBRARY" +\&\s-1TPM\s0 library (libtpms, \-ltpms) +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB\s-1TPM_RESULT\s0 TPM_IO_TpmEstablished_Get(\s-1TPM_BOOL\s0\fR *\fItpmEstablished\fR\fB);\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fB\f(BITPM_IO_TpmEstablished_Get()\fB\fR function returns the value of the +TPMEstablished flag of the \s-1TPM\s0's permanent data. +.SH "ERRORS" +.IX Header "ERRORS" +.IP "\fB\s-1TPM_SUCCESS\s0\fR" 4 +.IX Item "TPM_SUCCESS" +The function completed sucessfully. +.IP "\fB\s-1TPM_FAIL\s0\fR" 4 +.IX Item "TPM_FAIL" +General failure. +.PP +For a complete list of \s-1TPM\s0 error codes please consult the include file +\&\fBlibtpms/tpm_error.h\fR +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBTPMLIB_MainInit\fR(3), \fBTPMLIB_Terminate\fR(3), \fBTPMLIB_RegisterCallbacks\fR(3), +\&\fBTPMLIB_Process\fR(3), \fBTPM_IO_Hash_Start\fR(3), \fBTPM_IO_Hash_End\fR(3), +\&\fBTPM_IO_Hash_Data\fR(3) diff --git a/man/man3/TPM_IO_TpmEstablished_Get.pod b/man/man3/TPM_IO_TpmEstablished_Get.pod new file mode 100644 index 00000000..1c7f28f6 --- /dev/null +++ b/man/man3/TPM_IO_TpmEstablished_Get.pod @@ -0,0 +1,47 @@ +=head1 NAME + +TPM_IO_TpmEstablished_Get - get the value of the TPMEstablished flag + +=head1 LIBRARY + +TPM library (libtpms, -ltpms) + +=head1 SYNOPSIS + +B<#include > + +B<#include > + +B<#include > + +B *IB<);> + +=head1 DESCRIPTION + +The B function returns the value of the +TPMEstablished flag of the TPM's permanent data. + +=head1 ERRORS + +=over 4 + +=item B + +The function completed sucessfully. + +=item B + +General failure. + +=back + +For a complete list of TPM error codes please consult the include file +B + +=head1 SEE ALSO + +B(3), B(3), B(3), +B(3), B(3), B(3), +B(3) + +=cut diff --git a/man/man3/TPM_Malloc.3 b/man/man3/TPM_Malloc.3 new file mode 100644 index 00000000..8d8e300e --- /dev/null +++ b/man/man3/TPM_Malloc.3 @@ -0,0 +1,190 @@ +.\" Automatically generated by Pod::Man 2.23 (Pod::Simple 3.14) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is turned on, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.ie \nF \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. nr % 0 +. rr F +.\} +.el \{\ +. de IX +.. +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "TPM_MALLOC 1" +.TH TPM_MALLOC 1 "2011-10-12" "libtpms-0.5.1" "libtpms documentation" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +TPM_Malloc \- Allocate memory +.PP +TPM_Realloc \- Reallocate memory +.PP +TPM_Free \- Free memory +.SH "SYNOPSIS" +.IX Header "SYNOPSIS" +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB#include +.PP +\&\fB\s-1TPM_RESULT\s0 TPM_Malloc(unsigned char\fR **\fIbuffer\fR\fB, + uint32_t\fR \fIsize\fR\fB);\fR +.PP +\&\fB\s-1TPM_RESULT\s0 TPM_Realloc(unsigned char\fR **\fIbuffer\fR\fB, + uint32_t\fR \fIsize\fR\fB);\fR +.PP +\&\fBvoid TPM_Free(unsigned char\fR *\fIbuffer\fR\fB);\fR +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +The \fB\f(BITPM_Malloc()\fB\fR function is used to allocate a buffer of the given size. +The allocated buffer will be returned in the \fIbuffer\fR parameter. +.PP +The \fB\f(BITPM_Realloc()\fB\fR function is used to resize a buffer. The new size of +the buffer is given in the \fIsize\fR parameter. The reallocated buffer will +contain the data from the original buffer. +.PP +Both functions have the restriction that the buffer they can allocate +is limited to \fB\s-1TPM_ALLOC_MAX\s0\fR (64k) bytes. This size is sufficent +for all buffers needed by the \s-1TPM\s0. +.PP +Upon successful completion, the functions return \fB\s-1TPM_SUCCESS\s0\fR. In case the +requested buffer exceeds the limit, \fB\s-1TPM_SIZE\s0\fR will be returned. See further +possible error codes below. +.PP +The \fB\f(BITPM_Free()\fB\fR function frees the memory previously allocated using +either \fB\f(BITPM_Malloc()\fB\fR or \fB\f(BITPM_Realloc()\fB\fR. +.SH "ERRORS" +.IX Header "ERRORS" +.IP "\fB\s-1TPM_SUCCESS\s0\fR" 4 +.IX Item "TPM_SUCCESS" +The function completed sucessfully. +.IP "\fB\s-1TPM_SIZE\s0\fR" 4 +.IX Item "TPM_SIZE" +The size of the requested buffer exceeds the limit or the +system is out of memory. +.IP "\fB\s-1TPM_FAIL\s0\fR" 4 +.IX Item "TPM_FAIL" +Requested buffer is of size 0. +.PP +For a complete list of \s-1TPM\s0 error codes please consult the include file +\&\fBlibtpms/tpm_error.h\fR +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fBTPMLIB_MainInit\fR(3), \fBTPMLIB_Terminate\fR(3) +\&\fBTPMLIB_Process\fR(3), \fBTPMLIB_RegisterCallbacks\fR(3), \fBTPMLIB_GetVersion\fR(3) diff --git a/man/man3/TPM_Malloc.pod b/man/man3/TPM_Malloc.pod new file mode 100644 index 00000000..99015c8a --- /dev/null +++ b/man/man3/TPM_Malloc.pod @@ -0,0 +1,72 @@ +=head1 NAME + +TPM_Malloc - Allocate memory + +TPM_Realloc - Reallocate memory + +TPM_Free - Free memory + +=head1 SYNOPSIS + +B<#include > + +B<#include > + +B<#include > + +B **IB<, + uint32_t> IB<);> + +B **IB<, + uint32_t> IB<);> + +B *IB<);> + +=head1 DESCRIPTION + +The B function is used to allocate a buffer of the given size. +The allocated buffer will be returned in the I parameter. + +The B function is used to resize a buffer. The new size of +the buffer is given in the I parameter. The reallocated buffer will +contain the data from the original buffer. + +Both functions have the restriction that the buffer they can allocate +is limited to B (64k) bytes. This size is sufficent +for all buffers needed by the TPM. + +Upon successful completion, the functions return B. In case the +requested buffer exceeds the limit, B will be returned. See further +possible error codes below. + +The B function frees the memory previously allocated using +either B or B. + +=head1 ERRORS + +=over 4 + +=item B + +The function completed sucessfully. + +=item B + +The size of the requested buffer exceeds the limit or the +system is out of memory. + +=item B + +Requested buffer is of size 0. + +=back + +For a complete list of TPM error codes please consult the include file +B + +=head1 SEE ALSO + +B(3), B(3) +B(3), B(3), B(3) + +=cut diff --git a/man/man3/TPM_Realloc.3 b/man/man3/TPM_Realloc.3 new file mode 100644 index 00000000..bc24f9ef --- /dev/null +++ b/man/man3/TPM_Realloc.3 @@ -0,0 +1 @@ +.so man3/TPM_Malloc.3 \ No newline at end of file diff --git a/missing b/missing new file mode 100755 index 00000000..86a8fc31 --- /dev/null +++ b/missing @@ -0,0 +1,331 @@ +#! /bin/sh +# Common stub for a few missing GNU programs while installing. + +scriptversion=2012-01-06.13; # UTC + +# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, +# 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +# Originally by Fran,cois Pinard , 1996. + +# 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, 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, see . + +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + +if test $# -eq 0; then + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 +fi + +run=: +sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' +sed_minuso='s/.* -o \([^ ]*\).*/\1/p' + +# In the cases where this matters, `missing' is being run in the +# srcdir already. +if test -f configure.ac; then + configure_ac=configure.ac +else + configure_ac=configure.in +fi + +msg="missing on your system" + +case $1 in +--run) + # Try to run requested program, and just exit if it succeeds. + run= + shift + "$@" && exit 0 + # Exit code 63 means version mismatch. This often happens + # when the user try to use an ancient version of a tool on + # a file that requires a minimum version. In this case we + # we should proceed has if the program had been absent, or + # if --run hadn't been passed. + if test $? = 63; then + run=: + msg="probably too old" + fi + ;; + + -h|--h|--he|--hel|--help) + echo "\ +$0 [OPTION]... PROGRAM [ARGUMENT]... + +Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an +error status if there is no known handling for PROGRAM. + +Options: + -h, --help display this help and exit + -v, --version output version information and exit + --run try to run the given command, and emulate it if it fails + +Supported PROGRAM values: + aclocal touch file \`aclocal.m4' + autoconf touch file \`configure' + autoheader touch file \`config.h.in' + autom4te touch the output file, or create a stub one + automake touch all \`Makefile.in' files + bison create \`y.tab.[ch]', if possible, from existing .[ch] + flex create \`lex.yy.c', if possible, from existing .c + help2man touch the output file + lex create \`lex.yy.c', if possible, from existing .c + makeinfo touch the output file + yacc create \`y.tab.[ch]', if possible, from existing .[ch] + +Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and +\`g' are ignored when checking the name. + +Send bug reports to ." + exit $? + ;; + + -v|--v|--ve|--ver|--vers|--versi|--versio|--version) + echo "missing $scriptversion (GNU Automake)" + exit $? + ;; + + -*) + echo 1>&2 "$0: Unknown \`$1' option" + echo 1>&2 "Try \`$0 --help' for more information" + exit 1 + ;; + +esac + +# normalize program name to check for. +program=`echo "$1" | sed ' + s/^gnu-//; t + s/^gnu//; t + s/^g//; t'` + +# Now exit if we have it, but it failed. Also exit now if we +# don't have it and --version was passed (most likely to detect +# the program). This is about non-GNU programs, so use $1 not +# $program. +case $1 in + lex*|yacc*) + # Not GNU programs, they don't have --version. + ;; + + *) + if test -z "$run" && ($1 --version) > /dev/null 2>&1; then + # We have it, but it failed. + exit 1 + elif test "x$2" = "x--version" || test "x$2" = "x--help"; then + # Could not run --version or --help. This is probably someone + # running `$TOOL --version' or `$TOOL --help' to check whether + # $TOOL exists and not knowing $TOOL uses missing. + exit 1 + fi + ;; +esac + +# If it does not exist, or fails to run (possibly an outdated version), +# try to emulate it. +case $program in + aclocal*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acinclude.m4' or \`${configure_ac}'. You might want + to install the \`Automake' and \`Perl' packages. Grab them from + any GNU archive site." + touch aclocal.m4 + ;; + + autoconf*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`${configure_ac}'. You might want to install the + \`Autoconf' and \`GNU m4' packages. Grab them from any GNU + archive site." + touch configure + ;; + + autoheader*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`acconfig.h' or \`${configure_ac}'. You might want + to install the \`Autoconf' and \`GNU m4' packages. Grab them + from any GNU archive site." + files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` + test -z "$files" && files="config.h" + touch_files= + for f in $files; do + case $f in + *:*) touch_files="$touch_files "`echo "$f" | + sed -e 's/^[^:]*://' -e 's/:.*//'`;; + *) touch_files="$touch_files $f.in";; + esac + done + touch $touch_files + ;; + + automake*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. + You might want to install the \`Automake' and \`Perl' packages. + Grab them from any GNU archive site." + find . -type f -name Makefile.am -print | + sed 's/\.am$/.in/' | + while read f; do touch "$f"; done + ;; + + autom4te*) + echo 1>&2 "\ +WARNING: \`$1' is needed, but is $msg. + You might have modified some files without having the + proper tools for further handling them. + You can get \`$1' as part of \`Autoconf' from any GNU + archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo "#! /bin/sh" + echo "# Created by GNU Automake missing as a replacement of" + echo "# $ $@" + echo "exit 0" + chmod +x $file + exit 1 + fi + ;; + + bison*|yacc*) + echo 1>&2 "\ +WARNING: \`$1' $msg. You should only need it if + you modified a \`.y' file. You may need the \`Bison' package + in order for those modifications to take effect. You can get + \`Bison' from any GNU archive site." + rm -f y.tab.c y.tab.h + if test $# -ne 1; then + eval LASTARG=\${$#} + case $LASTARG in + *.y) + SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.c + fi + SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" y.tab.h + fi + ;; + esac + fi + if test ! -f y.tab.h; then + echo >y.tab.h + fi + if test ! -f y.tab.c; then + echo 'main() { return 0; }' >y.tab.c + fi + ;; + + lex*|flex*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.l' file. You may need the \`Flex' package + in order for those modifications to take effect. You can get + \`Flex' from any GNU archive site." + rm -f lex.yy.c + if test $# -ne 1; then + eval LASTARG=\${$#} + case $LASTARG in + *.l) + SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` + if test -f "$SRCFILE"; then + cp "$SRCFILE" lex.yy.c + fi + ;; + esac + fi + if test ! -f lex.yy.c; then + echo 'main() { return 0; }' >lex.yy.c + fi + ;; + + help2man*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a dependency of a manual page. You may need the + \`Help2man' package in order for those modifications to take + effect. You can get \`Help2man' from any GNU archive site." + + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -f "$file"; then + touch $file + else + test -z "$file" || exec >$file + echo ".ab help2man is required to generate this page" + exit $? + fi + ;; + + makeinfo*) + echo 1>&2 "\ +WARNING: \`$1' is $msg. You should only need it if + you modified a \`.texi' or \`.texinfo' file, or any other file + indirectly affecting the aspect of the manual. The spurious + call might also be the consequence of using a buggy \`make' (AIX, + DU, IRIX). You might want to install the \`Texinfo' package or + the \`GNU make' package. Grab either from any GNU archive site." + # The file to touch is that specified with -o ... + file=`echo "$*" | sed -n "$sed_output"` + test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` + if test -z "$file"; then + # ... or it is the one specified with @setfilename ... + infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` + file=`sed -n ' + /^@setfilename/{ + s/.* \([^ ]*\) *$/\1/ + p + q + }' $infile` + # ... or it is derived from the source name (dir/f.texi becomes f.info) + test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info + fi + # If the file does not exist, the user really needs makeinfo; + # let's fail without touching anything. + test -f $file || exit 1 + touch $file + ;; + + *) + echo 1>&2 "\ +WARNING: \`$1' is needed, and is $msg. + You might have modified some files without having the + proper tools for further handling them. Check the \`README' file, + it often tells you about the needed prerequisites for installing + this package. You may also peek at any GNU archive site, in case + some other package would contain this missing \`$1' program." + exit 1 + ;; +esac + +exit 0 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-time-zone: "UTC" +# time-stamp-end: "; # UTC" +# End: diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 00000000..f6c092ae --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,166 @@ +# +# src/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# + +lib_LTLIBRARIES=libtpms.la + +libtpms_la_LIBADD= + +libtpms_la_LDFLAGS = -Wl,--version-script=./libtpms.syms \ + -version-info $(LIBTPMS_VERSION_INFO) + +libtpms_la_CFLAGS = -include tpm_library_conf.h -I$(top_srcdir)/include/libtpms + +#Build 1.2 TPM +libtpms_la_CFLAGS += -DTPM_V12 +# build a PC Client TPM +libtpms_la_CFLAGS += -DTPM_PCCLIENT +# upon initialization have the TPM load the volatile state +libtpms_la_CFLAGS += -DTPM_VOLATILE_LOAD +# build the TPM enabled and activated +libtpms_la_CFLAGS += -DTPM_ENABLE_ACTIVATE +# build with AES support for symmetric crypto +libtpms_la_CFLAGS += -DTPM_AES +# build with libtpms callback support +libtpms_la_CFLAGS += -DTPM_LIBTPMS_CALLBACKS +# let the default NVRAM write to disk +libtpms_la_CFLAGS += -DTPM_NV_DISK +# build a POSIX type of TPM +libtpms_la_CFLAGS += -DTPM_POSIX + +libtpms_la_CFLAGS += @DEBUG_DEFINES@ + +CRYPTO_OBJFILES = + +libtpms_la_SOURCES = \ + tpm_admin.c \ + tpm_audit.c \ + tpm_auth.c \ + tpm_cryptoh.c \ + tpm_counter.c \ + tpm_daa.c \ + tpm_debug.c \ + tpm_delegate.c \ + tpm_digest.c \ + tpm_error.c \ + tpm_global.c \ + tpm_identity.c \ + tpm_init.c \ + tpm_libtpms_io.c \ + tpm_key.c \ + tpm_library.c \ + tpm_load.c \ + tpm_maint.c \ + tpm_memory.c \ + tpm_migration.c \ + tpm_nonce.c \ + tpm_nvfile.c \ + tpm_nvram.c \ + tpm_owner.c \ + tpm_pcr.c \ + tpm_permanent.c \ + tpm_platform.c \ + tpm_process.c \ + tpm_secret.c \ + tpm_session.c \ + tpm_sizedbuffer.c \ + tpm_startup.c \ + tpm_store.c \ + tpm_storage.c \ + tpm_ticks.c \ + tpm_time.c \ + tpm_tis.c \ + tpm_transport.c \ + tpm_ver.c \ + tpm_svnrevision.c + +noinst_HEADERS = \ + tpm_admin.h \ + tpm_audit.h \ + tpm_auth.h \ + tpm_commands.h \ + tpm_constants.h \ + tpm_counter.h \ + tpm_crypto.h \ + tpm_cryptoh.h \ + tpm_daa.h \ + tpm_debug.h \ + tpm_delegate.h \ + tpm_digest.h \ + tpm_global.h \ + tpm_identity.h \ + tpm_init.h \ + tpm_io.h \ + tpm_key.h \ + tpm_library_conf.h \ + tpm_library_intern.h \ + tpm_load.h \ + tpm_maint.h \ + tpm_migration.h \ + tpm_nonce.h \ + tpm_nvfile.h \ + tpm_nvram_const.h \ + tpm_nvram.h \ + tpm_owner.h \ + tpm_pcr.h \ + tpm_permanent.h \ + tpm_platform.h \ + tpm_process.h \ + tpm_secret.h \ + tpm_session.h \ + tpm_sizedbuffer.h \ + tpm_startup.h \ + tpm_storage.h \ + tpm_store.h \ + tpm_structures.h \ + tpm_svnrevision.h \ + tpm_ticks.h \ + tpm_time.h \ + tpm_transport.h \ + tpm_ver.h + + +if LIBTPMS_USE_FREEBL + +libtpms_la_SOURCES += tpm_crypto_freebl.c +libtpms_la_LIBADD += -lfreebl -lgmp -lnspr4 -lnssutil3 -lnss3 + +#work-around broken freebl includes +libtpms_la_CFLAGS += $(shell [ ! -r /usr/include/nss3/alghmac.h ] && \ + touch alghmac.h && \ + echo -I./) +# tpm_crypto_freebl.c: work around #include "blapi.h" : should be +libtpms_la_CFLAGS += $(shell nss-config --cflags) +#including nss3/blapi.h requires a look into nspr4 dir +libtpms_la_CFLAGS += $(shell nspr-config --cflags) + +else + +if LIBTPMS_USE_OPENSSL + +libtpms_la_SOURCES += tpm_crypto.c +libtpms_la_LIBADD += -lcrypto +libtpms_la_LDFLAGS += $(shell nspr-config --libs) +libtpms_la_CFLAGS += $(shell nspr-config --cflags) + +endif # LIBTPMS_USE_OPENSSL + +endif # LIBTPMS_USE_FREEBL + +LDFLAGS_ARCH = $(findstring -m32, $(CFLAGS)) +LDFLAGS_ARCH += $(findstring -m64, $(CFLAGS)) +LDFLAGS_ARCH += $(findstring -m32, $(LDFLAGS)) +LDFLAGS_ARCH += $(findstring -m64, $(LDFLAGS)) + +check-local: + @($(CC) $(LDFLAGS_ARCH) -nostdlib -L./.libs -ltpms 2>/dev/null || \ + (echo "There are undefined symbols in libtpms ($(LDFLAGS_ARCH))";\ + $(CC) $(LDFLAGS_ARCH) -nostdlib -L./.libs -ltpms 2>&1 | grep libtpms)) + @$(CC) $(LDFLAGS_ARCH) -nostdlib -L./.libs -ltpms 2>/dev/null + +EXTRA_DIST = \ + tpm_crypto_freebl.c \ + tpm_crypto.c \ + libtpms.syms diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 00000000..a0d31450 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,1046 @@ +# Makefile.in generated by automake 1.11.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# src/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# + + +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +@LIBTPMS_USE_FREEBL_TRUE@am__append_1 = tpm_crypto_freebl.c +@LIBTPMS_USE_FREEBL_TRUE@am__append_2 = -lfreebl -lgmp -lnspr4 -lnssutil3 -lnss3 + +#work-around broken freebl includes +# tpm_crypto_freebl.c: work around #include "blapi.h" : should be +#including nss3/blapi.h requires a look into nspr4 dir +@LIBTPMS_USE_FREEBL_TRUE@am__append_3 = $(shell [ ! -r \ +@LIBTPMS_USE_FREEBL_TRUE@ /usr/include/nss3/alghmac.h ] && \ +@LIBTPMS_USE_FREEBL_TRUE@ touch alghmac.h && echo -I./) $(shell \ +@LIBTPMS_USE_FREEBL_TRUE@ nss-config --cflags) $(shell \ +@LIBTPMS_USE_FREEBL_TRUE@ nspr-config --cflags) +@LIBTPMS_USE_FREEBL_FALSE@@LIBTPMS_USE_OPENSSL_TRUE@am__append_4 = tpm_crypto.c +@LIBTPMS_USE_FREEBL_FALSE@@LIBTPMS_USE_OPENSSL_TRUE@am__append_5 = -lcrypto +@LIBTPMS_USE_FREEBL_FALSE@@LIBTPMS_USE_OPENSSL_TRUE@am__append_6 = $(shell nspr-config --libs) +@LIBTPMS_USE_FREEBL_FALSE@@LIBTPMS_USE_OPENSSL_TRUE@am__append_7 = $(shell nspr-config --cflags) +subdir = src +DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +am__DEPENDENCIES_1 = +libtpms_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +am__libtpms_la_SOURCES_DIST = tpm_admin.c tpm_audit.c tpm_auth.c \ + tpm_cryptoh.c tpm_counter.c tpm_daa.c tpm_debug.c \ + tpm_delegate.c tpm_digest.c tpm_error.c tpm_global.c \ + tpm_identity.c tpm_init.c tpm_libtpms_io.c tpm_key.c \ + tpm_library.c tpm_load.c tpm_maint.c tpm_memory.c \ + tpm_migration.c tpm_nonce.c tpm_nvfile.c tpm_nvram.c \ + tpm_owner.c tpm_pcr.c tpm_permanent.c tpm_platform.c \ + tpm_process.c tpm_secret.c tpm_session.c tpm_sizedbuffer.c \ + tpm_startup.c tpm_store.c tpm_storage.c tpm_ticks.c tpm_time.c \ + tpm_tis.c tpm_transport.c tpm_ver.c tpm_svnrevision.c \ + tpm_crypto_freebl.c tpm_crypto.c +@LIBTPMS_USE_FREEBL_TRUE@am__objects_1 = \ +@LIBTPMS_USE_FREEBL_TRUE@ libtpms_la-tpm_crypto_freebl.lo +@LIBTPMS_USE_FREEBL_FALSE@@LIBTPMS_USE_OPENSSL_TRUE@am__objects_2 = libtpms_la-tpm_crypto.lo +am_libtpms_la_OBJECTS = libtpms_la-tpm_admin.lo \ + libtpms_la-tpm_audit.lo libtpms_la-tpm_auth.lo \ + libtpms_la-tpm_cryptoh.lo libtpms_la-tpm_counter.lo \ + libtpms_la-tpm_daa.lo libtpms_la-tpm_debug.lo \ + libtpms_la-tpm_delegate.lo libtpms_la-tpm_digest.lo \ + libtpms_la-tpm_error.lo libtpms_la-tpm_global.lo \ + libtpms_la-tpm_identity.lo libtpms_la-tpm_init.lo \ + libtpms_la-tpm_libtpms_io.lo libtpms_la-tpm_key.lo \ + libtpms_la-tpm_library.lo libtpms_la-tpm_load.lo \ + libtpms_la-tpm_maint.lo libtpms_la-tpm_memory.lo \ + libtpms_la-tpm_migration.lo libtpms_la-tpm_nonce.lo \ + libtpms_la-tpm_nvfile.lo libtpms_la-tpm_nvram.lo \ + libtpms_la-tpm_owner.lo libtpms_la-tpm_pcr.lo \ + libtpms_la-tpm_permanent.lo libtpms_la-tpm_platform.lo \ + libtpms_la-tpm_process.lo libtpms_la-tpm_secret.lo \ + libtpms_la-tpm_session.lo libtpms_la-tpm_sizedbuffer.lo \ + libtpms_la-tpm_startup.lo libtpms_la-tpm_store.lo \ + libtpms_la-tpm_storage.lo libtpms_la-tpm_ticks.lo \ + libtpms_la-tpm_time.lo libtpms_la-tpm_tis.lo \ + libtpms_la-tpm_transport.lo libtpms_la-tpm_ver.lo \ + libtpms_la-tpm_svnrevision.lo $(am__objects_1) \ + $(am__objects_2) +libtpms_la_OBJECTS = $(am_libtpms_la_OBJECTS) +libtpms_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libtpms_la_CFLAGS) \ + $(CFLAGS) $(libtpms_la_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(libtpms_la_SOURCES) +DIST_SOURCES = $(am__libtpms_la_SOURCES_DIST) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUG_DEFINES = @DEBUG_DEFINES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTPMS_VERSION = @LIBTPMS_VERSION@ +LIBTPMS_VERSION_INFO = @LIBTPMS_VERSION_INFO@ +LIBTPMS_VER_MAJOR = @LIBTPMS_VER_MAJOR@ +LIBTPMS_VER_MICRO = @LIBTPMS_VER_MICRO@ +LIBTPMS_VER_MINOR = @LIBTPMS_VER_MINOR@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +lib_LTLIBRARIES = libtpms.la +libtpms_la_LIBADD = $(am__append_2) $(am__append_5) +libtpms_la_LDFLAGS = -Wl,--version-script=./libtpms.syms -version-info \ + $(LIBTPMS_VERSION_INFO) $(am__append_6) + +#Build 1.2 TPM +# build a PC Client TPM +# upon initialization have the TPM load the volatile state +# build the TPM enabled and activated +# build with AES support for symmetric crypto +# build with libtpms callback support +# let the default NVRAM write to disk +# build a POSIX type of TPM +libtpms_la_CFLAGS = -include tpm_library_conf.h \ + -I$(top_srcdir)/include/libtpms -DTPM_V12 -DTPM_PCCLIENT \ + -DTPM_VOLATILE_LOAD -DTPM_ENABLE_ACTIVATE -DTPM_AES \ + -DTPM_LIBTPMS_CALLBACKS -DTPM_NV_DISK -DTPM_POSIX \ + @DEBUG_DEFINES@ $(am__append_3) $(am__append_7) +CRYPTO_OBJFILES = +libtpms_la_SOURCES = tpm_admin.c tpm_audit.c tpm_auth.c tpm_cryptoh.c \ + tpm_counter.c tpm_daa.c tpm_debug.c tpm_delegate.c \ + tpm_digest.c tpm_error.c tpm_global.c tpm_identity.c \ + tpm_init.c tpm_libtpms_io.c tpm_key.c tpm_library.c tpm_load.c \ + tpm_maint.c tpm_memory.c tpm_migration.c tpm_nonce.c \ + tpm_nvfile.c tpm_nvram.c tpm_owner.c tpm_pcr.c tpm_permanent.c \ + tpm_platform.c tpm_process.c tpm_secret.c tpm_session.c \ + tpm_sizedbuffer.c tpm_startup.c tpm_store.c tpm_storage.c \ + tpm_ticks.c tpm_time.c tpm_tis.c tpm_transport.c tpm_ver.c \ + tpm_svnrevision.c $(am__append_1) $(am__append_4) +noinst_HEADERS = \ + tpm_admin.h \ + tpm_audit.h \ + tpm_auth.h \ + tpm_commands.h \ + tpm_constants.h \ + tpm_counter.h \ + tpm_crypto.h \ + tpm_cryptoh.h \ + tpm_daa.h \ + tpm_debug.h \ + tpm_delegate.h \ + tpm_digest.h \ + tpm_global.h \ + tpm_identity.h \ + tpm_init.h \ + tpm_io.h \ + tpm_key.h \ + tpm_library_conf.h \ + tpm_library_intern.h \ + tpm_load.h \ + tpm_maint.h \ + tpm_migration.h \ + tpm_nonce.h \ + tpm_nvfile.h \ + tpm_nvram_const.h \ + tpm_nvram.h \ + tpm_owner.h \ + tpm_pcr.h \ + tpm_permanent.h \ + tpm_platform.h \ + tpm_process.h \ + tpm_secret.h \ + tpm_session.h \ + tpm_sizedbuffer.h \ + tpm_startup.h \ + tpm_storage.h \ + tpm_store.h \ + tpm_structures.h \ + tpm_svnrevision.h \ + tpm_ticks.h \ + tpm_time.h \ + tpm_transport.h \ + tpm_ver.h + +LDFLAGS_ARCH = $(findstring -m32, $(CFLAGS)) $(findstring -m64, \ + $(CFLAGS)) $(findstring -m32, $(LDFLAGS)) $(findstring -m64, \ + $(LDFLAGS)) +EXTRA_DIST = \ + tpm_crypto_freebl.c \ + tpm_crypto.c \ + libtpms.syms + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libtpms.la: $(libtpms_la_OBJECTS) $(libtpms_la_DEPENDENCIES) $(EXTRA_libtpms_la_DEPENDENCIES) + $(libtpms_la_LINK) -rpath $(libdir) $(libtpms_la_OBJECTS) $(libtpms_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_admin.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_audit.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_auth.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_counter.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_crypto.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_crypto_freebl.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_cryptoh.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_daa.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_debug.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_delegate.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_digest.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_error.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_global.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_identity.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_init.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_key.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_library.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_libtpms_io.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_load.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_maint.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_memory.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_migration.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_nonce.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_nvfile.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_nvram.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_owner.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_pcr.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_permanent.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_platform.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_process.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_secret.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_session.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_sizedbuffer.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_startup.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_storage.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_store.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_svnrevision.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_ticks.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_time.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_tis.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_transport.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtpms_la-tpm_ver.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libtpms_la-tpm_admin.lo: tpm_admin.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_admin.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_admin.Tpo -c -o libtpms_la-tpm_admin.lo `test -f 'tpm_admin.c' || echo '$(srcdir)/'`tpm_admin.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_admin.Tpo $(DEPDIR)/libtpms_la-tpm_admin.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_admin.c' object='libtpms_la-tpm_admin.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_admin.lo `test -f 'tpm_admin.c' || echo '$(srcdir)/'`tpm_admin.c + +libtpms_la-tpm_audit.lo: tpm_audit.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_audit.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_audit.Tpo -c -o libtpms_la-tpm_audit.lo `test -f 'tpm_audit.c' || echo '$(srcdir)/'`tpm_audit.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_audit.Tpo $(DEPDIR)/libtpms_la-tpm_audit.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_audit.c' object='libtpms_la-tpm_audit.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_audit.lo `test -f 'tpm_audit.c' || echo '$(srcdir)/'`tpm_audit.c + +libtpms_la-tpm_auth.lo: tpm_auth.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_auth.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_auth.Tpo -c -o libtpms_la-tpm_auth.lo `test -f 'tpm_auth.c' || echo '$(srcdir)/'`tpm_auth.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_auth.Tpo $(DEPDIR)/libtpms_la-tpm_auth.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_auth.c' object='libtpms_la-tpm_auth.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_auth.lo `test -f 'tpm_auth.c' || echo '$(srcdir)/'`tpm_auth.c + +libtpms_la-tpm_cryptoh.lo: tpm_cryptoh.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_cryptoh.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_cryptoh.Tpo -c -o libtpms_la-tpm_cryptoh.lo `test -f 'tpm_cryptoh.c' || echo '$(srcdir)/'`tpm_cryptoh.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_cryptoh.Tpo $(DEPDIR)/libtpms_la-tpm_cryptoh.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_cryptoh.c' object='libtpms_la-tpm_cryptoh.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_cryptoh.lo `test -f 'tpm_cryptoh.c' || echo '$(srcdir)/'`tpm_cryptoh.c + +libtpms_la-tpm_counter.lo: tpm_counter.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_counter.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_counter.Tpo -c -o libtpms_la-tpm_counter.lo `test -f 'tpm_counter.c' || echo '$(srcdir)/'`tpm_counter.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_counter.Tpo $(DEPDIR)/libtpms_la-tpm_counter.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_counter.c' object='libtpms_la-tpm_counter.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_counter.lo `test -f 'tpm_counter.c' || echo '$(srcdir)/'`tpm_counter.c + +libtpms_la-tpm_daa.lo: tpm_daa.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_daa.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_daa.Tpo -c -o libtpms_la-tpm_daa.lo `test -f 'tpm_daa.c' || echo '$(srcdir)/'`tpm_daa.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_daa.Tpo $(DEPDIR)/libtpms_la-tpm_daa.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_daa.c' object='libtpms_la-tpm_daa.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_daa.lo `test -f 'tpm_daa.c' || echo '$(srcdir)/'`tpm_daa.c + +libtpms_la-tpm_debug.lo: tpm_debug.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_debug.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_debug.Tpo -c -o libtpms_la-tpm_debug.lo `test -f 'tpm_debug.c' || echo '$(srcdir)/'`tpm_debug.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_debug.Tpo $(DEPDIR)/libtpms_la-tpm_debug.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_debug.c' object='libtpms_la-tpm_debug.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_debug.lo `test -f 'tpm_debug.c' || echo '$(srcdir)/'`tpm_debug.c + +libtpms_la-tpm_delegate.lo: tpm_delegate.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_delegate.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_delegate.Tpo -c -o libtpms_la-tpm_delegate.lo `test -f 'tpm_delegate.c' || echo '$(srcdir)/'`tpm_delegate.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_delegate.Tpo $(DEPDIR)/libtpms_la-tpm_delegate.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_delegate.c' object='libtpms_la-tpm_delegate.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_delegate.lo `test -f 'tpm_delegate.c' || echo '$(srcdir)/'`tpm_delegate.c + +libtpms_la-tpm_digest.lo: tpm_digest.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_digest.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_digest.Tpo -c -o libtpms_la-tpm_digest.lo `test -f 'tpm_digest.c' || echo '$(srcdir)/'`tpm_digest.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_digest.Tpo $(DEPDIR)/libtpms_la-tpm_digest.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_digest.c' object='libtpms_la-tpm_digest.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_digest.lo `test -f 'tpm_digest.c' || echo '$(srcdir)/'`tpm_digest.c + +libtpms_la-tpm_error.lo: tpm_error.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_error.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_error.Tpo -c -o libtpms_la-tpm_error.lo `test -f 'tpm_error.c' || echo '$(srcdir)/'`tpm_error.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_error.Tpo $(DEPDIR)/libtpms_la-tpm_error.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_error.c' object='libtpms_la-tpm_error.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_error.lo `test -f 'tpm_error.c' || echo '$(srcdir)/'`tpm_error.c + +libtpms_la-tpm_global.lo: tpm_global.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_global.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_global.Tpo -c -o libtpms_la-tpm_global.lo `test -f 'tpm_global.c' || echo '$(srcdir)/'`tpm_global.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_global.Tpo $(DEPDIR)/libtpms_la-tpm_global.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_global.c' object='libtpms_la-tpm_global.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_global.lo `test -f 'tpm_global.c' || echo '$(srcdir)/'`tpm_global.c + +libtpms_la-tpm_identity.lo: tpm_identity.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_identity.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_identity.Tpo -c -o libtpms_la-tpm_identity.lo `test -f 'tpm_identity.c' || echo '$(srcdir)/'`tpm_identity.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_identity.Tpo $(DEPDIR)/libtpms_la-tpm_identity.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_identity.c' object='libtpms_la-tpm_identity.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_identity.lo `test -f 'tpm_identity.c' || echo '$(srcdir)/'`tpm_identity.c + +libtpms_la-tpm_init.lo: tpm_init.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_init.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_init.Tpo -c -o libtpms_la-tpm_init.lo `test -f 'tpm_init.c' || echo '$(srcdir)/'`tpm_init.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_init.Tpo $(DEPDIR)/libtpms_la-tpm_init.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_init.c' object='libtpms_la-tpm_init.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_init.lo `test -f 'tpm_init.c' || echo '$(srcdir)/'`tpm_init.c + +libtpms_la-tpm_libtpms_io.lo: tpm_libtpms_io.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_libtpms_io.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_libtpms_io.Tpo -c -o libtpms_la-tpm_libtpms_io.lo `test -f 'tpm_libtpms_io.c' || echo '$(srcdir)/'`tpm_libtpms_io.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_libtpms_io.Tpo $(DEPDIR)/libtpms_la-tpm_libtpms_io.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_libtpms_io.c' object='libtpms_la-tpm_libtpms_io.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_libtpms_io.lo `test -f 'tpm_libtpms_io.c' || echo '$(srcdir)/'`tpm_libtpms_io.c + +libtpms_la-tpm_key.lo: tpm_key.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_key.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_key.Tpo -c -o libtpms_la-tpm_key.lo `test -f 'tpm_key.c' || echo '$(srcdir)/'`tpm_key.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_key.Tpo $(DEPDIR)/libtpms_la-tpm_key.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_key.c' object='libtpms_la-tpm_key.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_key.lo `test -f 'tpm_key.c' || echo '$(srcdir)/'`tpm_key.c + +libtpms_la-tpm_library.lo: tpm_library.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_library.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_library.Tpo -c -o libtpms_la-tpm_library.lo `test -f 'tpm_library.c' || echo '$(srcdir)/'`tpm_library.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_library.Tpo $(DEPDIR)/libtpms_la-tpm_library.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_library.c' object='libtpms_la-tpm_library.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_library.lo `test -f 'tpm_library.c' || echo '$(srcdir)/'`tpm_library.c + +libtpms_la-tpm_load.lo: tpm_load.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_load.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_load.Tpo -c -o libtpms_la-tpm_load.lo `test -f 'tpm_load.c' || echo '$(srcdir)/'`tpm_load.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_load.Tpo $(DEPDIR)/libtpms_la-tpm_load.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_load.c' object='libtpms_la-tpm_load.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_load.lo `test -f 'tpm_load.c' || echo '$(srcdir)/'`tpm_load.c + +libtpms_la-tpm_maint.lo: tpm_maint.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_maint.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_maint.Tpo -c -o libtpms_la-tpm_maint.lo `test -f 'tpm_maint.c' || echo '$(srcdir)/'`tpm_maint.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_maint.Tpo $(DEPDIR)/libtpms_la-tpm_maint.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_maint.c' object='libtpms_la-tpm_maint.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_maint.lo `test -f 'tpm_maint.c' || echo '$(srcdir)/'`tpm_maint.c + +libtpms_la-tpm_memory.lo: tpm_memory.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_memory.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_memory.Tpo -c -o libtpms_la-tpm_memory.lo `test -f 'tpm_memory.c' || echo '$(srcdir)/'`tpm_memory.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_memory.Tpo $(DEPDIR)/libtpms_la-tpm_memory.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_memory.c' object='libtpms_la-tpm_memory.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_memory.lo `test -f 'tpm_memory.c' || echo '$(srcdir)/'`tpm_memory.c + +libtpms_la-tpm_migration.lo: tpm_migration.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_migration.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_migration.Tpo -c -o libtpms_la-tpm_migration.lo `test -f 'tpm_migration.c' || echo '$(srcdir)/'`tpm_migration.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_migration.Tpo $(DEPDIR)/libtpms_la-tpm_migration.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_migration.c' object='libtpms_la-tpm_migration.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_migration.lo `test -f 'tpm_migration.c' || echo '$(srcdir)/'`tpm_migration.c + +libtpms_la-tpm_nonce.lo: tpm_nonce.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_nonce.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_nonce.Tpo -c -o libtpms_la-tpm_nonce.lo `test -f 'tpm_nonce.c' || echo '$(srcdir)/'`tpm_nonce.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_nonce.Tpo $(DEPDIR)/libtpms_la-tpm_nonce.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_nonce.c' object='libtpms_la-tpm_nonce.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_nonce.lo `test -f 'tpm_nonce.c' || echo '$(srcdir)/'`tpm_nonce.c + +libtpms_la-tpm_nvfile.lo: tpm_nvfile.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_nvfile.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_nvfile.Tpo -c -o libtpms_la-tpm_nvfile.lo `test -f 'tpm_nvfile.c' || echo '$(srcdir)/'`tpm_nvfile.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_nvfile.Tpo $(DEPDIR)/libtpms_la-tpm_nvfile.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_nvfile.c' object='libtpms_la-tpm_nvfile.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_nvfile.lo `test -f 'tpm_nvfile.c' || echo '$(srcdir)/'`tpm_nvfile.c + +libtpms_la-tpm_nvram.lo: tpm_nvram.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_nvram.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_nvram.Tpo -c -o libtpms_la-tpm_nvram.lo `test -f 'tpm_nvram.c' || echo '$(srcdir)/'`tpm_nvram.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_nvram.Tpo $(DEPDIR)/libtpms_la-tpm_nvram.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_nvram.c' object='libtpms_la-tpm_nvram.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_nvram.lo `test -f 'tpm_nvram.c' || echo '$(srcdir)/'`tpm_nvram.c + +libtpms_la-tpm_owner.lo: tpm_owner.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_owner.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_owner.Tpo -c -o libtpms_la-tpm_owner.lo `test -f 'tpm_owner.c' || echo '$(srcdir)/'`tpm_owner.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_owner.Tpo $(DEPDIR)/libtpms_la-tpm_owner.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_owner.c' object='libtpms_la-tpm_owner.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_owner.lo `test -f 'tpm_owner.c' || echo '$(srcdir)/'`tpm_owner.c + +libtpms_la-tpm_pcr.lo: tpm_pcr.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_pcr.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_pcr.Tpo -c -o libtpms_la-tpm_pcr.lo `test -f 'tpm_pcr.c' || echo '$(srcdir)/'`tpm_pcr.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_pcr.Tpo $(DEPDIR)/libtpms_la-tpm_pcr.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_pcr.c' object='libtpms_la-tpm_pcr.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_pcr.lo `test -f 'tpm_pcr.c' || echo '$(srcdir)/'`tpm_pcr.c + +libtpms_la-tpm_permanent.lo: tpm_permanent.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_permanent.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_permanent.Tpo -c -o libtpms_la-tpm_permanent.lo `test -f 'tpm_permanent.c' || echo '$(srcdir)/'`tpm_permanent.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_permanent.Tpo $(DEPDIR)/libtpms_la-tpm_permanent.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_permanent.c' object='libtpms_la-tpm_permanent.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_permanent.lo `test -f 'tpm_permanent.c' || echo '$(srcdir)/'`tpm_permanent.c + +libtpms_la-tpm_platform.lo: tpm_platform.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_platform.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_platform.Tpo -c -o libtpms_la-tpm_platform.lo `test -f 'tpm_platform.c' || echo '$(srcdir)/'`tpm_platform.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_platform.Tpo $(DEPDIR)/libtpms_la-tpm_platform.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_platform.c' object='libtpms_la-tpm_platform.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_platform.lo `test -f 'tpm_platform.c' || echo '$(srcdir)/'`tpm_platform.c + +libtpms_la-tpm_process.lo: tpm_process.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_process.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_process.Tpo -c -o libtpms_la-tpm_process.lo `test -f 'tpm_process.c' || echo '$(srcdir)/'`tpm_process.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_process.Tpo $(DEPDIR)/libtpms_la-tpm_process.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_process.c' object='libtpms_la-tpm_process.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_process.lo `test -f 'tpm_process.c' || echo '$(srcdir)/'`tpm_process.c + +libtpms_la-tpm_secret.lo: tpm_secret.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_secret.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_secret.Tpo -c -o libtpms_la-tpm_secret.lo `test -f 'tpm_secret.c' || echo '$(srcdir)/'`tpm_secret.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_secret.Tpo $(DEPDIR)/libtpms_la-tpm_secret.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_secret.c' object='libtpms_la-tpm_secret.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_secret.lo `test -f 'tpm_secret.c' || echo '$(srcdir)/'`tpm_secret.c + +libtpms_la-tpm_session.lo: tpm_session.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_session.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_session.Tpo -c -o libtpms_la-tpm_session.lo `test -f 'tpm_session.c' || echo '$(srcdir)/'`tpm_session.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_session.Tpo $(DEPDIR)/libtpms_la-tpm_session.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_session.c' object='libtpms_la-tpm_session.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_session.lo `test -f 'tpm_session.c' || echo '$(srcdir)/'`tpm_session.c + +libtpms_la-tpm_sizedbuffer.lo: tpm_sizedbuffer.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_sizedbuffer.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_sizedbuffer.Tpo -c -o libtpms_la-tpm_sizedbuffer.lo `test -f 'tpm_sizedbuffer.c' || echo '$(srcdir)/'`tpm_sizedbuffer.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_sizedbuffer.Tpo $(DEPDIR)/libtpms_la-tpm_sizedbuffer.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_sizedbuffer.c' object='libtpms_la-tpm_sizedbuffer.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_sizedbuffer.lo `test -f 'tpm_sizedbuffer.c' || echo '$(srcdir)/'`tpm_sizedbuffer.c + +libtpms_la-tpm_startup.lo: tpm_startup.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_startup.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_startup.Tpo -c -o libtpms_la-tpm_startup.lo `test -f 'tpm_startup.c' || echo '$(srcdir)/'`tpm_startup.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_startup.Tpo $(DEPDIR)/libtpms_la-tpm_startup.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_startup.c' object='libtpms_la-tpm_startup.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_startup.lo `test -f 'tpm_startup.c' || echo '$(srcdir)/'`tpm_startup.c + +libtpms_la-tpm_store.lo: tpm_store.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_store.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_store.Tpo -c -o libtpms_la-tpm_store.lo `test -f 'tpm_store.c' || echo '$(srcdir)/'`tpm_store.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_store.Tpo $(DEPDIR)/libtpms_la-tpm_store.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_store.c' object='libtpms_la-tpm_store.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_store.lo `test -f 'tpm_store.c' || echo '$(srcdir)/'`tpm_store.c + +libtpms_la-tpm_storage.lo: tpm_storage.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_storage.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_storage.Tpo -c -o libtpms_la-tpm_storage.lo `test -f 'tpm_storage.c' || echo '$(srcdir)/'`tpm_storage.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_storage.Tpo $(DEPDIR)/libtpms_la-tpm_storage.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_storage.c' object='libtpms_la-tpm_storage.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_storage.lo `test -f 'tpm_storage.c' || echo '$(srcdir)/'`tpm_storage.c + +libtpms_la-tpm_ticks.lo: tpm_ticks.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_ticks.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_ticks.Tpo -c -o libtpms_la-tpm_ticks.lo `test -f 'tpm_ticks.c' || echo '$(srcdir)/'`tpm_ticks.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_ticks.Tpo $(DEPDIR)/libtpms_la-tpm_ticks.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_ticks.c' object='libtpms_la-tpm_ticks.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_ticks.lo `test -f 'tpm_ticks.c' || echo '$(srcdir)/'`tpm_ticks.c + +libtpms_la-tpm_time.lo: tpm_time.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_time.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_time.Tpo -c -o libtpms_la-tpm_time.lo `test -f 'tpm_time.c' || echo '$(srcdir)/'`tpm_time.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_time.Tpo $(DEPDIR)/libtpms_la-tpm_time.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_time.c' object='libtpms_la-tpm_time.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_time.lo `test -f 'tpm_time.c' || echo '$(srcdir)/'`tpm_time.c + +libtpms_la-tpm_tis.lo: tpm_tis.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_tis.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_tis.Tpo -c -o libtpms_la-tpm_tis.lo `test -f 'tpm_tis.c' || echo '$(srcdir)/'`tpm_tis.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_tis.Tpo $(DEPDIR)/libtpms_la-tpm_tis.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_tis.c' object='libtpms_la-tpm_tis.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_tis.lo `test -f 'tpm_tis.c' || echo '$(srcdir)/'`tpm_tis.c + +libtpms_la-tpm_transport.lo: tpm_transport.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_transport.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_transport.Tpo -c -o libtpms_la-tpm_transport.lo `test -f 'tpm_transport.c' || echo '$(srcdir)/'`tpm_transport.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_transport.Tpo $(DEPDIR)/libtpms_la-tpm_transport.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_transport.c' object='libtpms_la-tpm_transport.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_transport.lo `test -f 'tpm_transport.c' || echo '$(srcdir)/'`tpm_transport.c + +libtpms_la-tpm_ver.lo: tpm_ver.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_ver.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_ver.Tpo -c -o libtpms_la-tpm_ver.lo `test -f 'tpm_ver.c' || echo '$(srcdir)/'`tpm_ver.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_ver.Tpo $(DEPDIR)/libtpms_la-tpm_ver.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_ver.c' object='libtpms_la-tpm_ver.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_ver.lo `test -f 'tpm_ver.c' || echo '$(srcdir)/'`tpm_ver.c + +libtpms_la-tpm_svnrevision.lo: tpm_svnrevision.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_svnrevision.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_svnrevision.Tpo -c -o libtpms_la-tpm_svnrevision.lo `test -f 'tpm_svnrevision.c' || echo '$(srcdir)/'`tpm_svnrevision.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_svnrevision.Tpo $(DEPDIR)/libtpms_la-tpm_svnrevision.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_svnrevision.c' object='libtpms_la-tpm_svnrevision.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_svnrevision.lo `test -f 'tpm_svnrevision.c' || echo '$(srcdir)/'`tpm_svnrevision.c + +libtpms_la-tpm_crypto_freebl.lo: tpm_crypto_freebl.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_crypto_freebl.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_crypto_freebl.Tpo -c -o libtpms_la-tpm_crypto_freebl.lo `test -f 'tpm_crypto_freebl.c' || echo '$(srcdir)/'`tpm_crypto_freebl.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_crypto_freebl.Tpo $(DEPDIR)/libtpms_la-tpm_crypto_freebl.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_crypto_freebl.c' object='libtpms_la-tpm_crypto_freebl.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_crypto_freebl.lo `test -f 'tpm_crypto_freebl.c' || echo '$(srcdir)/'`tpm_crypto_freebl.c + +libtpms_la-tpm_crypto.lo: tpm_crypto.c +@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -MT libtpms_la-tpm_crypto.lo -MD -MP -MF $(DEPDIR)/libtpms_la-tpm_crypto.Tpo -c -o libtpms_la-tpm_crypto.lo `test -f 'tpm_crypto.c' || echo '$(srcdir)/'`tpm_crypto.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libtpms_la-tpm_crypto.Tpo $(DEPDIR)/libtpms_la-tpm_crypto.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='tpm_crypto.c' object='libtpms_la-tpm_crypto.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libtpms_la_CFLAGS) $(CFLAGS) -c -o libtpms_la-tpm_crypto.lo `test -f 'tpm_crypto.c' || echo '$(srcdir)/'`tpm_crypto.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-libLTLIBRARIES + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am check-local clean \ + clean-generic clean-libLTLIBRARIES clean-libtool ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-libLTLIBRARIES + + +check-local: + @($(CC) $(LDFLAGS_ARCH) -nostdlib -L./.libs -ltpms 2>/dev/null || \ + (echo "There are undefined symbols in libtpms ($(LDFLAGS_ARCH))";\ + $(CC) $(LDFLAGS_ARCH) -nostdlib -L./.libs -ltpms 2>&1 | grep libtpms)) + @$(CC) $(LDFLAGS_ARCH) -nostdlib -L./.libs -ltpms 2>/dev/null + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/libtpms.syms b/src/libtpms.syms new file mode 100644 index 00000000..86a43728 --- /dev/null +++ b/src/libtpms.syms @@ -0,0 +1,22 @@ +# Symbol file for the linker. For newer versions add new sections. + +LIBTPMS_0.5.1 { + global: + TPM_IO_Hash_Data; + TPM_IO_Hash_End; + TPM_IO_Hash_Start; + TPM_IO_TpmEstablished_Get; + TPMLIB_DecodeBlob; + TPMLIB_GetTPMProperty; + TPMLIB_GetVersion; + TPMLIB_MainInit; + TPMLIB_Process; + TPMLIB_RegisterCallbacks; + TPMLIB_Terminate; + TPMLIB_VolatileAll_Store; + TPM_Free; + TPM_Malloc; + TPM_Realloc; + local: + *; +}; diff --git a/src/tpm_admin.c b/src/tpm_admin.c new file mode 100644 index 00000000..6b795e0e --- /dev/null +++ b/src/tpm_admin.c @@ -0,0 +1,2004 @@ +/********************************************************************************/ +/* */ +/* TPM Admin Test and Opt-in */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_admin.c 4505 2011-03-20 17:43:27Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_cryptoh.h" +#include "tpm_digest.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_ticks.h" +#include "tpm_time.h" + +#include "tpm_admin.h" + +/* The Software TPM Self Test works as follows: + + TPM_LimitedSelfTestCommon(void) - self tests which affect all TPM's + TPM_LimitedSelfTestTPM(tpm_state) - self test per virtual TPM + + TPM_ContinueSelfTestCmd(tpm_state) - currently does nothing + on failure, sets tpm_state->testState to failure for the virtual TPM + + TPM_SelfTestFullCmd(tpm_state) calls + TPM_LimitedSelfTestTPM() + TPM_ContinueSelfTestCmd(tpm_state) + on failure, sets tpm_state->testState to failure for the virtual TPM + + TPM_MainInit(void) calls + TPM_LimitedSelfTestCommon(void) + TPM_LimitedSelfTestTPM(tpm_state) + + TPM_Process_ContinueSelfTest(tpm_state) calls either (depending on FIPS mode) + TPM_SelfTestFullCmd(tpm_state) + TPM_ContinueSelfTestCmd(tpm_state) + + TPM_Process_SelfTestFull(tpm_state) calls + TPM_SelfTestFullCmd(tpm_state) + + The Software TPM assumes that the coprocessor has run self tests before the application code even + begins. So this code doesn't do any real testing of the underlying hardware. This simplifies + the state machine, since TPM_Process_ContinueSelfTest doesn't require a separate thread. +*/ + +/* TPM_LimitedSelfTestCommon() provides the assurance that a selected subset of TPM commands will + perform properly. The limited nature of the self-test allows the TPM to be functional in as short + of time as possible. all the TPM tests. + + The caller is responsible for setting the shutdown state on error. +*/ + +TPM_RESULT TPM_LimitedSelfTestCommon(void) +{ + TPM_RESULT rc = 0; + uint32_t tv_sec; + uint32_t tv_usec; + + printf(" TPM_LimitedSelfTestCommon:\n"); +#if 0 + if (rc == 0) { + rc = TPM_Sbuffer_Test(); + } +#endif + if (rc == 0) { + rc = TPM_Uint64_Test(); + } + if (rc == 0) { + rc = TPM_CryptoTest(); + } + /* test time of day clock */ + if (rc == 0) { + rc = TPM_GetTimeOfDay(&tv_sec, &tv_usec); + } + if (rc != 0) { + rc = TPM_FAILEDSELFTEST; + } + return rc; +} + +TPM_RESULT TPM_LimitedSelfTestTPM(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_NONCE clrData; + TPM_SIZED_BUFFER encData; + TPM_NONCE decData; + uint32_t decLength; + + + printf(" TPM_LimitedSelfTestTPM:\n"); + TPM_SizedBuffer_Init(&encData); /* freed @1 */ + + /* 8. The TPM MUST check the following: */ + /* a. RNG functionality */ + /* NOTE Tested by coprocessor boot */ + /* b. Reading and extending the integrity registers. The self-test for the integrity registers + will leave the integrity registers in a known state. */ + /* NOTE Since there is nothing special about the PCR's, the common TPM_CryptoTest() is + sufficient */ + /* c. Testing the EK integrity, if it exists */ + /* i. This requirement specifies that the TPM will verify that the endorsement key pair can + encrypt and decrypt a known value. This tests the RSA engine. If the EK has not yet been + generated the TPM action is manufacturer specific. */ + if ((rc == 0) && + (tpm_state->tpm_permanent_data.endorsementKey.keyUsage != TPM_KEY_UNINITIALIZED)) { + /* check the key integrity */ + if (rc == 0) { + rc = TPM_Key_CheckPubDataDigest(&(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* encrypt */ + if (rc == 0) { + TPM_Nonce_Generate(clrData); + rc = TPM_RSAPublicEncrypt_Key(&encData, /* output */ + clrData, /* input */ + TPM_NONCE_SIZE, /* input */ + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* decrypt */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptH(decData, /* decrypted data */ + &decLength, /* length of data put into decrypt_data */ + TPM_NONCE_SIZE, /* size of decrypt_data buffer */ + encData.buffer, + encData.size, + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* verify */ + if (rc == 0) { + if (decLength != TPM_NONCE_SIZE) { + printf("TPM_LimitedSelfTestTPM: Error, decrypt length %u should be %u\n", + decLength, TPM_NONCE_SIZE); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + rc = TPM_Nonce_Compare(clrData, decData); + } + } + /* d. The integrity of the protected capabilities of the TPM */ + /* i. This means that the TPM must ensure that its "microcode" has not changed, and not that a + test must be run on each function. */ + /* e. Any tamper-resistance markers */ + /* i. The tests on the tamper-resistance or tamper-evident markers are under programmable + control. */ + /* There is no requirement to check tamper-evident tape or the status of epoxy surrounding the + case. */ + /* NOTE: Done by coprocessor POST */ + /* 9. The TPM SHOULD check the following: */ + /* a. The hash functionality */ + /* i. This check will hash a known value and compare it to an expected result. There is no + requirement to accept external data to perform the check. */ + /* ii. The TPM MAY support a test using external data. */ + /* NOTE: Done by TPM_CryptoTest() */ + /* b. Any symmetric algorithms */ + /* i. This check will use known data with a random key to encrypt and decrypt the data */ + /* NOTE: Done by TPM_CryptoTest() */ + /* c. Any additional asymmetric algorithms */ + /* i. This check will use known data to encrypt and decrypt. */ + /* NOTE: So far only RSA is supported */ + /* d. The key-wrapping mechanism */ + /* i. The TPM should wrap and unwrap a key. The TPM MUST NOT use the endorsement key pair for + this test. */ + /* NOTE: There is nothing special about serializing a TPM_STORE_ASYMKEY */ + /* e. Any other internal mechanisms */ + TPM_SizedBuffer_Delete(&encData); /* @1 */ + if (rc != 0) { + rc = TPM_FAILEDSELFTEST; + } + /* set the TPM test state */ + if ((rc == 0) && (tpm_state->testState != TPM_TEST_STATE_FAILURE)) { + printf(" TPM_LimitedSelfTestTPM: Set testState to %u \n", TPM_TEST_STATE_LIMITED); + tpm_state->testState = TPM_TEST_STATE_LIMITED; + } + else { + printf(" TPM_LimitedSelfTestTPM: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return rc; +} + +/* TPM_ContinueSelfTestCmd() runs the continue self test actions + +*/ + +TPM_RESULT TPM_ContinueSelfTestCmd(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + /* NOTE all done by limited self test */ + printf(" TPM_ContinueSelfTestCmd:\n"); + if (rc != 0) { + rc = TPM_FAILEDSELFTEST; + } + /* set the TPM test state */ + if (rc == 0) { + printf(" TPM_ContinueSelfTestCmd: Set testState to %u \n", TPM_TEST_STATE_FULL); + tpm_state->testState = TPM_TEST_STATE_FULL; + } + else { + printf(" TPM_ContinueSelfTestCmd: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return rc; +} + +/* TPM_SelfTestFullCmd is a request to have the TPM perform another complete self-test. This test + will take some time but provides an accurate assessment of the TPM's ability to perform all + operations. + + Runs the actions of self test full. +*/ + +TPM_RESULT TPM_SelfTestFullCmd(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SelfTestFullCmd\n"); + if (rc == 0) { + rc = TPM_LimitedSelfTestTPM(tpm_state); + } + if (rc == 0) { + rc = TPM_ContinueSelfTestCmd(tpm_state); + } + return rc; +} + +/* 4.1 TPM_SelfTestFull rev 88 + + SelfTestFull tests all of the TPM capabilities. + + Unlike TPM_ContinueSelfTest, which may optionally return immediately and then perform the tests, + TPM_SelfTestFull always performs the tests and then returns success or failure. +*/ + +TPM_RESULT TPM_Process_SelfTestFull(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SelfTestFull: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SelfTestFull: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. TPM_SelfTestFull SHALL cause a TPM to perform self-test of each TPM internal function. */ + /* a. If the self-test succeeds, return TPM_SUCCESS. */ + /* b. If the self-test fails, return TPM_FAILEDSELFTEST. */ + /* 2. Failure of any test results in overall failure, and the TPM goes into failure mode. */ + /* 3. If the TPM has not executed the action of TPM_ContinueSelfTest, the TPM */ + /* a. MAY perform the full self-test. */ + /* b. MAY return TPM_NEEDS_SELFTEST. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SelfTestFullCmd(tpm_state); + } + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_SelfTestFull: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 4.2 TPM_ContinueSelfTest rev 88 + + TPM_Process_ContinueSelfTest informs the TPM that it may complete the self test of all TPM + functions. + + The TPM may return success immediately and then perform the self-test, or it may perform the + self-test and then return success or failure. + + 1. Prior to executing the actions of TPM_ContinueSelfTest, if the TPM receives a command C1 that + uses an untested TPM function, the TPM MUST take one of these actions: + + a. The TPM MAY return TPM_NEEDS_SELFTEST + + i. This indicates that the TPM has not tested the internal resources required to execute C1. + + ii. The TPM does not execute C1. + + iii. The caller MUST issue TPM_ContinueSelfTest before re-issuing the command C1. + + (1) If the TPM permits TPM_SelfTestFull prior to completing the actions of TPM_ContinueSelfTest, + the caller MAY issue TPM_SelfTestFull rather than TPM_ContinueSelfTest. + + b. The TPM MAY return TPM_DOING_SELFTEST + + i. This indicates that the TPM is doing the actions of TPM_ContinueSelfTest implicitly, as if the + TPM_ContinueSelfTest command had been issued. + + ii. The TPM does not execute C1. + + iii. The caller MUST wait for the actions of TPM_ContinueSelfTest to complete before reissuing + the command C1. + + c. The TPM MAY return TPM_SUCCESS or an error code associated with C1. + + i. This indicates that the TPM has completed the actions of TPM_ContinueSelfTest and has + completed the command C1. + + ii. The error code MAY be TPM_FAILEDSELFTEST. +*/ + +TPM_RESULT TPM_Process_ContinueSelfTest(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ContinueSelfTest: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ContinueSelfTest: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* 1. If TPM_PERMANENT_FLAGS -> FIPS is TRUE or TPM_PERMANENT_FLAGS -> TPMpost is TRUE */ + if ((tpm_state->tpm_permanent_flags.FIPS) || + (tpm_state->tpm_permanent_flags.TPMpost)) { + /* a. The TPM MUST run ALL self-tests */ + returnCode = TPM_SelfTestFullCmd(tpm_state); + } + /* 2. Else */ + else { + /* a. The TPM MUST complete all self-tests that are outstanding */ + /* i. Instead of completing all outstanding self-tests the TPM MAY run all self-tests */ + returnCode = TPM_ContinueSelfTestCmd(tpm_state); + } + } + /* 3. The TPM either + a. MAY immediately return TPM_SUCCESS + i. When TPM_ContinueSelfTest finishes execution, it MUST NOT respond to the caller with a + return code. + b. MAY complete the self-test and then return TPM_SUCCESS or TPM_FAILEDSELFTEST. + NOTE Option 3.b. implemented + */ + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_ContinueSelfTest: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 4.3 TPM_GetTestResult rev 96 + + TPM_GetTestResult provides manufacturer specific information regarding the results of the self + test. This command will work when the TPM is in self test failure mode. The reason for allowing + this command to operate in the failure mode is to allow TPM manufacturers to obtain diagnostic + information. +*/ + +TPM_RESULT TPM_Process_GetTestResult(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outData; /* The outData this is manufacturer specific */ + + printf("TPM_Process_GetTestResult: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&outData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + /* This command will work when the TPM is in self test failure or limited operation mode. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_NO_LOCKOUT); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetTestResult: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM SHALL respond to this command with a manufacturer specific block of information + that describes the result of the latest self test. */ + /* 2. The information MUST NOT contain any data that uniquely identifies an individual TPM. */ + /* allocate some reasonable area */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Allocate(&outData, 128); + } + /* for now, just return the state of shutdown as a printable string */ + if (returnCode == TPM_SUCCESS) { + /* cast because TPM_SIZED_BUFFER is typically unsigned (binary) but sprintf expects char */ + outData.size = sprintf((char *)(outData.buffer), "Shutdown %08x\n", tpm_state->testState); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetTestResult: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&outData); /* @1 */ + return rcf; +} + +/* 5.1 TPM_SetOwnerInstall rev 100 + + When enabled but without an owner this command sets the PERMANENT flag that allows or disallows + the ability to insert an owner. + */ + +TPM_RESULT TPM_Process_SetOwnerInstall(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_BOOL state; /* State to which ownership flag is to be set. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetOwnerInstall: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&state, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetOwnerInstall: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* 1. If the TPM has a current owner, this command immediately returns with TPM_SUCCESS. */ + if (tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_SetOwnerInstall: Already current owner\n"); + } + /* If the TPM does not have a current owner */ + else { + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerInstall: No current owner\n"); + /* 2. The TPM validates the assertion of physical presence. The TPM then sets the + value of TPM_PERMANENT_FLAGS -> ownership to the value in state. + */ + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_SetOwnerInstall: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerInstall: Setting ownership to %02x\n", state); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.ownership), /* flag */ + state); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetOwnerInstall: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 5.2 TPM_OwnerSetDisable rev 107 + + The TPM owner sets the PERMANENT disable flag to TRUE or FALSE. +*/ + +TPM_RESULT TPM_Process_OwnerSetDisable(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_BOOL disableState; /* Value for disable state */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_OwnerSetDisable: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get disableState parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&disableState, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_OWNER | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OwnerSetDisable: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. The TPM SHALL authenticate the command as coming from the TPM Owner. If unsuccessful, the + TPM SHALL return TPM_AUTHFAIL. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. The TPM SHALL set the TPM_PERMANENT_FLAGS -> disable flag to the value in the + disableState parameter. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OwnerSetDisable: Setting disable to %u\n", disableState); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.disable), /* flag */ + disableState); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OwnerSetDisable: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + return rcf; +} + +/* 5.3 TPM_PhysicalEnable rev 87 + + Sets the PERMANENT disable flag to FALSE using physical presence as authorization. +*/ + +TPM_RESULT TPM_Process_PhysicalEnable(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_PhysicalEnable: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PhysicalEnable: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that physical presence is being asserted, if not return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_PhysicalEnable: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 2. The TPM SHALL set the TPM_PERMANENT_FLAGS.disable value to FALSE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PhysicalEnable: Setting disable to FALSE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.disable), /* flag */ + FALSE); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PhysicalEnable: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 5.4 TPM_PhysicalDisable rev 87 + + Sets the PERMANENT disable flag to TRUE using physical presence as authorization +*/ + +TPM_RESULT TPM_Process_PhysicalDisable(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_PhysicalDisable: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_ENABLED | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PhysicalDisable: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that physical presence is being asserted, if not return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_PhysicalDisable: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 2. The TPM SHALL set the TPM_PERMANENT_FLAGS.disable value to TRUE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PhysicalDisable: Setting disable to TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.disable ), /* flag */ + TRUE); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PhysicalDisable: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 5.5 TPM_PhysicalSetDeactivated rev 105 + + Changes the TPM persistent deactivated flag using physical presence as authorization. +*/ + +TPM_RESULT TPM_Process_PhysicalSetDeactivated(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_BOOL state; /* State to which deactivated flag is to be set. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_PhysicalSetDeactivated: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get state parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&state, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PhysicalSetDeactivated: state %02x\n", state); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_ENABLED | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PhysicalSetDeactivated: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that physical presence is being asserted, if not return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_PhysicalSetDeactivated: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 2. The TPM SHALL set the TPM_PERMANENT_FLAGS.deactivated flag to the value in the state + parameter. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PhysicalSetDeactivated: Setting deactivated to %u\n", state); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.deactivated), /* flag */ + state); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PhysicalSetDeactivated: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 5.6 TPM_SetTempDeactivated rev 87 + + This command allows the operator of the platform to deactivate the TPM until the next boot of the + platform. + + This command requires operator authorization. The operator can provide the authorization by + either the assertion of physical presence or presenting the operation authorization value. +*/ + +TPM_RESULT TPM_Process_SetTempDeactivated(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* auth handle for operation validation. Session type must + be OIAP. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization handle */ + TPM_AUTHDATA operatorAuth; /* HMAC key: operatorAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; +#if TPM_V12 + TPM_BOOL physicalPresence; +#endif + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetTempDeactivated: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_ACTIVATED | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { +#if TPM_V12 + returnCode = TPM_CheckRequestTag10(tag); +#else /* v1.1 is always auth0. This check implicitly bypasses the operatorAuth Actions below. */ + returnCode = TPM_CheckRequestTag0(tag); +#endif + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + operatorAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetTempDeactivated: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. If tag = TPM_TAG_REQ_AUTH1_COMMAND */ + /* a. If TPM_PERMANENT_FLAGS -> operator is FALSE return TPM_NOOPERATOR */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + if (!tpm_state->tpm_permanent_flags.tpmOperator) { + printf("TPM_Process_SetTempDeactivated: Error, no operator\n"); + returnCode = TPM_NOOPERATOR; + } + } + /* b. Validate command and parameters using operatorAuth, on error return TPM_AUTHFAIL */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf(" TPM_Process_SetTempDeactivated: authHandle %08x\n", authHandle); + /* get the session data */ + returnCode = + TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OIAP, + 0, /* OSAP entity type */ + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.operatorAuth), /* OIAP */ + NULL); /* OSAP */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* operator HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + operatorAuth); /* Authorization digest for input */ + + } +#if TPM_V12 /* v1.1 does not require physical presence */ + /* 2. Else */ + /* a. If physical presence is not asserted the TPM MUST return TPM_BAD_PRESENCE */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (!physicalPresence) { + printf("TPM_Process_SetTempDeactivated: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } +#endif + /* 3. The TPM SHALL set the TPM_STCLEAR_FLAGS.deactivated flag to the value TRUE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetTempDeactivated: Setting deactivated to TRUE\n"); + tpm_state->tpm_stclear_flags.deactivated = TRUE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetTempDeactivated: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* operator HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 5.7 TPM_SetOperatorAuth rev 87 + + 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. If there is a concern regarding the path between the + TPM and the keyboard then unless the keyboard is using encryption and a secure channel an + attacker can read the values. +*/ + +TPM_RESULT TPM_Process_SetOperatorAuth(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_SECRET operatorAuth; /* The operator authorization */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetOperatorAuth: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get operatorAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Secret_Load(operatorAuth, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetOperatorAuth: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If physical presence is not asserted the TPM MUST return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_SetOperatorAuth: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + if (returnCode == TPM_SUCCESS) { + /* 2. The TPM SHALL set the TPM_PERSISTENT_DATA -> operatorAuth */ + TPM_Digest_Copy(tpm_state->tpm_permanent_data.operatorAuth, operatorAuth); + /* 3. The TPM SHALL set TPM_PERMANENT_FLAGS -> operator to TRUE */ + printf("TPM_Process_SetOperatorAuth: Setting operator to TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.tpmOperator), /* flag */ + TRUE); /* value */ + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetOperatorAuth: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 9.3 TPM_ResetLockValue rev 96 + + Command that resets the TPM dictionary attack mitigation values + + This allows the TPM owner to cancel the effect of a number of successive authorization failures. + + If this command itself has an authorization failure, it is blocked for the remainder of the lock + out period. This prevents a dictionary attack on the owner authorization using this command. + + It is understood that this command allows the TPM owner to perform a dictionary attack on other + authorization values by alternating a trial and this command. Similarly, delegating this command + allows the owner's delegate to perform a dictionary attack. +*/ + +TPM_RESULT TPM_Process_ResetLockValue(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for TPM Owner + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* HMAC key TPM Owner auth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ResetLockValue: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + /* Update disableResetLock. Ignore the return code since this command is not locked out */ + TPM_Authdata_CheckState(tpm_state); + /* NOTE No TPM_CHECK_NO_LOCKOUT, since this command proceeds anyway */ + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_ENABLED | + TPM_CHECK_ACTIVATED | + TPM_CHECK_OWNER)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ResetLockValue: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. If TPM_STCLEAR_DATA -> disableResetLock is TRUE return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_stclear_data.disableResetLock) { + printf("TPM_Process_ResetLockValue: Error, command locked out\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* a. The internal dictionary attack mechanism will set TPM_STCLEAR_DATA -> disableResetLock to + FALSE when the timeout period expires */ + /* NOTE Done by TPM_Authdata_CheckState() */ + /* Validate the parameters and owner authorization for this command */ + if (returnCode == TPM_SUCCESS) { + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. If the the command and parameters validation using ownerAuth fails */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_ResetLockValue: Error, disabling ordinal\n"); + /* a. Set TPM_STCLEAR_DATA -> disableResetLock to TRUE */ + tpm_state->tpm_stclear_data.disableResetLock = TRUE; + /* b. Restart the TPM dictionary attack lock out period */ + /* A failure restarts it anyway with double the period.*/ + /* c. Return TPM_AUTHFAIL */ + } + } + /* 3. Reset the internal TPM dictionary attack mitigation mechanism */ + /* a. The mechanism is vendor specific and can include time outs, reboots, and other mitigation + strategies */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ResetLockValue: Resetting the failure counter\n"); + /* clear the authorization failure counter */ + tpm_state->tpm_stclear_data.authFailCount = 0; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ResetLockValue: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + return rcf; +} + diff --git a/src/tpm_admin.h b/src/tpm_admin.h new file mode 100644 index 00000000..f162ee41 --- /dev/null +++ b/src/tpm_admin.h @@ -0,0 +1,141 @@ +/********************************************************************************/ +/* */ +/* TPM Admin Test and Opt-in */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_admin.h 4403 2011-02-08 18:28:22Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_ADMIN_H +#define TPM_ADMIN_H + +#include "tpm_types.h" +#include "tpm_global.h" +#include "tpm_store.h" + +TPM_RESULT TPM_LimitedSelfTestCommon(void); +TPM_RESULT TPM_LimitedSelfTestTPM(tpm_state_t *tpm_state); + +TPM_RESULT TPM_ContinueSelfTestCmd(tpm_state_t *tpm_state); +TPM_RESULT TPM_SelfTestFullCmd(tpm_state_t *tpm_state); + +TPM_RESULT TPM_Process_ContinueSelfTest(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_SelfTestFull(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_GetTestResult(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_SetOwnerInstall(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_OwnerSetDisable(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_PhysicalDisable(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_PhysicalEnable(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_PhysicalSetDeactivated(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_SetTempDeactivated(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_SetOperatorAuth(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_ResetLockValue(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +#endif diff --git a/src/tpm_audit.c b/src/tpm_audit.c new file mode 100644 index 00000000..751a282c --- /dev/null +++ b/src/tpm_audit.c @@ -0,0 +1,1271 @@ +/********************************************************************************/ +/* */ +/* Audit Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_audit.c 4438 2011-02-13 23:03:56Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_counter.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_global.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_permanent.h" +#include "tpm_process.h" + +#include "tpm_audit.h" + +/* + TPM_AUDIT_EVENT_IN +*/ + +/* TPM_AuditEventIn_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_AuditEventIn_Init(TPM_AUDIT_EVENT_IN *tpm_audit_event_in) +{ + printf(" TPM_AuditEventIn_Init:\n"); + TPM_Digest_Init(tpm_audit_event_in->inputParms); + TPM_CounterValue_Init(&(tpm_audit_event_in->auditCount)); + return; +} + +/* TPM_AuditEventIn_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_AuditEventIn_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUDIT_EVENT_IN *tpm_audit_event_in) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuditEventIn_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_AUDIT_EVENT_IN); + } + /* store inputParms */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_audit_event_in->inputParms); + } + /* store auditCount */ + if (rc == 0) { + rc = TPM_CounterValue_StorePublic(sbuffer, &(tpm_audit_event_in->auditCount)); + } + return rc; +} + +/* TPM_AuditEventIn_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_AuditEventIn_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_AuditEventIn_Delete(TPM_AUDIT_EVENT_IN *tpm_audit_event_in) +{ + printf(" TPM_AuditEventIn_Delete:\n"); + if (tpm_audit_event_in != NULL) { + TPM_AuditEventIn_Init(tpm_audit_event_in); + } + return; +} + +/* + TPM_AUDIT_EVENT_OUT +*/ + +/* TPM_AuditEventOut_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_AuditEventOut_Init(TPM_AUDIT_EVENT_OUT *tpm_audit_event_out) +{ + printf(" TPM_AuditEventOut_Init:\n"); + TPM_Digest_Init(tpm_audit_event_out->outputParms); + TPM_CounterValue_Init(&(tpm_audit_event_out->auditCount)); + return; +} + +/* TPM_AuditEventOut_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_AuditEventOut_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUDIT_EVENT_OUT *tpm_audit_event_out) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuditEventOut_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_AUDIT_EVENT_OUT); + } + /* store outputParms */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_audit_event_out->outputParms); + } + /* store auditCount */ + if (rc == 0) { + rc = TPM_CounterValue_StorePublic(sbuffer, &(tpm_audit_event_out->auditCount)); + } + return rc; +} + +/* TPM_AuditEventOut_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_AuditEventOut_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_AuditEventOut_Delete(TPM_AUDIT_EVENT_OUT *tpm_audit_event_out) +{ + printf(" TPM_AuditEventOut_Delete:\n"); + if (tpm_audit_event_out != NULL) { + TPM_AuditEventOut_Init(tpm_audit_event_out); + } + return; +} + +/* + ordinalAuditStatus Processing +*/ + +/* TPM_OrdinalAuditStatus_Init() initializes the TPM_PERMANENT_DATA 'ordinalAuditStatus' to the + default + + The flags are stored as a bit map to conserve NVRAM. + + The array is not written back to NVRAM. +*/ + +TPM_RESULT TPM_OrdinalAuditStatus_Init(TPM_PERMANENT_DATA *tpm_permanent_data) +{ + TPM_RESULT rc = 0; + TPM_COMMAND_CODE ord; /* iterate through all ordinals */ + TPM_BOOL auditDefault; /* result for an ordinal */ + TPM_BOOL altered; + + printf(" TPM_OrdinalAuditStatus_Init:\n"); + + for (ord = 0 ; (rc == 0) && (ord < TPM_ORDINALS_MAX) ; ord++) { + /* get the default audit state from the ordinals table */ + TPM_OrdinalTable_GetAuditDefault(&auditDefault, ord); + /* write to the TPM_PERMANENT_DATA bit map */ + rc = TPM_OrdinalAuditStatus_SetAuditStatus(&altered, tpm_permanent_data, auditDefault, ord); + } + /* hack for TSC ordinals */ + if (rc == 0) { + TPM_OrdinalTable_GetAuditDefault(&auditDefault, TSC_ORD_PhysicalPresence); + rc = TPM_OrdinalAuditStatus_SetAuditStatus(&altered, tpm_permanent_data, auditDefault, + TSC_ORD_PhysicalPresence); + } + if (rc == 0) { + TPM_OrdinalTable_GetAuditDefault(&auditDefault, TSC_ORD_ResetEstablishmentBit); + rc = TPM_OrdinalAuditStatus_SetAuditStatus(&altered, tpm_permanent_data, auditDefault, + TSC_ORD_ResetEstablishmentBit); + } + return rc; +} + +/* TPM_OrdinalAuditStatus_Store() stores a list of all ordinals being audited + */ + +TPM_RESULT TPM_OrdinalAuditStatus_Store(TPM_SIZED_BUFFER *ordinalList, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_COMMAND_CODE startOrdinal) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + TPM_COMMAND_CODE ord; + TPM_BOOL auditStatus; + + printf(" TPM_OrdinalAuditStatus_Store\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* scan through the ordinals array */ + for (ord = startOrdinal ; (rc == 0) && (ord < TPM_ORDINALS_MAX) ; ord++ ) { + /* determine if the ordinal being audited */ + if (rc == 0) { + rc = TPM_OrdinalAuditStatus_GetAuditStatus(&auditStatus, ord, tpm_permanent_data); + } + /* if being audited */ + if ((rc == 0) && auditStatus) { + rc = TPM_Sbuffer_Append32(&sbuffer, ord); /* append ordinal to the list */ + } + } + /* scan the TSC ordinals */ + if (rc == 0) { + if (rc == 0) { + rc = TPM_OrdinalAuditStatus_GetAuditStatus(&auditStatus, + TSC_ORD_PhysicalPresence, + tpm_permanent_data); + } + if ((rc == 0) && auditStatus) { + rc = TPM_Sbuffer_Append32(&sbuffer, TSC_ORD_PhysicalPresence); + } + if (rc == 0) { + rc = TPM_OrdinalAuditStatus_GetAuditStatus(&auditStatus, + TSC_ORD_ResetEstablishmentBit, + tpm_permanent_data); + } + /* if being audited */ + if ((rc == 0) && auditStatus) { + rc = TPM_Sbuffer_Append32(&sbuffer, TSC_ORD_ResetEstablishmentBit); + } + } + /* convert the list to a TPM_SIZED_BUFFER */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetFromStore(ordinalList, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_OrdinalAuditStatus_GetAuditState() gets the audit state for the ordinal + */ + +TPM_RESULT TPM_OrdinalAuditStatus_GetAuditStatus(TPM_BOOL *auditStatus, + TPM_COMMAND_CODE ordinal, + TPM_PERMANENT_DATA *tpm_permanent_data) +{ + TPM_RESULT rc = 0; + size_t index; /* index of ordinal in array */ + unsigned int offset; /* bit position of ordinal in array */ + unsigned char bit; + + if (rc == 0) { + /* handle the TPM ordinals */ + if (ordinal < TPM_ORDINALS_MAX) { + index = ordinal/CHAR_BIT; + offset = ordinal % CHAR_BIT; + bit = 0x01 << offset; + *auditStatus = tpm_permanent_data->ordinalAuditStatus[index] & bit; + } + /* handle the TSC ordinals */ + else if (ordinal == TSC_ORD_PhysicalPresence) { + *auditStatus = tpm_permanent_data->tscOrdinalAuditStatus & TSC_PHYS_PRES_AUDIT; + } + else if (ordinal == TSC_ORD_ResetEstablishmentBit) { + *auditStatus = tpm_permanent_data->tscOrdinalAuditStatus & TSC_RESET_ESTAB_AUDIT; + } + else { + printf("TPM_OrdinalAuditStatus_GetAuditStatus: Error (fatal) " + "ordinal %08x out of range\n", ordinal); + rc = TPM_FAIL; /* should never occur, always called with ordinal processing */ + } + } + /* trace the ordinals with auditing enabled */ + if ((rc == 0) && *auditStatus) { + printf(" TPM_OrdinalAuditStatus_GetAuditStatus: ordinal %08x status %02x\n", + ordinal, *auditStatus); + } + return rc; +} + +/* TPM_OrdinalAuditStatus_SetAuditStatus() sets the TPM_PERMANENT_DATA -> ordinalAuditStatus for the + ordinal + + The flags are stored as a bit map to conserve NVRAM. + + The array is not written back to NVRAM. On error, TPM_PERMANENT_DATA is not changed. + + altered is TRUE if the bit was changed, +*/ + +TPM_RESULT TPM_OrdinalAuditStatus_SetAuditStatus(TPM_BOOL *altered, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL auditStatus, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_BOOL auditable; /* TRUE if the ordinal is auditable by this TPM + implementation */ + size_t index; /* index of ordinal in array */ + unsigned int offset; /* bit position of ordinal in array */ + unsigned char bit; + + *altered = FALSE; /* default, returned on error */ +#if 0 + printf(" TPM_OrdinalAuditStatus_SetAuditStatus: ordinal %08x status %02x\n", + ordinal, auditStatus); +#endif + /* If trying to set, screen against the 'never audit' ordinal table */ + if ((rc == 0) && auditStatus) { + TPM_OrdinalTable_GetAuditable(&auditable, ordinal); + /* if it is a 'never audit' ordinal, it can not be set */ + if (!auditable) { + printf("TPM_OrdinalAuditStatus_SetAuditStatus: " + "Error, cannot audit ordinal %08x\n", ordinal); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + /* handle the TPM ordinals */ + if (ordinal < TPM_ORDINALS_MAX) { + index = ordinal/CHAR_BIT; + offset = ordinal % CHAR_BIT; + bit = 0x01 << offset; + /* determine if the bit is to be altered */ + if (((tpm_permanent_data->ordinalAuditStatus[index] & bit) && !auditStatus) || + (!(tpm_permanent_data->ordinalAuditStatus[index] & bit) && auditStatus)) { + + *altered = TRUE; + } + if (auditStatus) { + /* set the bit */ + tpm_permanent_data->ordinalAuditStatus[index] |= bit; + } + else { + /* clear the bit */ + tpm_permanent_data->ordinalAuditStatus[index] &= ~bit; + } + } + /* handle the TSC ordinals */ + else if (ordinal == TSC_ORD_PhysicalPresence) { + /* determine if the bit is to be altered */ + if (((tpm_permanent_data->tscOrdinalAuditStatus & TSC_PHYS_PRES_AUDIT) + && !auditStatus) || + (!(tpm_permanent_data->tscOrdinalAuditStatus & TSC_PHYS_PRES_AUDIT) + && auditStatus)) { + + *altered = TRUE; + } + if (auditStatus) { + tpm_permanent_data->tscOrdinalAuditStatus |= TSC_PHYS_PRES_AUDIT; + } + else { + tpm_permanent_data->tscOrdinalAuditStatus &= ~TSC_PHYS_PRES_AUDIT; + } + } + else if (ordinal == TSC_ORD_ResetEstablishmentBit) { + if (auditStatus) { + /* determine if the bit is to be altered */ + if (((tpm_permanent_data->tscOrdinalAuditStatus & TSC_RESET_ESTAB_AUDIT) + && !auditStatus) || + (!(tpm_permanent_data->tscOrdinalAuditStatus & TSC_RESET_ESTAB_AUDIT) + && auditStatus)) { + + *altered = TRUE; + } + tpm_permanent_data->tscOrdinalAuditStatus |= TSC_RESET_ESTAB_AUDIT; + } + else { + tpm_permanent_data->tscOrdinalAuditStatus &= ~TSC_RESET_ESTAB_AUDIT; + } + } + else { + printf("TPM_OrdinalAuditStatus_SetAuditStatus: Error ordinal %08x out of range\n", + ordinal); + rc = TPM_BADINDEX; + } + } + return rc; +} + +/* + Common Processing Functions +*/ + +/* 8.1 Audit Generation rev 109 + + TPM_AuditDigest_ExtendIn() extends the audit digest with a digest of input parameters +*/ + +TPM_RESULT TPM_AuditDigest_ExtendIn(tpm_state_t *tpm_state, + TPM_DIGEST inParamDigest) +{ + TPM_RESULT rc = 0; + TPM_AUDIT_EVENT_IN tpm_audit_event_in; + TPM_STORE_BUFFER eventIn_sbuffer; + const unsigned char *eventIn_buffer; /* serialized buffer */ + uint32_t eventIn_length; /* serialization length */ + + printf(" TPM_AuditDigest_ExtendIn:\n"); + TPM_AuditEventIn_Init(&tpm_audit_event_in); /* freed @1 */ + TPM_Sbuffer_Init(&eventIn_sbuffer); /* freed @2 */ + + if (rc == 0) { + /* b. Create A1 a TPM_AUDIT_EVENT_IN structure */ + /* NOTE Done by TPM_AuditEventIn_Init() */ + /* i. Set A1 -> inputParms to the digest of the input parameters from the command */ + /* (1) Digest value according to the HMAC digest rules of the "above the line" parameters + (i.e. the first HMAC digest calculation). */ + TPM_Digest_Copy(tpm_audit_event_in.inputParms, inParamDigest); + /* ii. Set A1 -> auditCount to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + TPM_CounterValue_CopyPublic(&(tpm_audit_event_in.auditCount), + &(tpm_state->tpm_permanent_data.auditMonotonicCounter)); + /* serialize the A1 TPM_AUDIT_EVENT_IN object */ + rc = TPM_AuditEventIn_Store(&eventIn_sbuffer, &tpm_audit_event_in); + + } + if (rc == 0) { + /* get the serialization results */ + TPM_Sbuffer_Get(&eventIn_sbuffer, &eventIn_buffer, &eventIn_length); + /* c. Set TPM_STANY_DATA -> auditDigest to SHA-1 (TPM_STANY_DATA -> auditDigest || A1) */ + TPM_PrintFour(" TPM_AuditDigest_ExtendIn: Previous digest", + tpm_state->tpm_stclear_data.auditDigest); + TPM_PrintAll(" TPM_AuditDigest_ExtendIn: TPM_AUDIT_EVENT_IN", eventIn_buffer, eventIn_length); + rc = TPM_SHA1(tpm_state->tpm_stclear_data.auditDigest, + TPM_DIGEST_SIZE, tpm_state->tpm_stclear_data.auditDigest, + eventIn_length, eventIn_buffer, + 0, NULL); + TPM_PrintFour(" TPM_AuditDigest_ExtendIn: Current digest (in)", + tpm_state->tpm_stclear_data.auditDigest); + } + TPM_AuditEventIn_Delete(&tpm_audit_event_in); /* @1 */ + TPM_Sbuffer_Delete(&eventIn_sbuffer); /* @2 */ + return rc; +} + +/* 8.1 Audit Generation rev 109 + + TPM_AuditDigest_ExtendOut() extends the audit digest with a digest of output parameters +*/ + +TPM_RESULT TPM_AuditDigest_ExtendOut(tpm_state_t *tpm_state, + TPM_DIGEST outParamDigest) +{ + TPM_RESULT rc = 0; + TPM_AUDIT_EVENT_OUT tpm_audit_event_out; + TPM_STORE_BUFFER eventOut_sbuffer; + const unsigned char *eventOut_buffer; /* serialized buffer */ + uint32_t eventOut_length; /* serialization length */ + + printf(" TPM_AuditDigest_ExtendOut:\n"); + TPM_AuditEventOut_Init(&tpm_audit_event_out); /* freed @1 */ + TPM_Sbuffer_Init(&eventOut_sbuffer); /* freed @2 */ + + if (rc == 0) { + /* d. Create A2 a TPM_AUDIT_EVENT_OUT structure */ + /* NOTE Done by TPM_AuditEventOut_Init() */ + /* i. Set A2 -> outputParms to the digest of the output parameters from the command */ + /* (1). Digest value according to the HMAC digest rules of the "above the line" parameters + (i.e. the first HMAC digest calculation). */ + TPM_Digest_Copy(tpm_audit_event_out.outputParms, outParamDigest); + /* ii. Set A2 -> auditCount to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + TPM_CounterValue_CopyPublic(&(tpm_audit_event_out.auditCount), + &(tpm_state->tpm_permanent_data.auditMonotonicCounter)); + /* serialize the A2 TPM_AUDIT_EVENT_OUT object */ + rc = TPM_AuditEventOut_Store(&eventOut_sbuffer, &tpm_audit_event_out); + } + if (rc == 0) { + /* get the serialization results */ + TPM_Sbuffer_Get(&eventOut_sbuffer, &eventOut_buffer, &eventOut_length); + /* e. Set TPM_STANY_DATA -> auditDigest to SHA-1 (TPM_STANY_DATA -> auditDigest || A2) */ + TPM_PrintFour(" TPM_AuditDigest_ExtendOut: Previous digest", + tpm_state->tpm_stclear_data.auditDigest); + TPM_PrintAll(" TPM_AuditDigest_ExtendOut: TPM_AUDIT_EVENT_OUT", eventOut_buffer, eventOut_length); + rc = TPM_SHA1(tpm_state->tpm_stclear_data.auditDigest, + TPM_DIGEST_SIZE, tpm_state->tpm_stclear_data.auditDigest, + eventOut_length, eventOut_buffer, + 0, NULL); + TPM_PrintFour(" TPM_AuditDigest_ExtendOut: Current digest (out)", + tpm_state->tpm_stclear_data.auditDigest); + } + TPM_AuditEventOut_Delete(&tpm_audit_event_out); /* @1 */ + TPM_Sbuffer_Delete(&eventOut_sbuffer); /* @2 */ + return rc; +} + +/* + Processing Functions +*/ + +/* The TPM generates an audit event in response to the TPM executing a command that has the audit + flag set to TRUE for that command. + + The TPM maintains an extended value for all audited operations. +*/ + +/* 8.3 TPM_GetAuditDigest rev 87 + + This returns the current audit digest. The external audit log has the responsibility to track the + parameters that constitute the audit digest. + + This value may be unique to an individual TPM. The value however will be changing at a rate set + by the TPM Owner. Those attempting to use this value may find it changing without their + knowledge. This value represents a very poor source of tracking uniqueness. +*/ + +TPM_RESULT TPM_Process_GetAuditDigest(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + uint32_t startOrdinal; /* The starting ordinal for the list of audited ordinals */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST auditDigest; /* Log of all audited events */ + TPM_BOOL more; /* TRUE if the output does not contain a full list of + audited ordinals */ + TPM_SIZED_BUFFER ordList; /* List of ordinals that are audited. */ + + printf("TPM_Process_GetAuditDigest: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&ordList); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get startOrdinal parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&startOrdinal, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetAuditDigest: startOrdinal %08x\n", startOrdinal); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetAuditDigest: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* 1. The TPM sets auditDigest to TPM_STANY_DATA -> auditDigest */ + TPM_Digest_Copy(auditDigest, tpm_state->tpm_stclear_data.auditDigest); + /* 2. The TPM sets counterValue to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + /* NOTE Since there is only one, use it directly on the output */ + printf("TPM_Process_GetAuditDigest: Counter value %08x\n", + tpm_state->tpm_permanent_data.auditMonotonicCounter.counter); + /* 3. The TPM creates an ordered list of audited ordinals. The list starts at startOrdinal + listing each ordinal that is audited. */ + /* a. If startOrdinal is 0 then the first ordinal that could be audited would be TPM_OIAP + (ordinal 0x0000000A) */ + /* b. The next ordinal would be TPM_OSAP (ordinal 0x0000000B) */ + returnCode = TPM_OrdinalAuditStatus_Store(&ordList, + &(tpm_state->tpm_permanent_data), + startOrdinal); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetAuditDigest: ordSize %u\n", ordList.size); + /* 4. If the ordered list does not fit in the output buffer the TPM sets more to TRUE */ + more = FALSE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetAuditDigest: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + /* append counterValue */ + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append counterValue */ + returnCode = TPM_CounterValue_StorePublic + (response, + &(tpm_state->tpm_permanent_data.auditMonotonicCounter)); + } + /* 5. Return TPM_STANY_DATA -> auditDigest as auditDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, auditDigest); + } + /* append more */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, &more, sizeof(TPM_BOOL)); + } + /* append ordList */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &ordList); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&ordList); /* @1 */ + return rcf; +} + +/* 8.4 TPM_GetAuditDigestSigned rev 101 + + The signing of the audit log returns 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. + + Note to future architects + + When auditing functionality is active in a TPM, it may seem logical to remove this ordinal from + the active set of ordinals as the signing functionality of this command could be handled in a + signed transport session. While true this command has a secondary affect also, resetting the + audit log digest. As the reset requires TPM Owner authentication there must be some way in this + command to reflect the TPM Owner wishes. By requiring that a TPM Identity key be the only key + that can sign and reset the TPM Owners authentication is implicit in the execution of the command + (TPM Identity Keys are created and controlled by the TPM Owner only). Hence while one might want + to remove an ordinal this is not one that can be removed if auditing is functional. +*/ + +TPM_RESULT TPM_Process_GetAuditDigestSigned(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The handle of a loaded key that can perform digital + signatures. */ + TPM_BOOL closeAudit; /* Indication if audit session should be closed */ + TPM_NONCE antiReplay; /* A nonce to prevent replay attacks */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for key + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA keyAuth; /* Authorization. HMAC key: key.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SIGN_INFO d1SignInfo; + TPM_SIZED_BUFFER d3SizedBuffer; /* List of ordinals that are audited. */ + TPM_STORE_BUFFER d2Sbuffer; /* data to be signed */ + TPM_DIGEST h1; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST ordinalDigest; /* Digest of all audited ordinals */ + TPM_SIZED_BUFFER sig; /* The signature of the area */ + + printf("TPM_Process_GetAuditDigestSigned: Ordinal Entry\n"); + TPM_SignInfo_Init(&d1SignInfo); /* freed @1 */ + TPM_SizedBuffer_Init(&d3SizedBuffer); /* freed @2 */ + TPM_Sbuffer_Init(&d2Sbuffer); /* freed @3 */ + TPM_SizedBuffer_Init(&sig); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get closeAudit parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetAuditDigestSigned: keyHandle %08x\n", keyHandle); + returnCode = TPM_LoadBool(&closeAudit, &command, ¶mSize); + } + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + keyAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetAuditDigestSigned: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the AuthData and parameters using keyAuth, return TPM_AUTHFAIL on error */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_GetAuditDigestSigned: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* validate the authorization to use the key pointed to by keyHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + keyAuth); /* Authorization digest for input */ + } + /* 2.Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or TPM_KEY_LEGACY, + if not return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + (sigKey->keyUsage != TPM_KEY_IDENTITY) && + (sigKey->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_GetAuditDigestSigned: Error, keyUsage %04hx is invalid\n", + sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. The TPM validates that the key pointed to by keyHandle has a signature scheme of + TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO, return TPM_INVALID_KEYUSAGE on + error */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_GetAuditDigestSigned: Error, invalid sigScheme%04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + if (returnCode == TPM_SUCCESS) { + /* 4. Create D1 a TPM_SIGN_INFO structure and set the structure defaults */ + /* NOTE Done by TPM_SignInfo_Init() */ + /* a. Set D1 -> fixed to "ADIG" */ + memcpy(d1SignInfo.fixed, "ADIG", TPM_SIGN_INFO_FIXED_SIZE); + /* b. Set D1 -> replay to antiReplay */ + TPM_Nonce_Copy(d1SignInfo.replay, antiReplay); + /* c. Create D3 a list of all audited ordinals as defined in the TPM_GetAuditDigest + uint32_t[] ordList outgoing parameter */ + returnCode = TPM_OrdinalAuditStatus_Store(&d3SizedBuffer, + &(tpm_state->tpm_permanent_data), + 0); + } + /* d. Create D4 (ordinalDigest outgoing parameter) the SHA-1 of D3 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(ordinalDigest, + d3SizedBuffer.size, d3SizedBuffer.buffer, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + /* e. Set auditDigest to TPM_STANY_DATA -> auditDigest */ + /* NOTE: Use it directly on the output */ + /* f. Set counterValue to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + /* NOTE Since there is only one, use it directly on the output */ + /* g. Create D2 the concatenation of auditDigest || counterValue || D4 */ + returnCode = TPM_Sbuffer_Append(&d2Sbuffer, + tpm_state->tpm_stclear_data.auditDigest, TPM_DIGEST_SIZE); + } + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_CounterValue_StorePublic(&d2Sbuffer, + &(tpm_state->tpm_permanent_data.auditMonotonicCounter)); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(&d2Sbuffer, + ordinalDigest, TPM_DIGEST_SIZE); + } + /* h. Set D1 -> data to D2 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(d1SignInfo.data), &d2Sbuffer); + } + /* i. Create a digital signature of the SHA-1 of D1 by using the signature scheme for keyHandle + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(h1, &d1SignInfo, + (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + h1, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* input, signing key */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_GetAuditDigestSigned: auditDigest", + tpm_state->tpm_stclear_data.auditDigest); + TPM_PrintFour("TPM_Process_GetAuditDigestSigned: ordinalDigest", + ordinalDigest); + } + /* j. Set ordinalDigest to D4 */ + /* NOTE Created directly in ordinalDigest */ + /* 5. If closeAudit == TRUE */ + if ((returnCode == TPM_SUCCESS) && closeAudit) { + /* a. If keyHandle->keyUsage is TPM_KEY_IDENTITY */ + if (sigKey->keyUsage == TPM_KEY_IDENTITY) { + /* i. TPM_STANY_DATA -> auditDigest MUST be set to all zeros. */ + TPM_Digest_Init(tpm_state->tpm_stclear_data.auditDigest); + } + /* b. Else */ + else { + /* i. Return TPM_INVALID_KEYUSAGE */ + printf("TPM_Process_GetAuditDigestSigned: Error, " + "cannot closeAudit with keyUsage %04hx\n", sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetAuditDigestSigned: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return counterValue */ + returnCode = TPM_CounterValue_StorePublic + (response, + &(tpm_state->tpm_permanent_data.auditMonotonicCounter)); + } + /* return auditDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, tpm_state->tpm_stclear_data.auditDigest); + } + /* return ordinalDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, ordinalDigest); + } + /* return sig */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SignInfo_Delete(&d1SignInfo); /* @1 */ + TPM_SizedBuffer_Delete(&d3SizedBuffer); /* @2 */ + TPM_Sbuffer_Delete(&d2Sbuffer); /* @3 */ + TPM_SizedBuffer_Delete(&sig); /* @4 */ + return rcf; +} + +/* 8.5 TPM_SetOrdinalAuditStatus rev 109 + + Set the audit flag for a given ordinal. This command requires the authentication of the TPM + Owner. +*/ + +TPM_RESULT TPM_Process_SetOrdinalAuditStatus(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_COMMAND_CODE ordinalToAudit; /* The ordinal whose audit flag is to be set */ + TPM_BOOL auditState; /* Value for audit flag */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL altered; /* status is changing */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetOrdinalAuditStatus: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get ordinalToAudit parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&ordinalToAudit, &command, ¶mSize); + } + /* get auditState parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&auditState, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOrdinalAuditStatus: ordinalToAudit %08x auditState %02x\n", + ordinalToAudit, auditState); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetOrdinalAuditStatus: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the AuthData to execute the command and the parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Validate that the ordinal points to a valid TPM ordinal, return TPM_BADINDEX on error */ + /* a. Valid TPM ordinal means an ordinal that the TPM implementation supports */ + /* Done by TPM_OrdinalAuditStatus_SetAuditState() */ + /* 3. Set the non-volatile flag associated with ordinalToAudit to the value in auditState */ + /* NOTE: On error, TPM_PERMANENT_DATA is not changed */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_OrdinalAuditStatus_SetAuditStatus(&altered, + &(tpm_state->tpm_permanent_data), + auditState, /* uninitialized */ + ordinalToAudit); + /* It's not really uninitialized, but beam doesn't understand that TPM_GetInParamDigest() + can't turn a FALSE into a TRUE */ + } + /* Store the permanent data back to NVRAM */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentAll_NVStore(tpm_state, + altered, + returnCode); + } + /* Audit Generation 3.b. Corner Cases: TPM_SetOrdinalAuditStatus: In the case where the + ordinalToAudit is TPM_ORD_SetOrdinalAuditStatus, audit is based on the initial state, not the + final state. */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetOrdinalAuditStatus: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + return rcf; +} diff --git a/src/tpm_audit.h b/src/tpm_audit.h new file mode 100644 index 00000000..4bb2e2e7 --- /dev/null +++ b/src/tpm_audit.h @@ -0,0 +1,117 @@ +/********************************************************************************/ +/* */ +/* Audit Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_audit.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_AUDIT_H +#define TPM_AUDIT_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_structures.h" + +/* + TPM_AUDIT_EVENT_IN +*/ + +void TPM_AuditEventIn_Init(TPM_AUDIT_EVENT_IN *tpm_audit_event_in); +TPM_RESULT TPM_AuditEventIn_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUDIT_EVENT_IN *tpm_audit_event_in); +void TPM_AuditEventIn_Delete(TPM_AUDIT_EVENT_IN *tpm_audit_event_in); + +/* + TPM_AUDIT_EVENT_OUT +*/ + +void TPM_AuditEventOut_Init(TPM_AUDIT_EVENT_OUT *tpm_audit_event_out); +TPM_RESULT TPM_AuditEventOut_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUDIT_EVENT_OUT *tpm_audit_event_out); +void TPM_AuditEventOut_Delete(TPM_AUDIT_EVENT_OUT *tpm_audit_event_out); + +/* + ordinalAuditStatus Processing +*/ + +TPM_RESULT TPM_OrdinalAuditStatus_Init(TPM_PERMANENT_DATA *tpm_permanent_data); +TPM_RESULT TPM_OrdinalAuditStatus_Store(TPM_SIZED_BUFFER *ordinalList, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_COMMAND_CODE startOrdinal); +TPM_RESULT TPM_OrdinalAuditStatus_GetAuditStatus(TPM_BOOL *auditStatus, + TPM_COMMAND_CODE ordinal, + TPM_PERMANENT_DATA *tpm_permanent_data); +TPM_RESULT TPM_OrdinalAuditStatus_SetAuditStatus(TPM_BOOL *altered, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL auditStatus, + TPM_COMMAND_CODE ordinal); + +/* + Common Processing Functions +*/ + +TPM_RESULT TPM_AuditDigest_ExtendIn(tpm_state_t *tpm_state, + TPM_DIGEST inParamDigest); +TPM_RESULT TPM_AuditDigest_ExtendOut(tpm_state_t *tpm_state, + TPM_DIGEST outParamDigest); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_GetAuditDigest(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_GetAuditDigestSigned(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_SetOrdinalAuditStatus(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + +#endif diff --git a/src/tpm_auth.c b/src/tpm_auth.c new file mode 100644 index 00000000..1a06a1ca --- /dev/null +++ b/src/tpm_auth.c @@ -0,0 +1,2297 @@ +/********************************************************************************/ +/* */ +/* Authorization */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_auth.c 4438 2011-02-13 23:03:56Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_storage.h" +#include "tpm_time.h" +#include "tpm_transport.h" + +#include "tpm_auth.h" + +/* Dictionary attack mitigation: + + TPM_Authdata_CheckState() - called at command entry + if past limit, + check authFailTime vs. current time + if command allowed + disableResetLock = FALSE + + TPM_Authdata_Check() - called during the command to validate authorization data + TPM_Authdata_Fail() - called on failure + authFailCount++ + if past limit, + authFailTime = current time + + TPM_ResetLockValue + TPM_Authdata_CheckState() + disableResetLock = FALSE if no lockout + if disableResetLock, return error + if authorization failure + disableResetLock = TRUE + authFailCount = 0 +*/ + +/* TPM_Authdata_Init() zeros the tpm_authdata + +*/ + +void TPM_Authdata_Init(TPM_AUTHDATA tpm_authdata) +{ + printf(" TPM_Authdata_Init:\n"); + memset(tpm_authdata, 0, TPM_AUTHDATA_SIZE); + return; +} + +/* TPM_Authdata_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_Authdata_Load(TPM_AUTHDATA tpm_authdata, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Authdata_Load:\n"); + + /* check stream_size */ + if (rc == 0) { + if (*stream_size < TPM_AUTHDATA_SIZE) { + printf("TPM_Authdata_Load: Error, stream_size %u less than %u\n", + *stream_size, TPM_DIGEST_SIZE); + rc = TPM_BAD_PARAM_SIZE; + } + } + if (rc == 0) { + memcpy(tpm_authdata, *stream, TPM_AUTHDATA_SIZE); + *stream += TPM_AUTHDATA_SIZE; + *stream_size -= TPM_AUTHDATA_SIZE; + } + return rc; +} + +/* TPM_Authdata_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + After use, call TPM_Sbuffer_Delete() to free memory +*/ + +TPM_RESULT TPM_Authdata_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUTHDATA tpm_authdata) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Authdata_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_authdata, TPM_AUTHDATA_SIZE); + } + return rc; +} + +/* TPM_AuthParams_Get() is common code to load a set of "below the double line" request parameters + from the input stream. + */ + +TPM_RESULT TPM_AuthParams_Get(TPM_AUTHHANDLE *authHandle, /* The authorization handle used for + this command */ + TPM_BOOL *authHandleValid, + TPM_NONCE nonceOdd, /* Nonce generated by system associated with + authHandle */ + TPM_BOOL *continueAuthSession, /* The continue use flag for the + authorization handle */ + TPM_AUTHDATA authData, /* Authorization digest for input params. */ + unsigned char **command, /* parameter stream */ + uint32_t *paramSize) /* bytes left in command */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuthParams_Get:\n"); + /* get authHandle parameter */ + if (rc == 0) { + rc = TPM_Load32(authHandle, command, paramSize); + } + /* get nonceOdd parameter */ + if (rc == 0) { + rc = TPM_Nonce_Load(nonceOdd, command, paramSize); + } + /* get continueAuthSession parameter */ + if (rc == 0) { + rc = TPM_LoadBool(continueAuthSession, command, paramSize); + } + /* get authData parameter */ + if (rc == 0) { + rc = TPM_Authdata_Load(authData, command, paramSize); + } + if (rc == 0) { + *authHandleValid = TRUE; /* so handle can be terminated */ + } + return rc; +} + + +/* TPM_SetAuthParams is common code to set a set of "below the double line" response parameters. + */ + +TPM_RESULT TPM_AuthParams_Set(TPM_STORE_BUFFER *response, + TPM_SECRET hmacKey, /* HMAC key */ + TPM_AUTH_SESSION_DATA *auth_session_data, /* session data for + authHandle */ + TPM_DIGEST outParamDigest, + TPM_NONCE nonceOdd, /* Nonce generated by system + associated with authHandle */ + TPM_BOOL continueAuthSession) /* session continue use flag */ +{ + TPM_RESULT rc = 0; + TPM_AUTHDATA resAuth; /* The authorization digest for the returned parameters */ + + printf(" TPM_AuthParams_Set:\n"); + /* generate new nonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Generate(auth_session_data->nonceEven); + } + /* append nonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Store(response, auth_session_data->nonceEven); + } + /* append continueAuthSession */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(response, &continueAuthSession, sizeof(TPM_BOOL)); + } + /* Calculate resAuth using the hmac key */ + if (rc == 0) { + rc = TPM_Authdata_Generate(resAuth, /* result */ + hmacKey, /* HMAC key */ + outParamDigest, /* params */ + auth_session_data->nonceEven, + nonceOdd, + continueAuthSession); + } + /* append resAuth */ + if (rc == 0) { + rc = TPM_Authdata_Store(response, resAuth); + } + return rc; +} + +TPM_RESULT TPM_Authdata_Generate(TPM_AUTHDATA resAuth, /* result */ + TPM_SECRET usageAuth, /* HMAC key */ + TPM_DIGEST outParamDigest, /* digest of outputs above double + line */ + TPM_NONCE nonceEven, + TPM_NONCE nonceOdd, + TPM_BOOL continueSession) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Authdata_Generate:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_Authdata_Generate: outParamDigest", outParamDigest); + TPM_PrintFour(" TPM_Authdata_Generate: usageAuth (key)", usageAuth); + TPM_PrintFour(" TPM_Authdata_Generate: nonceEven", nonceEven); + TPM_PrintFour(" TPM_Authdata_Generate: nonceOdd", nonceOdd); + printf (" TPM_Authdata_Generate: continueSession %02x\n", continueSession); + rc = TPM_HMAC_Generate(resAuth, + usageAuth, /* key */ + TPM_DIGEST_SIZE, outParamDigest, /* response digest */ + TPM_NONCE_SIZE, nonceEven, /* 2H */ + TPM_NONCE_SIZE, nonceOdd, /* 3H */ + sizeof(TPM_BOOL), &continueSession, /* 4H */ + 0, NULL); + TPM_PrintFour(" TPM_Authdata_Generate: resAuth", resAuth); + } + return rc; +} + +/* TPM_Authdata_Check() checks the authorization of a command. + + Handles the protection against dictionary attacks. + + Returns TPM_AUTHFAIL if the TPM_AUTHDATA does not match. +*/ + +TPM_RESULT TPM_Authdata_Check(tpm_state_t *tpm_state, + TPM_SECRET hmacKey, /* HMAC key */ + TPM_DIGEST inParamDigest, /* digest of inputs above line */ + TPM_AUTH_SESSION_DATA *tpm_auth_session_data, /* auth session */ + TPM_NONCE nonceOdd, /* Nonce generated by system + associated with authHandle */ + TPM_BOOL continueSession, + TPM_AUTHDATA usageAuth) /* Authorization digest for input */ +{ + TPM_RESULT rc = 0; + TPM_BOOL valid; + + printf(" TPM_Authdata_Check:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_Authdata_Check: inParamDigest", inParamDigest); + TPM_PrintFour(" TPM_Authdata_Check: usageAuth (key)", hmacKey); + TPM_PrintFour(" TPM_Authdata_Check: nonceEven", tpm_auth_session_data->nonceEven); + TPM_PrintFour(" TPM_Authdata_Check: nonceOdd", nonceOdd); + printf (" TPM_Authdata_Check: continueSession %02x\n", continueSession); + /* HMAC the inParamDigest, authLastNonceEven, nonceOdd, continue */ + /* authLastNonceEven is retrieved from internal authorization session storage */ + rc = TPM_HMAC_Check(&valid, + usageAuth, /* expected, from command */ + hmacKey, /* key */ + sizeof(TPM_DIGEST), inParamDigest, /* command digest */ + sizeof(TPM_NONCE), tpm_auth_session_data->nonceEven, /* 2H */ + sizeof(TPM_NONCE), nonceOdd, /* 3H */ + sizeof(TPM_BOOL), &continueSession, /* 4H */ + 0, NULL); + } + if (rc == 0) { + if (!valid) { + printf("TPM_Authdata_Check: Error, authorization failed\n"); + /* record the authorization failure */ + rc = TPM_Authdata_Fail(tpm_state); + /* TPM_Authdata_Fail() fatal TPM_FAIL error takes precedence, else TPM_AUTHFAIL */ + if (rc == 0) { + rc = TPM_AUTHFAIL; + } + } + } + return rc; +} + +/* TPM_Auth2data_Check() is a wrapper around TPM_Authdata_Check() that returns TPM_AUTH2FAIL + in place of TPM_AUTHFAIL. +*/ + +TPM_RESULT TPM_Auth2data_Check(tpm_state_t *tpm_state, + TPM_SECRET hmacKey, /* HMAC key */ + TPM_DIGEST inParamDigest, /* digest of inputs above line */ + TPM_AUTH_SESSION_DATA *tpm_auth_session_data, /* auth session */ + TPM_NONCE nonceOdd, /* Nonce generated by system + associated with authHandle */ + TPM_BOOL continueSession, + TPM_AUTHDATA usageAuth) /* Authorization digest for input */ +{ + TPM_RESULT rc = 0; + + rc = TPM_Authdata_Check(tpm_state, + hmacKey, + inParamDigest, + tpm_auth_session_data, + nonceOdd, + continueSession, + usageAuth); + if (rc == TPM_AUTHFAIL) { + rc = TPM_AUTH2FAIL; + } + return rc; +} + +/* TPM_Authdata_Fail() processes an authorization failure event, to mitigate dictionary attacks. + + Returns TPM_FAIL on error, so that the caller can shut down the TPM +*/ + +TPM_RESULT TPM_Authdata_Fail(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + uint32_t tv_usec; /* dummy, discard usec */ + + if (rc == 0) { + /* Each failure increments the counter. No need to check for overflow. Unless + TPM_LOCKOUT_THRESHOLD is absurdly large, the left shift overflows first. */ + tpm_state->tpm_stclear_data.authFailCount++; + printf(" TPM_Authdata_Fail: New authFailCount %u\n", + tpm_state->tpm_stclear_data.authFailCount); + /* Test if past the failure threshold. Each time authorization fails, this test is made. + Once in dictionary attack mitigation, there will be no authdata check until the + mitigation period is exceeded. After that, if there is another failure, the fail count + increases and mitigation begins again. + + Note that a successful authorization does NOT reset authFailCount, as this would allow a + dictionary attack by an attacker that knew ANY good authorization value. The count is + only reset by the owner using TPM_ResetLockValue. + */ + if (tpm_state->tpm_stclear_data.authFailCount > TPM_LOCKOUT_THRESHOLD) { + /* the current authorization failure time is the start time */ + rc = TPM_GetTimeOfDay(&(tpm_state->tpm_stclear_data.authFailTime), &tv_usec); + printf(" TPM_Authdata_Fail: Past limit, authFailTime %u\n", + tpm_state->tpm_stclear_data.authFailTime); + } + } + return rc; +} + +/* TPM_Authdata_GetState() gets the boolean dictionary attack mitigation state. + + */ + +TPM_RESULT TPM_Authdata_GetState(TPM_DA_STATE *state, + uint32_t *timeLeft, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + uint32_t currentTime; /* in seconds */ + uint32_t tv_usec; /* dummy, discarded */ + uint32_t threshold_diff; /* in failure counts */ + uint32_t waitTime; /* in seconds, timeout based on threshold_diff */ + uint32_t timeDiff; /* in seconds, how far along is timeout */ + + printf(" TPM_Authdata_GetState:\n"); + *state = TPM_DA_STATE_INACTIVE; /* default value */ + + /* if there is an attack in progress */ + if (tpm_state->tpm_stclear_data.authFailCount > TPM_LOCKOUT_THRESHOLD) { + printf(" TPM_Authdata_GetState: In timeout, authFailCount %u threshold %u\n", + tpm_state->tpm_stclear_data.authFailCount, TPM_LOCKOUT_THRESHOLD); + /* get the current time */ + if (rc == 0) { + /* throw away usec. This means that the time difference could be 1 sec off. But the + lockout mechanism is somewhat arbitrary anyway */ + rc = TPM_GetTimeOfDay(¤tTime, &tv_usec); + } + /* calculate how much time to wait */ + if (rc == 0) { + printf(" TPM_Authdata_GetState: currentTime %u authFailTime %u\n", + currentTime, tpm_state->tpm_stclear_data.authFailTime); + /* how many failures over the threshold. The -1 makes threshold_diff 0 based, so the + first waitTime is 1 sec. */ + threshold_diff = tpm_state->tpm_stclear_data.authFailCount - TPM_LOCKOUT_THRESHOLD - 1; + /* Wait time depends on how far over threshold, wait 1 sec and double each time. Ignore + shift overflow, since the previous timeout 0x80000000 sec is 68 years. */ + waitTime = 0x01 << threshold_diff; + /* how far along is timeout. */ + if (currentTime >= tpm_state->tpm_stclear_data.authFailTime) { + timeDiff = currentTime - tpm_state->tpm_stclear_data.authFailTime; + } + /* handle unlikely currentTime wrap around */ + else { + timeDiff = ((0xffffffff - tpm_state->tpm_stclear_data.authFailTime) + + currentTime) + 1; + } + /* if not past the timeout, return an error */ + printf(" TPM_Authdata_GetState: waitTime %u timeDiff %u\n", + waitTime, timeDiff); + if (waitTime > timeDiff) { + printf("TPM_Authdata_GetState: Error, timeout not complete\n"); + *state = TPM_DA_STATE_ACTIVE; + *timeLeft = waitTime - timeDiff; + } + } + } + return rc; +} + +/* TPM_Authdata_CheckState() checks the dictionary attack mitigation state. + + This function is typically called at the beginning of each command. + + If an attack is in progress, and the lockout timeout has not expired, an error is returned. +*/ + +TPM_RESULT TPM_Authdata_CheckState(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_DA_STATE state; + uint32_t timeLeft; + + printf(" TPM_Authdata_CheckState:\n"); + /* Get the dictionary attack mitigation state */ + if (rc == 0) { + rc = TPM_Authdata_GetState(&state, &timeLeft, tpm_state); + } + /* If not during the timeout period, allow the TPM_ResetLockValue ordinal */ + if (rc == 0) { + if (state == TPM_DA_STATE_INACTIVE) { + tpm_state->tpm_stclear_data.disableResetLock = FALSE; + } + else { /* TPM_DA_STATE_ACTIVE */ + rc = TPM_DEFEND_LOCK_RUNNING; + } + } + return rc; +} + +/* + TPM_CHANGEAUTH_VALIDATE +*/ + +/* TPM_ChangeauthValidate_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_ChangeauthValidate_Init(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate) +{ + printf(" TPM_ChangeauthValidate_Init:\n"); + TPM_Secret_Init(tpm_changeauth_validate->newAuthSecret); + TPM_Nonce_Init(tpm_changeauth_validate->n1); + return; +} + +/* TPM_ChangeauthValidate_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_ChangeauthValidate_Init() + After use, call TPM_ChangeauthValidate_Delete() to free memory +*/ + +TPM_RESULT TPM_ChangeauthValidate_Load(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ChangeauthValidate_Load:\n"); + /* load newAuthSecret */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_changeauth_validate->newAuthSecret, stream, stream_size); + } + /* load n1 */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_changeauth_validate->n1, stream, stream_size); + } + return rc; +} + +/* TPM_ChangeauthValidate_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_ChangeauthValidate_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ChangeauthValidate_Store:\n"); + /* store newAuthSecret */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_changeauth_validate->newAuthSecret); + } + /* store n1 */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_changeauth_validate->n1); + } + return rc; +} + +/* TPM_ChangeauthValidate_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_ChangeauthValidate_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_ChangeauthValidate_Delete(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate) +{ + printf(" TPM_ChangeauthValidate_Delete:\n"); + if (tpm_changeauth_validate != NULL) { + TPM_ChangeauthValidate_Init(tpm_changeauth_validate); + } + return; +} + +/* + TPM_DA_INFO +*/ + +/* TPM_DaInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DaInfo_Init(TPM_DA_INFO *tpm_da_info) +{ + printf(" TPM_DaInfo_Init:\n"); +/* tpm_da_info->tag = TPM_TAG_DA_INFO; */ + tpm_da_info->state = TPM_DA_STATE_INACTIVE; + tpm_da_info->currentCount = 0; + tpm_da_info->thresholdCount = TPM_LOCKOUT_THRESHOLD; + /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */ + tpm_da_info->actionAtThreshold.tag = TPM_TAG_DA_ACTION_TYPE; + tpm_da_info->actionAtThreshold.actions = TPM_DA_ACTION_TIMEOUT; + tpm_da_info->actionDependValue = 0; + TPM_SizedBuffer_Init(&tpm_da_info->vendorData); + return; +} + +/* TPM_DaInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DaInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DA_INFO *tpm_da_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DaInfo_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_INFO); + } + /* store state */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_da_info->state), sizeof(TPM_DA_STATE)); + } + /* store currentCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_da_info->currentCount); + } + /* store thresholdCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_da_info->thresholdCount); + } + /* store actionAtThreshold */ + /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */ + /* store TPM_DA_ACTION_TYPE tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_ACTION_TYPE); + } + /* store TPM_DA_ACTION_TYPE actions */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_da_info->actionAtThreshold.actions); + } + /* store actionDependValue */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_da_info->actionDependValue); + } + /* store vendorData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_da_info->vendorData)); + } + return rc; +} + +/* TPM_DaInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DaInfo_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DaInfo_Delete(TPM_DA_INFO *tpm_da_info) +{ + printf(" TPM_DaInfo_Delete:\n"); + if (tpm_da_info != NULL) { + TPM_SizedBuffer_Delete(&(tpm_da_info->vendorData)); + TPM_DaInfo_Init(tpm_da_info); + } + return; +} + +/* TPM_DaInfoLimited_Set() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DaInfo_Set(TPM_DA_INFO *tpm_da_info, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DaInfo_Set:\n"); + /* state: Dynamic. The actual state of the dictionary attack mitigation logic. */ + /* actionDependValue: Dynamic. Action being taken when the dictionary attack mitigation logic + is active. E.g., when actionAtThreshold is TPM_DA_ACTION_TIMEOUT, this is the lockout time + remaining in seconds. */ + if (rc == 0) { + rc = TPM_Authdata_GetState(&(tpm_da_info->state), + &(tpm_da_info->actionDependValue), + tpm_state); + } + /* Dynamic. The actual count of the authorization failure counter for the selected entity + type */ + if (rc == 0) { + if (tpm_state->tpm_stclear_data.authFailCount <= 0xffff) { + tpm_da_info->currentCount = tpm_state->tpm_stclear_data.authFailCount; + } + /* with the doubling, this should never overflow. So overflow indicates a serious error */ + else { + printf("TPM_DaInfo_Set: Error (fatal), authFailCount overflow %08x\n", + tpm_state->tpm_stclear_data.authFailCount); + rc = TPM_FAIL; + } + } + return rc; +} + +/* + TPM_DA_INFO_LIMITED +*/ + +/* TPM_DaInfoLimited_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DaInfoLimited_Init(TPM_DA_INFO_LIMITED *tpm_da_info_limited) +{ + printf(" TPM_DaInfoLimited_Init:\n"); +/* tpm_da_info_limited->tag = TPM_TAG_DA_INFO_LIMITED; */ + tpm_da_info_limited->state = TPM_DA_STATE_INACTIVE; + /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */ + tpm_da_info_limited->actionAtThreshold.tag = TPM_TAG_DA_ACTION_TYPE; + tpm_da_info_limited->actionAtThreshold.actions = TPM_DA_ACTION_TIMEOUT; + TPM_SizedBuffer_Init(&tpm_da_info_limited->vendorData); + return; +} + +/* TPM_DaInfoLimited_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DaInfoLimited_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DA_INFO_LIMITED *tpm_da_info_limited) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DaInfoLimited_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_INFO_LIMITED); + } + /* store state */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_da_info_limited->state), sizeof (TPM_DA_STATE)); + } + /* store actionAtThreshold */ + /* TPM_DA_ACTION_TYPE is a trivial structure, in-line here */ + /* store TPM_DA_ACTION_TYPE tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DA_ACTION_TYPE); + } + /* store TPM_DA_ACTION_TYPE actions */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_da_info_limited->actionAtThreshold.actions); + } + /* store vendorData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_da_info_limited->vendorData)); + } + return rc; +} + +/* TPM_DaInfoLimited_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DaInfoLimited_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DaInfoLimited_Delete(TPM_DA_INFO_LIMITED *tpm_da_info_limited) +{ + printf(" TPM_DaInfoLimited_Delete:\n"); + if (tpm_da_info_limited != NULL) { + TPM_SizedBuffer_Delete(&(tpm_da_info_limited->vendorData)); + TPM_DaInfoLimited_Init(tpm_da_info_limited); + } + return; +} + +/* TPM_DaInfoLimited_Set() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DaInfoLimited_Set(TPM_DA_INFO_LIMITED *tpm_da_info_limited, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + uint32_t timeLeft; + + printf(" TPM_DaInfoLimited_Set:\n"); + /* Dynamic. The actual state of the dictionary attack mitigation logic. */ + if (rc == 0) { + rc = TPM_Authdata_GetState(&(tpm_da_info_limited->state), &timeLeft, tpm_state); + } + return rc; +} + +/* + Processing Functions +*/ + + +/* 17.1 TPM_ChangeAuth rev 107 + + The TPM_ChangeAuth command allows the owner of an entity to change the authorization data for the + entity. + + This command cannot invalidate the old entity. Therefore, the authorization change is only + effective if the application can guarantee that the old entity can be securely destroyed. If not, + two valid entities will exist, one with the old and one with the new authorization secret. + + If this command is delegated, the delegated party can expand its key use privileges. That party + can create a copy of the key with known authorization, and it can then use the key without any + ordinal restrictions. + + TPM_ChangeAuth requires the encryption of one parameter ("NewAuth"). For the sake of uniformity + with other commands that require the encryption of more than one parameter, the string used for + XOR encryption is generated by concatenating the evenNonce (created during the OSAP session) with + the session shared secret and then hashing the result. + + The parameter list to this command must always include two authorization sessions, regardless of + the state of authDataUsage for the respective keys. +*/ + +TPM_RESULT TPM_Process_ChangeAuth(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* Handle of the parent key to the entity. */ + TPM_PROTOCOL_ID protocolID = 0; /* The protocol in use. */ + TPM_ENCAUTH newAuth; /* The encrypted new authorization data for the entity */ + TPM_ENTITY_TYPE entityType = 0; /* The type of entity to be modified */ + TPM_SIZED_BUFFER encData; /* The encrypted entity that is to be modified. */ + + TPM_AUTHHANDLE parentAuthHandle; /* The authorization handle used for the parent + key. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with + parentAuthHandle */ + TPM_BOOL continueAuthSession; /* Ignored, parentAuthHandle is always terminated. */ + TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and + parentHandle. HMAC key: parentKey.usageAuth. */ + + TPM_AUTHHANDLE entityAuthHandle; /* The authorization handle used for the encrypted + entity. The session type MUST be OIAP */ + TPM_NONCE entitynonceOdd; /* Nonce generated by system associated with + entityAuthHandle */ + TPM_BOOL continueEntitySession; /* Ignored, entityAuthHandle is always terminated. */ + TPM_AUTHDATA entityAuth; /* The authorization digest for the inputs and encrypted + entity. HMAC key: entity.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL parentAuthHandleValid = FALSE; + TPM_BOOL entityAuthHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *parent_auth_session_data = NULL; /* session data for + parentAuthHandle */ + TPM_AUTH_SESSION_DATA *entity_auth_session_data = NULL; /* session data for + entityAuthHandle */ + TPM_KEY *parentKey = NULL; + TPM_SECRET *parentHmacKey; + TPM_SECRET *entityHmacKey; + TPM_SECRET saveKey; /* copy of entity HMAC key for response */ + TPM_BOOL parentPCRStatus; + TPM_AUTHDATA decryptAuth; + unsigned char *b1DecryptData; + uint32_t b1DecryptDataLength = 0; /* actual valid data */ + unsigned char *stream; /* for deserializing decrypted encData */ + uint32_t stream_size; + TPM_STORE_ASYMKEY keyEntity; /* entity structure when it's a TPM_ET_KEY */ + TPM_SEALED_DATA sealEntity; /* entity structure when it's a TPM_ET_DATA */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outData; /* The modified, encrypted entity. */ + + printf("TPM_Process_ChangeAuth: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&encData); /* freed @1 */ + TPM_SizedBuffer_Init(&outData); /* freed @2 */ + b1DecryptData = NULL; /* freed @3 */ + TPM_StoreAsymkey_Init(&keyEntity); /* freed @4 */ + TPM_SealedData_Init(&sealEntity); /* freed @5 */ + /* + get inputs + */ + /* get parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get protocolID parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuth: parentHandle %08x\n", parentHandle); + returnCode = TPM_Load16(&protocolID, &command, ¶mSize); + } + /* get newAuth parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuth: protocolID %04hx\n", protocolID); + returnCode = TPM_Authdata_Load(newAuth, &command, ¶mSize); + } + /* get entityType parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&entityType, &command, ¶mSize); + } + /* get encData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&encData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuth: encDataSize %u\n", encData.size); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag2(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&parentAuthHandle, + &parentAuthHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuth: parentAuthHandle %08x\n", parentAuthHandle); + returnCode = TPM_AuthParams_Get(&entityAuthHandle, + &entityAuthHandleValid, + entitynonceOdd, + &continueEntitySession, + entityAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuth: entityAuthHandle %08x\n", entityAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ChangeAuth: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + parentAuthHandleValid = FALSE; + entityAuthHandleValid = FALSE; + } + /* + Processing + */ + /* Description + 1. The parentAuthHandle session type MUST be TPM_PID_OSAP. + 2. In this capability, the SRK cannot be accessed as entityType TPM_ET_KEY, since the SRK is + not wrapped by a parent key. + */ + /* 1. Verify that entityType is one of TPM_ET_DATA, TPM_ET_KEY and return the error + TPM_WRONG_ENTITYTYPE if not. */ + if (returnCode == TPM_SUCCESS) { + if ((entityType != TPM_ET_DATA) && + (entityType != TPM_ET_KEY)) { + printf("TPM_Process_ChangeAuth: Error, bad entityType %04x\n", entityType); + returnCode = TPM_WRONG_ENTITYTYPE; + } + } + /* 2. Verify that parentAuthHandle session type is TPM_PID_OSAP return TPM_BAD_MODE on error */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to authenticate */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the OSAP session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&parent_auth_session_data, + &parentHmacKey, + tpm_state, + parentAuthHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + NULL, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 3. Verify that entityAuthHandle session type is TPM_PID_OIAP return TPM_BAD_MODE on error */ + /* keyEntity and sealEntity are not valid yet, so pass in NULL and ignore the returned + entityHmacKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&entity_auth_session_data, + &entityHmacKey, + tpm_state, + entityAuthHandle, + TPM_PID_OIAP, + 0, /* OSAP entity type */ + ordinal, + NULL, + NULL, + NULL); + } + /* 4.If protocolID is not TPM_PID_ADCP, the TPM MUST return TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if (protocolID != TPM_PID_ADCP) { + printf("TPM_Process_ChangeAuth: Error, bad protocolID\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 5. The encData field MUST be the encData field from either the TPM_STORED_DATA or TPM_KEY + structures. */ + /* NOTE Seems the same as Action 1. */ + /* 6. Create decryptAuth by decrypting newAuth according to the ADIP indicated by + parentHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(decryptAuth, + NULL, + newAuth, + parent_auth_session_data, + NULL, + NULL, + FALSE); /* odd and even */ + } + /* 7. The TPM MUST validate the command using the authorization data in the parentAuth parameter + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *parentHmacKey, /* HMAC key */ + inParamDigest, + parent_auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* 8. Validate that parentHandle -> keyUsage is TPM_KEY_STORAGE, if not return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_ChangeAuth: Error, keyUsage %04hx is invalid\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 9. After parameter validation the TPM creates b1 by decrypting encData using the key pointed + to by parentHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPrivateDecryptMalloc(&b1DecryptData, /* decrypted data */ + &b1DecryptDataLength, /* actual size of + decrypted data */ + encData.buffer,/* encrypted data */ + encData.size, /* encrypted data size */ + parentKey); + } + if ((returnCode == TPM_SUCCESS) && (entityType == TPM_ET_KEY)) { + printf("TPM_Process_ChangeAuth: entityType is TPM_ET_KEY\n"); + /* 10. The TPM MUST validate that b1 is a valid TPM structure, either a TPM_STORE_ASYMKEY or + a TPM_SEALED_DATA */ + if (returnCode == TPM_SUCCESS) { + stream = b1DecryptData; + stream_size = b1DecryptDataLength; + returnCode = TPM_StoreAsymkey_Load(&keyEntity, FALSE, + &stream, &stream_size, + NULL, /* TPM_KEY_PARMS */ + NULL); /* TPM_SIZED_BUFFER pubKey */ + } + /* a. Check the length and payload, return TPM_INVALID_STRUCTURE on any mismatch. */ + /* NOTE: Done by TPM_StoreAsymkey_Load() */ + if (returnCode == TPM_SUCCESS) { + /* save a copy of the HMAC key for the response before changing */ + TPM_Secret_Copy(saveKey, keyEntity.usageAuth); + /* a.The TPM must validate the command using the authorization data entityAuth + parameter. The HMAC key is TPM_STORE_ASYMKEY -> usageAuth or TPM_SEALED_DATA -> + authData. */ + returnCode = TPM_Auth2data_Check(tpm_state, + keyEntity.usageAuth, /* HMAC key */ + inParamDigest, + entity_auth_session_data, /* authorization session */ + entitynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueEntitySession, + entityAuth); /* Authorization digest for input */ + } + /* 11. The TPM replaces the authorization data for b1 with decryptAuth created above. */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_ChangeAuth: usageAuth was", keyEntity.usageAuth); + TPM_PrintFour("TPM_Process_ChangeAuth: usageAuth now", decryptAuth); + TPM_Secret_Copy(keyEntity.usageAuth, decryptAuth); + } + /* 12. The TPM encrypts b1 using the appropriate mechanism for the type using the + parentKeyHandle to provide the key information. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StoreAsymkey_GenerateEncData(&outData, &keyEntity, parentKey); + } + } + else if ((returnCode == TPM_SUCCESS) && (entityType == TPM_ET_DATA)) { + printf("TPM_Process_ChangeAuth: entityType is TPM_ET_DATA\n"); + /* 10. The TPM MUST validate that b1 is a valid TPM structure, either a TPM_STORE_ASYMKEY or + a TPM_SEALED_DATA */ + if (returnCode == TPM_SUCCESS) { + stream = b1DecryptData; + stream_size = b1DecryptDataLength; + returnCode = TPM_SealedData_Load(&sealEntity, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuth: Checking tpmProof\n"); + returnCode = TPM_Secret_Compare(sealEntity.tpmProof, + tpm_state->tpm_permanent_data.tpmProof); + } + /* a. Check the length and payload, return TPM_INVALID_STRUCTURE on any mismatch. */ + /* NOTE: Done by TPM_SealedData_Load() */ + if (returnCode == TPM_SUCCESS) { + /* save a copy of the HMAC key for the response before changing */ + TPM_Secret_Copy(saveKey, sealEntity.authData); + /* a.The TPM must validate the command using the authorization data entityAuth + parameter. The HMAC key is TPM_STORE_ASYMKEY -> usageAuth or TPM_SEALED_DATA -> + authData. */ + returnCode = TPM_Auth2data_Check(tpm_state, + sealEntity.authData, /* HMAC key */ + inParamDigest, + entity_auth_session_data, /* authorization session */ + entitynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueEntitySession, + entityAuth); /* Authorization digest for input */ + } + /* 11. The TPM replaces the authorization data for b1 with decryptAuth created above. */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_ChangeAuth: authData was", sealEntity.authData); + TPM_PrintFour("TPM_Process_ChangeAuth: authData now", decryptAuth); + TPM_Secret_Copy(sealEntity.authData, decryptAuth); + } + /* 12. The TPM encrypts b1 using the appropriate mechanism for the type using the + parentKeyHandle to provide the key information. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SealedData_GenerateEncData(&outData, &sealEntity, parentKey); + } + } + /* 13. The TPM MUST enforce the destruction of both the parentAuthHandle and entityAuthHandle + sessions. */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + continueEntitySession = FALSE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ChangeAuth: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 14. The new blob is returned in outData when appropriate. */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *parentHmacKey, /* HMAC key */ + parent_auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + saveKey, /* the original and not the new auth value */ + entity_auth_session_data, + outParamDigest, + entitynonceOdd, + continueEntitySession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* 15. The TPM MUST enforce the destruction of both the parentAuthHandle and entityAuthHandle + sessions. */ + if (parentAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, parentAuthHandle); + } + if (entityAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, entityAuthHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&encData); /* @1 */ + TPM_SizedBuffer_Delete(&outData); /* @2 */ + free(b1DecryptData); /* @3 */ + TPM_StoreAsymkey_Delete(&keyEntity); /* @4 */ + TPM_SealedData_Delete(&sealEntity); /* @5 */ + return rcf; +} + +/* 17.2 TPM_ChangeAuthOwner rev 98 + + 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's targeted for an environment (e.g. a server) with long lasting sessions should not + invalidate all sessions. +*/ + +TPM_RESULT TPM_Process_ChangeAuthOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_PROTOCOL_ID protocolID; /* The protocol in use. */ + TPM_ENCAUTH newAuth; /* The encrypted new authorization data for the entity */ + TPM_ENTITY_TYPE entityType = 0; /* The type of entity to be modified */ + TPM_AUTHHANDLE ownerAuthHandle; /* The authorization handle used for the TPM + Owner. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with ownerAuthHandle + */ + TPM_BOOL continueAuthSession = TRUE; /* Continue use flag the TPM ignores this value */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and ownerHandle. HMAC + key: tpmOwnerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL ownerAuthHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *owner_auth_session_data = NULL; /* session data for ownerAuthHandle + */ + TPM_SECRET *hmacKey; + TPM_SECRET saveKey; /* copy of HMAC key, since sessions invalidated */ + TPM_AUTHDATA decryptAuth; + TPM_AUTHDATA *entityAuth; /* pointer to either owner or SRK auth */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ChangeAuthOwner: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get protocolID parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&protocolID, &command, ¶mSize); + } + /* get newAuth parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuthOwner: protocolID %04hx\n", protocolID); + returnCode = TPM_Authdata_Load(newAuth, &command, ¶mSize); + } + /* get entityType parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&entityType, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&ownerAuthHandle, + &ownerAuthHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ChangeAuthOwner: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + ownerAuthHandleValid = FALSE; + } + /* + Processing + */ + /* 1. The TPM MUST validate the command using the AuthData in the ownerAuth parameter */ + /* 2. The ownerAuthHandle session type MUST be TPM_PID_OSAP */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&owner_auth_session_data, + &hmacKey, + tpm_state, + ownerAuthHandle, + TPM_PID_OSAP, + TPM_ET_OWNER, + ordinal, + NULL, + NULL, + tpm_state->tpm_permanent_data.ownerAuth); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + owner_auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 3. If protocolID is not TPM_PID_ADCP, the TPM MUST return TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if (protocolID != TPM_PID_ADCP) { + printf("TPM_Process_ChangeAuthOwner: Error, bad protocolID\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 4. Verify that entityType is either TPM_ET_OWNER or TPM_ET_SRK, and return the error + TPM_WRONG_ENTITYTYPE if not. */ + if (returnCode == TPM_SUCCESS) { + if (entityType == TPM_ET_OWNER) { + printf("TPM_Process_ChangeAuthOwner: entityType TPM_ET_OWNER\n"); + entityAuth = &(tpm_state->tpm_permanent_data.ownerAuth); + } + else if (entityType == TPM_ET_SRK) { + printf("TPM_Process_ChangeAuthOwner: entityType TPM_ET_SRK\n"); + entityAuth = &(tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->usageAuth); + } + else { + entityAuth = NULL; /* just to quiet the compiler */ + printf("TPM_Process_ChangeAuthOwner: Error, wrong entityType %04x\n", entityType); + returnCode = TPM_WRONG_ENTITYTYPE; + } + } + /* 5. Create decryptAuth by decrypting newAuth according to the ADIP indicated by + ownerAuthHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(decryptAuth, + NULL, + newAuth, + owner_auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_ChangeAuthOwner: From entityAuth", *entityAuth); + TPM_PrintFour("TPM_Process_ChangeAuthOwner: To decryptAuth", decryptAuth); + /* 6. The TPM MUST enforce the destruction of the ownerAuthHandle session upon completion of + this command (successful or unsuccessful). This includes setting continueAuthSession to + FALSE */ + continueAuthSession = FALSE; + /* 7. Set the authorization data for the indicated entity to decryptAuth */ + TPM_Secret_Copy(*entityAuth, decryptAuth); + /* save a copy of the HMAC key for the response before invalidating */ + TPM_Secret_Copy(saveKey, *hmacKey); + /* 8. The TPM MUST invalidate all owner authorized OSAP and DSAP sessions, active or + saved. */ + TPM_AuthSessions_TerminateEntity(&continueAuthSession, + ownerAuthHandle, + tpm_state->tpm_stclear_data.authSessions, + TPM_ET_OWNER, /* TPM_ENTITY_TYPE */ + NULL); /* ignore entityDigest */ + /* 9. The TPM MAY invalidate all sessions, active or saved */ + /* Store the permanent data back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ChangeAuthOwner: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + saveKey, /* HMAC key */ + owner_auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + ownerAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, ownerAuthHandle); + } + /* + cleanup + */ + return rcf; +} + + +/* 27.4.1 TPM_ChangeAuthAsymStart rev 87 + + The TPM_ChangeAuthAsymStart starts the process of changing AuthData for an entity. It sets up an + OIAP session that must be retained for use by its twin TPM_ChangeAuthAsymFinish command. + + TPM_ChangeAuthAsymStart creates a temporary asymmetric public key "tempkey" to provide + confidentiality for new AuthData to be sent to the TPM. TPM_ChangeAuthAsymStart certifies that + tempkey was generated by a genuine TPM, by generating a certifyInfo structure that is signed by a + TPM identity. The owner of that TPM identity must cooperate to produce this command, because + TPM_ChangeAuthAsymStart requires authorization to use that identity. + + It is envisaged that tempkey and certifyInfo are given to the owner of the entity whose + authorization is to be changed. That owner uses certifyInfo and a TPM_IDENTITY_CREDENTIAL to + verify that tempkey was generated by a genuine TPM. This is done by verifying the + TPM_IDENTITY_CREDENTIAL using the public key of a CA, verifying the signature on the certifyInfo + structure with the public key of the identity in TPM_IDENTITY_CREDENTIAL, and verifying tempkey + by comparing its digest with the value inside certifyInfo. The owner uses tempkey to encrypt the + desired new AuthData and inserts that encrypted data in a TPM_ChangeAuthAsymFinish command, in + the knowledge that only a TPM with a specific identity can interpret the new AuthData. +*/ + +TPM_RESULT TPM_Process_ChangeAuthAsymStart(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE idHandle; /* The keyHandle identifier of a loaded identity ID key */ + TPM_NONCE antiReplay; /* The nonce to be inserted into the certifyInfo structure + */ + TPM_KEY_PARMS tempKeyParms; /* Structure contains all parameters of ephemeral key. */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for idHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA idAuth; /* Authorization. HMAC key: idKey.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *idKey = NULL; + TPM_SECRET *idKeyUsageAuth; + TPM_BOOL idPCRStatus; + TPM_RSA_KEY_PARMS *temp_rsa_key_parms; /* tempKey is RSA */ + TPM_BOOL key_added = FALSE; /* added to key handle entries */ + TPM_DIGEST h1Digest; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CERTIFY_INFO certifyInfo; /* The certifyInfo structure that is to be signed. */ + TPM_SIZED_BUFFER sig; /* The signature of the certifyInfo parameter. */ + TPM_KEY_HANDLE ephHandle; /* The keyHandle identifier to be used by + ChangeAuthAsymFinish for the ephemeral key */ + TPM_KEY *tempKey; /* Structure containing all parameters and public part of + ephemeral key. TPM_KEY.encSize is set to 0. NOTE + Actually tempKey and k1 are the same. The encData is + present but not returned in the response. */ + + printf("TPM_Process_ChangeAuthAsymStart: Ordinal Entry\n"); + TPM_KeyParms_Init(&tempKeyParms); /* freed @1 */ + TPM_CertifyInfo_Init(&certifyInfo); /* freed @2 */ + TPM_SizedBuffer_Init(&sig); /* freed @3 */ + tempKey = NULL; /* freed @4 */ + /* + get inputs + */ + /* get idHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&idHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuthAsymStart: idHandle %08x\n", idHandle); + /* get antiReplay parameter */ + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get tempKey (actually tempKeyParms) parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_Load(&tempKeyParms, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + idAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ChangeAuthAsymStart: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 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.*/ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&idKey, &idPCRStatus, tpm_state, idHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if (returnCode == TPM_SUCCESS) { + if (idKey->keyUsage != TPM_KEY_IDENTITY) { + printf("TPM_Process_ChangeAuthAsymStart: Error, keyUsage %04hx is invalid\n", + idKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + if (idKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_ChangeAuthAsymStart: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get idHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&idKeyUsageAuth, idKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + idKey, + idKeyUsageAuth, /* OIAP */ + idKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + idAuth); /* Authorization digest for input */ + } + /* 2. The TPM SHALL validate the algorithm parameters for the key to create from the tempKey + parameter. */ + if (returnCode == TPM_SUCCESS) { + /* get the TPM_RSA_KEY_PARMS structure from the TPM_KEY_PARMS structure */ + /* 3. Recommended key type is RSA */ + returnCode = TPM_KeyParms_GetRSAKeyParms(&temp_rsa_key_parms, &tempKeyParms); + } + /* 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 (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_CheckProperties(&tempKeyParms, + TPM_KEY_AUTHCHANGE, + 0, /* required key length in bits */ + tpm_state->tpm_permanent_flags.FIPS); + } + /* 7. The TPM SHALL create a new key (k1) in accordance with the algorithm parameter. The newly + created key is pointed to by ephHandle. */ + /* NOTE tempKey is used as k1 */ + /* Allocate space for k1. The key cannot be a local variable, since it persists in key storage + after the command completes. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc((unsigned char **)&tempKey, sizeof(TPM_KEY)); + } + /* + Field Descriptions for certifyInfo parameter + Type Name Description + TPM_VERSION Version TPM version structure; Part 2 TPM_VERSION + keyFlags Redirection This SHALL be set to FALSE + Migratable This SHALL be set to FALSE + Volatile This SHALL be set to TRUE + TPM_AUTH_DATA_USAGE authDataUsage This SHALL be set to TPM_AUTH_NEVER + TPM_KEY_USAGE KeyUsage This SHALL be set to TPM_KEY_AUTHCHANGE + uint32_t PCRInfoSize This SHALL be set to 0 + TPM_DIGEST pubDigest This SHALL be the hash of the public key + being certified. + TPM_NONCE Data This SHALL be set to antiReplay + TPM_KEY_PARMS info This specifies the type of key and its parameters. + TPM_BOOL parentPCRStatus This SHALL be set to FALSE. + */ + /* generate a TPM_KEY using TPM_KEY_PARMS. encData is stored as clear text since there is no + parent key for the ephemeral key */ + if (returnCode == TPM_SUCCESS) { + /* This must immediately follow the successful malloc, so the _Delete / free work */ + TPM_Key_Init(tempKey); + printf(" TPM_Process_ChangeAuthAsymStart: Creating ephemeral key\n"); + returnCode = TPM_Key_GenerateRSA(tempKey, + tpm_state, + NULL, /* encData cleartext */ + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + 1, /* TPM_KEY */ + TPM_KEY_AUTHCHANGE, /* keyUsage */ + TPM_ISVOLATILE, /* keyFlags */ + TPM_AUTH_NEVER, /* authDataUsage */ + &tempKeyParms, /* TPM_KEY_PARMS */ + NULL, /* TPM_PCR_INFO */ + NULL); /* TPM_PCR_INFO_LONG */ + } + if (returnCode == TPM_SUCCESS) { + ephHandle = 0; /* no preferred value */ + returnCode = TPM_KeyHandleEntries_AddKeyEntry(&ephHandle, /* output */ + tpm_state->tpm_key_handle_entries, /* input */ + tempKey, /* input */ + 0, /* parentPCRStatus not used */ + 0); /* keyControl not used */ + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuthAsymStart: Ephemeral key handle %08x\n", ephHandle); + /* remember that the handle has been added to handle list, so it can be deleted on error */ + key_added = TRUE; + } + /* 8. The TPM SHALL fill in all fields in tempKey using k1 for the information. The TPM_KEY -> + encSize MUST be 0. */ + /* NOTE Not required. k1 and tempKey are the same */ + /* 9. The TPM SHALL fill in certifyInfo using k1 for the information. The certifyInfo -> data + field is supplied by the antiReplay. */ + if (returnCode == TPM_SUCCESS) { + printf(" TPM_Process_ChangeAuthAsymStart: Creating certifyInfo\n"); + TPM_Nonce_Copy(certifyInfo.data, antiReplay); + returnCode = TPM_CertifyInfo_Set(&certifyInfo, tempKey); + } + /* 10. The TPM then signs the certifyInfo parameter using the key pointed to by idHandle. The + resulting signed blob is returned in sig parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(h1Digest, &certifyInfo, + (TPM_STORE_FUNCTION_T)TPM_CertifyInfo_Store); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuthAsymStart: Signing certifyInfo digest\n"); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + h1Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + idKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ChangeAuthAsymStart: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return certifyInfo */ + returnCode = TPM_CertifyInfo_Store(response, &certifyInfo); + } + /* return sig */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + } + /* return ephHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, ephHandle); + } + /* return tempKey. TPM_Key_StorePubData() does not store any encData. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_StorePubData(response, FALSE, tempKey); + } + if (returnCode == TPM_SUCCESS) { + /* TPM_KEY.encSize is set to 0 */ + returnCode = TPM_Sbuffer_Append32(response, 0); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_KeyParms_Delete(&tempKeyParms); /* @1 */ + TPM_CertifyInfo_Delete(&certifyInfo); /* @2 */ + TPM_SizedBuffer_Delete(&sig); /* @3 */ + /* if there was a failure, delete inKey */ + if ((rcf != 0) || + (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(tempKey); /* @4 */ + free(tempKey); /* @4 */ + if (key_added) { + /* if there was a failure and tempKey was stored in the handle list, free the handle. + Ignore errors, since only one error code can be returned. */ + TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, ephHandle); + } + } + return rcf; +} + +/* 27.4.2 TPM_ChangeAuthAsymFinish rev 110 + + The TPM_ChangeAuthAsymFinish command allows the owner of an entity to change the AuthData for the + entity. + + The command requires the cooperation of the owner of the parent of the entity, since AuthData + must be provided to use that parent entity. The command requires knowledge of the existing + AuthData information and passes the new AuthData information. The newAuthLink parameter proves + knowledge of existing AuthData information and new AuthData information. The new AuthData + information "encNewAuth" is encrypted using the "tempKey" variable obtained via + TPM_ChangeAuthAsymStart. + + A parent therefore retains control over a change in the AuthData of a child, but is prevented + from knowing the new AuthData for that child. + + The changeProof parameter provides a proof that the new AuthData value was properly inserted into + the entity. The inclusion of a nonce from the TPM provides an entropy source in the case where + the AuthData value may be in itself be a low entropy value (hash of a password etc). +*/ + +TPM_RESULT TPM_Process_ChangeAuthAsymFinish(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* The keyHandle of the parent key for the input + data */ + TPM_KEY_HANDLE ephHandle; /* The keyHandle identifier for the ephemeral key */ + TPM_ENTITY_TYPE entityType = 0; /* The type of entity to be modified */ + TPM_HMAC newAuthLink; /* HMAC calculation that links the old and new + AuthData values together */ + TPM_SIZED_BUFFER encNewAuth; /* New AuthData encrypted with ephemeral key. */ + TPM_SIZED_BUFFER encData; /* The encrypted entity that is to be modified. */ + TPM_AUTHHANDLE authHandle; /* Authorization for parent key. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with + authHandle */ + TPM_BOOL continueAuthSession; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA privAuth; /* The authorization session digest for inputs and + parentHandle. HMAC key: parentKey.usageAuth. */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *parentKey = NULL; + TPM_SECRET *parentKeyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_KEY *ephKey = NULL; + TPM_BOOL ephPCRStatus; + unsigned char *stream; /* for deserializing decrypted encData */ + uint32_t stream_size; + TPM_STORE_ASYMKEY keyEntity; /* entity structure when it's a TPM_ET_KEY */ + unsigned char *e1DecryptData; + uint32_t e1DecryptDataLength = 0; /* actual valid data */ + unsigned char *a1Auth; + uint32_t a1AuthLength = 0; /* actual valid data */ + TPM_CHANGEAUTH_VALIDATE changeauthValidate; + TPM_BOOL valid; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outData; /* The modified, encrypted entity. */ + TPM_NONCE saltNonce; /* A nonce value from the TPM RNG to add entropy to the + changeProof value */ + TPM_DIGEST changeProof; /* Proof that AuthData has changed. */ + + printf("TPM_Process_ChangeAuthAsymFinish: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&encNewAuth); /* freed @1 */ + TPM_SizedBuffer_Init(&encData); /* freed @2 */ + TPM_SizedBuffer_Init(&outData); /* freed @3 */ + TPM_StoreAsymkey_Init(&keyEntity); /* freed @4 */ + e1DecryptData = NULL; /* freed @5 */ + a1Auth = NULL; /* freed @6 */ + TPM_ChangeauthValidate_Init(&changeauthValidate); /* freed @7 */ + /* + get inputs + */ + /* get parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* get ephHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuthAsymFinish: parentHandle %08x\n", parentHandle); + returnCode = TPM_Load32(&ephHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuthAsymFinish: ephHandle %08x\n", ephHandle); + /* get entityType parameter */ + returnCode = TPM_Load16(&entityType, &command, ¶mSize); + } + /* get newAuthLink parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(newAuthLink, &command, ¶mSize); + } + /* get encNewAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&encNewAuth, &command, ¶mSize); + } + /* get encData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&encData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuthAsymFinish: encDataSize %u\n", encData.size); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ChangeAuthAsymFinish: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. The TPM SHALL validate that the authHandle parameter authorizes use of the key in + parentHandle.*/ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_ChangeAuthAsymFinish: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get idHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + if (parentHandle != TPM_KH_SRK) { + returnCode = TPM_Key_GetUsageAuth(&parentKeyUsageAuth, parentKey); + } + /* If the parentHandle points to the SRK then the HMAC key MUST be built using the TPM Owner + authorization. */ + else { + parentKeyUsageAuth = &(tpm_state->tpm_permanent_data.ownerAuth); + } + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + if (parentHandle != TPM_KH_SRK) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentKeyUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* If the parentHandle points to the SRK then the HMAC key MUST be built using the TPM Owner + authorization. */ + else { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + parentKey, + parentKeyUsageAuth, /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /*OSAP*/ + } + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. The encData field MUST be the encData field from TPM_STORED_DATA or TPM_KEY. */ + if (returnCode == TPM_SUCCESS) { + /* FIXME currently only TPM_KEY supported */ + if (entityType != TPM_ET_KEY) { + printf("TPM_Process_ChangeAuthAsymFinish: Error, bad entityType %04x\n", entityType); + returnCode = TPM_WRONG_ENTITYTYPE; + } + } + /* Validate that parentHandle -> keyUsage is TPM_KEY_STORAGE, if not return the error code + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_ChangeAuthAsymFinish: Error, keyUsage %04hx is invalid\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. The TPM SHALL create e1 by decrypting the entity held in the encData parameter. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPrivateDecryptMalloc(&e1DecryptData, /* decrypted data */ + &e1DecryptDataLength, /* actual size of decrypted + data */ + encData.buffer,/* encrypted data */ + encData.size, /* encrypted data size */ + parentKey); + } + if (returnCode == TPM_SUCCESS) { + stream = e1DecryptData; + stream_size = e1DecryptDataLength; + returnCode = TPM_StoreAsymkey_Load(&keyEntity, FALSE, + &stream, &stream_size, + NULL, /* TPM_KEY_PARMS */ + NULL); /* TPM_SIZED_BUFFER pubKey */ + } + /* 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. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&ephKey, &ephPCRStatus, tpm_state, ephHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if (returnCode == TPM_SUCCESS) { + if (ephKey->keyUsage != TPM_KEY_AUTHCHANGE) { + printf("TPM_Process_ChangeAuthAsymFinish: Error: " + "ephHandle does not point to TPM_KEY_AUTHCHANGE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPrivateDecryptMalloc(&a1Auth, /* decrypted data */ + &a1AuthLength, /* actual size of decrypted data */ + encNewAuth.buffer, /* encrypted data */ + encNewAuth.size, /* encrypted data size */ + ephKey); + } + if (returnCode == TPM_SUCCESS) { + stream = a1Auth; + stream_size = a1AuthLength; + returnCode = TPM_ChangeauthValidate_Load(&changeauthValidate, &stream, &stream_size); + } + /* 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). */ + /* 6. The TPM SHALL compare b1 with newAuthLink. The TPM SHALL indicate a failure if the values + do not match. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_HMAC_Check(&valid, + newAuthLink, /* expect */ + keyEntity.usageAuth, /* HMAC key is current auth */ + TPM_SECRET_SIZE, changeauthValidate.newAuthSecret, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + if (!valid) { + printf("TPM_Process_ChangeAuthAsymFinish: Error, authenticating newAuthLink\n"); + returnCode = TPM_AUTHFAIL; + } + } + if (returnCode == TPM_SUCCESS) { + /* 7. The TPM SHALL replace e1 -> authData with a1 -> newAuthSecret */ + TPM_Secret_Copy(keyEntity.usageAuth, changeauthValidate.newAuthSecret); + /* 8. The TPM SHALL encrypt e1 using the appropriate functions for the entity type. The key + to encrypt with is parentHandle. */ + returnCode = TPM_StoreAsymkey_GenerateEncData(&outData, &keyEntity, parentKey); + } + /* 9. The TPM SHALL create salt-Nonce by taking the next 20 bytes from the TPM RNG. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Random(saltNonce, TPM_NONCE_SIZE); + } + /* 10. The TPM SHALL create changeProof a HMAC of (saltNonce concatenated with a1 -> n1) using + a1 -> newAuthSecret as the HMAC secret. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_HMAC_Generate(changeProof, /* hmac output */ + changeauthValidate.newAuthSecret, /* hmac key */ + TPM_NONCE_SIZE, saltNonce, + TPM_NONCE_SIZE, changeauthValidate.n1, + 0, NULL); + } + /* 11. The TPM MUST destroy the TPM_KEY_AUTHCHANGE key associated with the authorization + session. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ChangeAuthAsymFinish: Deleting ephemeral key\n"); + TPM_Key_Delete(ephKey); /* free the key resources */ + free(ephKey); /* free the key itself */ + /* remove entry from the key handle entries list */ + returnCode = TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, + ephHandle); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ChangeAuthAsymFinish: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + } + /* return saltNonce */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, saltNonce); + } + /* return changeProof */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, changeProof); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&encNewAuth); /* @1 */ + TPM_SizedBuffer_Delete(&encData); /* @2 */ + TPM_SizedBuffer_Delete(&outData); /* @3 */ + TPM_StoreAsymkey_Delete(&keyEntity); /* @4 */ + free(e1DecryptData); /* @5 */ + free(a1Auth); /* @6 */ + TPM_ChangeauthValidate_Delete(&changeauthValidate); /* @7 */ + return rcf; +} diff --git a/src/tpm_auth.h b/src/tpm_auth.h new file mode 100644 index 00000000..fa8250a9 --- /dev/null +++ b/src/tpm_auth.h @@ -0,0 +1,176 @@ +/********************************************************************************/ +/* */ +/* Authorization */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_auth.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_AUTH_H +#define TPM_AUTH_H + +#include "tpm_global.h" +#include "tpm_session.h" +#include "tpm_store.h" +#include "tpm_structures.h" +#include "tpm_types.h" + +/* + TPM_AUTHDATA +*/ + +void TPM_Authdata_Init(TPM_AUTHDATA tpm_authdata); +TPM_RESULT TPM_Authdata_Load(TPM_AUTHDATA tpm_authdata, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Authdata_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUTHDATA tpm_authdata); + +TPM_RESULT TPM_Authdata_Generate(TPM_AUTHDATA resAuth, + TPM_SECRET usageAuth, + TPM_DIGEST outParamDigest, + TPM_NONCE nonceEven, + TPM_NONCE nonceOdd, + TPM_BOOL continueSession); + +TPM_RESULT TPM_Authdata_Check(tpm_state_t *tpm_state, + TPM_SECRET hmacKey, + TPM_DIGEST inParamDigest, + TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + TPM_NONCE nonceOdd, + TPM_BOOL continueSession, + TPM_AUTHDATA usageAuth); +TPM_RESULT TPM_Auth2data_Check(tpm_state_t *tpm_state, + TPM_SECRET hmacKey, + TPM_DIGEST inParamDigest, + TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + TPM_NONCE nonceOdd, + TPM_BOOL continueSession, + TPM_AUTHDATA usageAuth); + +TPM_RESULT TPM_Authdata_Fail(tpm_state_t *tpm_state); +TPM_RESULT TPM_Authdata_GetState(TPM_DA_STATE *state, + uint32_t *timeLeft, + tpm_state_t *tpm_state); +TPM_RESULT TPM_Authdata_CheckState(tpm_state_t *tpm_state); + +/* + Utilities for command input and output parameter load and store +*/ + +TPM_RESULT TPM_AuthParams_Get(TPM_AUTHHANDLE *authHandle, + TPM_BOOL *authHandleValid, + TPM_NONCE nonceOdd, + TPM_BOOL *continueAuthSession, + TPM_AUTHDATA authData, + unsigned char **command, + uint32_t *paramSize); + +TPM_RESULT TPM_AuthParams_Set(TPM_STORE_BUFFER *response, + TPM_SECRET hmacKey, + TPM_AUTH_SESSION_DATA *auth_session_data, + TPM_DIGEST outParamDigest, + TPM_NONCE nonceOdd, + TPM_BOOL continueAuthSession); + +/* + TPM_CHANGEAUTH_VALIDATE +*/ + +void TPM_ChangeauthValidate_Init(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate); +TPM_RESULT TPM_ChangeauthValidate_Load(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_ChangeauthValidate_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate); +void TPM_ChangeauthValidate_Delete(TPM_CHANGEAUTH_VALIDATE *tpm_changeauth_validate); + +/* + TPM_DA_INFO +*/ + +void TPM_DaInfo_Init(TPM_DA_INFO *tpm_da_info); +TPM_RESULT TPM_DaInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DA_INFO *tpm_da_info); +void TPM_DaInfo_Delete(TPM_DA_INFO *tpm_da_info); + +TPM_RESULT TPM_DaInfo_Set(TPM_DA_INFO *tpm_da_info, + tpm_state_t *tpm_state); + +/* + TPM_DA_INFO_LIMITED +*/ + +void TPM_DaInfoLimited_Init(TPM_DA_INFO_LIMITED *tpm_da_info_limited); +TPM_RESULT TPM_DaInfoLimited_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DA_INFO_LIMITED *tpm_da_info_limited); +void TPM_DaInfoLimited_Delete(TPM_DA_INFO_LIMITED *tpm_da_info_limited); + +TPM_RESULT TPM_DaInfoLimited_Set(TPM_DA_INFO_LIMITED *tpm_da_info_limited, + tpm_state_t *tpm_state); + +/* + Processing functions +*/ + +TPM_RESULT TPM_Process_ChangeAuth(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ChangeAuthOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ChangeAuthAsymStart(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ChangeAuthAsymFinish(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +#endif diff --git a/src/tpm_commands.h b/src/tpm_commands.h new file mode 100644 index 00000000..a12c3827 --- /dev/null +++ b/src/tpm_commands.h @@ -0,0 +1,51 @@ +/********************************************************************************/ +/* */ +/* TPM Command Structure */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_commands.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_COMMANDS_H +#define TPM_COMMANDS_H + +#include "tpm_types.h" + +/* general structure for all commands */ + +#define TPM_TAG_OFFSET 0 +#define TPM_PARAMSIZE_OFFSET (sizeof(TPM_TAG) + TPM_TAG_OFFSET) +#define TPM_ORDINAL_OFFSET (sizeof(uint32_t) + TPM_PARAMSIZE_OFFSET) + +#endif diff --git a/src/tpm_constants.h b/src/tpm_constants.h new file mode 100644 index 00000000..00174f61 --- /dev/null +++ b/src/tpm_constants.h @@ -0,0 +1,1652 @@ +/********************************************************************************/ +/* */ +/* TPM Constants */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_constants.h 4603 2011-08-16 20:40:26Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_CONSTANTS_H +#define TPM_CONSTANTS_H + +#include + +/* + NOTE implementation Specific +*/ + +/* + version, revision, specLevel, errataRev +*/ + +/* current for released specification revision 103 */ + +#define TPM_REVISION_MAX 9999 +#ifndef TPM_REVISION +#define TPM_REVISION TPM_REVISION_MAX +#endif + +#if (TPM_REVISION >= 116) + +#define TPM_SPEC_LEVEL 0x0002 /* uint16_t The level of ordinals supported */ +#define TPM_ERRATA_REV 0x03 /* specification errata level */ + +#elif (TPM_REVISION >= 103) + +#define TPM_SPEC_LEVEL 0x0002 /* uint16_t The level of ordinals supported */ +#define TPM_ERRATA_REV 0x02 /* specification errata level */ + +#elif (TPM_REVISION >= 94) + +#define TPM_SPEC_LEVEL 0x0002 /* uint16_t The level of ordinals supported */ +#define TPM_ERRATA_REV 0x01 /* specification errata level */ + +#elif (TPM_REVISION >= 85) + +#define TPM_SPEC_LEVEL 0x0002 /* uint16_t The level of ordinals supported */ +#define TPM_ERRATA_REV 0x00 /* specification errata level */ + +#else + +#define TPM_SPEC_LEVEL 0x0001 /* uint16_t The level of ordinals supported */ +#define TPM_ERRATA_REV 0x00 /* specification errata level */ + +#endif + +/* IBM specific */ + +#if 0 /* at one time vendorID was the PCI vendor ID, this is the IBM code */ +#define TPM_VENDOR_ID "\x00\x00\x10\x14" /* BYTE[4], the vendor ID, obtained from the TCG, + typically PCI vendor ID */ +#endif + + + +#define TPM_VENDOR_ID "IBM" /* 4 bytes, as of rev 99 vendorID and TPM_CAP_PROP_MANUFACTURER + return the same value */ +#define TPM_MANUFACTURER "IBM" /* 4 characters, assigned by TCG, typically stock ticker symbol */ + + +/* Timeouts in microseconds. These are for the platform specific interface (e.g. the LPC bus + registers in the PC Client TPM). They are most likely not applicable to a software TPM. */ +#define TPM_TIMEOUT_A 1000000 +#define TPM_TIMEOUT_B 1000000 +#define TPM_TIMEOUT_C 1000000 +#define TPM_TIMEOUT_D 1000000 + +/* dictionary attack mitigation */ + +#define TPM_LOCKOUT_THRESHOLD 5 /* successive failures to trigger lockout, must be greater + than 0 */ + +/* Denotes the duration value in microseconds of the duration of the three classes of commands: + Small, Medium and Long. The command types are in the Part 2 Ordinal Table. Essentially: + + Long - creating an RSA key pair + Medium - using an RSA key + Short - anything else +*/ + +#ifndef TPM_SMALL_DURATION +#define TPM_SMALL_DURATION 2000000 +#endif + +#ifndef TPM_MEDIUM_DURATION +#define TPM_MEDIUM_DURATION 5000000 +#endif + +#ifndef TPM_LONG_DURATION +#define TPM_LONG_DURATION 60000000 +#endif + +/* startup effects */ + +#define TPM_STARTUP_EFFECTS_VALUE \ +(TPM_STARTUP_EFFECTS_ST_ANY_RT_KEY | /* key resources init by TPM_Startup(ST_ANY) */ \ + TPM_STARTUP_EFFECTS_ST_STATE_RT_HASH | /* hash resources are init by TPM_Startup(ST_STATE) */ \ + TPM_STARTUP_EFFECTS_ST_CLEAR_AUDITDIGEST) /* auditDigest nulled on TPM_Startup(ST_CLEAR) */ + +/* + TPM buffer limits +*/ + +/* This value is used to limit memory allocation to prevent resource overload. */ + +#ifndef TPM_ALLOC_MAX +#define TPM_ALLOC_MAX 0x10000 /* 64k bytes */ +#endif + +/* This is the increment by which the TPM_STORE_BUFFER grows. A larger number saves realloc's. A + smaller number saves memory. + + TPM_ALLOC_MAX must be a multiple of this value. +*/ + +#define TPM_STORE_BUFFER_INCREMENT (TPM_ALLOC_MAX / 64) + +/* This is the maximum value of the TPM input and output packet buffer. It should be large enough + to accommodate the largest TPM command or response, currently about 1200 bytes. It should be + small enough to accommodate whatever software is driving the TPM. + + NOTE: Some commands are somewhat open ended, and related to this parmater. E.g., The input size + for the TPM_SHA1Init. The output size for TPM_GetRandom. + + It is returned by TPM_GetCapability -> TPM_CAP_PROP_INPUT_BUFFER +*/ + +#ifndef TPM_BUFFER_MAX +#define TPM_BUFFER_MAX 0x1000 /* 4k bytes */ +#endif + +/* Random number generator */ + +/* maximum bytes in one TPM_GetRandom() call + + Use maximum input buffer size minus tag, paramSize, returnCode, randomBytesSize. +*/ + +#define TPM_RANDOM_MAX (TPM_BUFFER_MAX \ + - sizeof(TPM_TAG) - sizeof(uint32_t) \ + - sizeof(TPM_RESULT) - sizeof(uint32_t)) + +/* Maximum number of bytes that can be sent to TPM_SHA1Update. Must be a multiple of 64 bytes. + + Use maximum input buffer size minus tag, paramSize, ordinal, numBytes. +*/ + +#define TPM_SHA1_MAXNUMBYTES (TPM_BUFFER_MAX - 64) + +/* extra audit status bits for TSC commands outside the normal ordinal range */ +#define TSC_PHYS_PRES_AUDIT 0x01 +#define TSC_RESET_ESTAB_AUDIT 0x02 + + +/* TPM_CAP_MFR capabilities */ +#define TPM_CAP_PROCESS_ID 0x00000020 + + +/* define a value for an illegal instance handle */ + +#define TPM_ILLEGAL_INSTANCE_HANDLE 0xffffffff + +/* + NOTE End Implementation Specific +*/ + +/* 3. Structure Tags rev 105 + + There have been some indications that knowing what structure is in use would be valuable + information in each structure. This new tag will be in each new structure that the TPM defines. + + The upper nibble of the value designates the purview of the structure tag. 0 is used for TPM + structures, 1 for platforms, and 2-F are reserved. +*/ + +/* 3.1 TPM_STRUCTURE_TAG */ + +/* Structure */ +#define TPM_TAG_CONTEXTBLOB 0x0001 /* TPM_CONTEXT_BLOB */ +#define TPM_TAG_CONTEXT_SENSITIVE 0x0002 /* TPM_CONTEXT_SENSITIVE */ +#define TPM_TAG_CONTEXTPOINTER 0x0003 /* TPM_CONTEXT_POINTER */ +#define TPM_TAG_CONTEXTLIST 0x0004 /* TPM_CONTEXT_LIST */ +#define TPM_TAG_SIGNINFO 0x0005 /* TPM_SIGN_INFO */ +#define TPM_TAG_PCR_INFO_LONG 0x0006 /* TPM_PCR_INFO_LONG */ +#define TPM_TAG_PERSISTENT_FLAGS 0x0007 /* TPM_PERSISTENT_FLAGS (deprecated 1.1 struct) */ +#define TPM_TAG_VOLATILE_FLAGS 0x0008 /* TPM_VOLATILE_FLAGS (deprecated 1.1 struct) */ +#define TPM_TAG_PERSISTENT_DATA 0x0009 /* TPM_PERSISTENT_DATA (deprecated 1.1 struct) */ +#define TPM_TAG_VOLATILE_DATA 0x000A /* TPM_VOLATILE_DATA (deprecated 1.1 struct) */ +#define TPM_TAG_SV_DATA 0x000B /* TPM_SV_DATA */ +#define TPM_TAG_EK_BLOB 0x000C /* TPM_EK_BLOB */ +#define TPM_TAG_EK_BLOB_AUTH 0x000D /* TPM_EK_BLOB_AUTH */ +#define TPM_TAG_COUNTER_VALUE 0x000E /* TPM_COUNTER_VALUE */ +#define TPM_TAG_TRANSPORT_INTERNAL 0x000F /* TPM_TRANSPORT_INTERNAL */ +#define TPM_TAG_TRANSPORT_LOG_IN 0x0010 /* TPM_TRANSPORT_LOG_IN */ +#define TPM_TAG_TRANSPORT_LOG_OUT 0x0011 /* TPM_TRANSPORT_LOG_OUT */ +#define TPM_TAG_AUDIT_EVENT_IN 0x0012 /* TPM_AUDIT_EVENT_IN */ +#define TPM_TAG_AUDIT_EVENT_OUT 0X0013 /* TPM_AUDIT_EVENT_OUT */ +#define TPM_TAG_CURRENT_TICKS 0x0014 /* TPM_CURRENT_TICKS */ +#define TPM_TAG_KEY 0x0015 /* TPM_KEY */ +#define TPM_TAG_STORED_DATA12 0x0016 /* TPM_STORED_DATA12 */ +#define TPM_TAG_NV_ATTRIBUTES 0x0017 /* TPM_NV_ATTRIBUTES */ +#define TPM_TAG_NV_DATA_PUBLIC 0x0018 /* TPM_NV_DATA_PUBLIC */ +#define TPM_TAG_NV_DATA_SENSITIVE 0x0019 /* TPM_NV_DATA_SENSITIVE */ +#define TPM_TAG_DELEGATIONS 0x001A /* TPM DELEGATIONS */ +#define TPM_TAG_DELEGATE_PUBLIC 0x001B /* TPM_DELEGATE_PUBLIC */ +#define TPM_TAG_DELEGATE_TABLE_ROW 0x001C /* TPM_DELEGATE_TABLE_ROW */ +#define TPM_TAG_TRANSPORT_AUTH 0x001D /* TPM_TRANSPORT_AUTH */ +#define TPM_TAG_TRANSPORT_PUBLIC 0X001E /* TPM_TRANSPORT_PUBLIC */ +#define TPM_TAG_PERMANENT_FLAGS 0X001F /* TPM_PERMANENT_FLAGS */ +#define TPM_TAG_STCLEAR_FLAGS 0X0020 /* TPM_STCLEAR_FLAGS */ +#define TPM_TAG_STANY_FLAGS 0X0021 /* TPM_STANY_FLAGS */ +#define TPM_TAG_PERMANENT_DATA 0X0022 /* TPM_PERMANENT_DATA */ +#define TPM_TAG_STCLEAR_DATA 0X0023 /* TPM_STCLEAR_DATA */ +#define TPM_TAG_STANY_DATA 0X0024 /* TPM_STANY_DATA */ +#define TPM_TAG_FAMILY_TABLE_ENTRY 0X0025 /* TPM_FAMILY_TABLE_ENTRY */ +#define TPM_TAG_DELEGATE_SENSITIVE 0X0026 /* TPM_DELEGATE_SENSITIVE */ +#define TPM_TAG_DELG_KEY_BLOB 0X0027 /* TPM_DELG_KEY_BLOB */ +#define TPM_TAG_KEY12 0x0028 /* TPM_KEY12 */ +#define TPM_TAG_CERTIFY_INFO2 0X0029 /* TPM_CERTIFY_INFO2 */ +#define TPM_TAG_DELEGATE_OWNER_BLOB 0X002A /* TPM_DELEGATE_OWNER_BLOB */ +#define TPM_TAG_EK_BLOB_ACTIVATE 0X002B /* TPM_EK_BLOB_ACTIVATE */ +#define TPM_TAG_DAA_BLOB 0X002C /* TPM_DAA_BLOB */ +#define TPM_TAG_DAA_CONTEXT 0X002D /* TPM_DAA_CONTEXT */ +#define TPM_TAG_DAA_ENFORCE 0X002E /* TPM_DAA_ENFORCE */ +#define TPM_TAG_DAA_ISSUER 0X002F /* TPM_DAA_ISSUER */ +#define TPM_TAG_CAP_VERSION_INFO 0X0030 /* TPM_CAP_VERSION_INFO */ +#define TPM_TAG_DAA_SENSITIVE 0X0031 /* TPM_DAA_SENSITIVE */ +#define TPM_TAG_DAA_TPM 0X0032 /* TPM_DAA_TPM */ +#define TPM_TAG_CMK_MIGAUTH 0X0033 /* TPM_CMK_MIGAUTH */ +#define TPM_TAG_CMK_SIGTICKET 0X0034 /* TPM_CMK_SIGTICKET */ +#define TPM_TAG_CMK_MA_APPROVAL 0X0035 /* TPM_CMK_MA_APPROVAL */ +#define TPM_TAG_QUOTE_INFO2 0X0036 /* TPM_QUOTE_INFO2 */ +#define TPM_TAG_DA_INFO 0x0037 /* TPM_DA_INFO */ +#define TPM_TAG_DA_INFO_LIMITED 0x0038 /* TPM_DA_INFO_LIMITED */ +#define TPM_TAG_DA_ACTION_TYPE 0x0039 /* TPM_DA_ACTION_TYPE */ + +/* + SW TPM Tags +*/ + +/* + These tags are used to describe the format of serialized TPM non-volatile state +*/ + +/* These describe the overall format */ + +/* V1 state is the sequence permanent data, permanent flags, owner evict keys, NV defined space */ + +#define TPM_TAG_NVSTATE_V1 0x0001 /* svn revision 4078 */ + +/* These tags describe the TPM_PERMANENT_DATA format */ + +/* For the first release, use the standard TPM_TAG_PERMANENT_DATA tag. Since this tag is never + visible outside the TPM, the tag value can be changed if the format changes. +*/ + +/* These tags describe the TPM_PERMANENT_FLAGS format */ + +/* The TPM_PERMANENT_FLAGS structure changed from rev 94 to 103. Unfortunately, the standard TPM + tag did not change. Define distinguishing values here. +*/ + +#define TPM_TAG_NVSTATE_PF94 0x0001 +#define TPM_TAG_NVSTATE_PF103 0x0002 + +/* This tag describes the owner evict key format */ + +#define TPM_TAG_NVSTATE_OE_V1 0x0001 + +/* This tag describes the NV defined space format */ + +#define TPM_TAG_NVSTATE_NV_V1 0x0001 + +/* V2 added the NV public optimization */ + +#define TPM_TAG_NVSTATE_NV_V2 0x0002 + +/* + These tags are used to describe the format of serialized TPM volatile state +*/ + +/* These describe the overall format */ + +/* V1 state is the sequence TPM Parameters, TPM_STCLEAR_FLAGS, TPM_STANY_FLAGS, TPM_STCLEAR_DATA, + TPM_STANY_DATA, TPM_KEY_HANDLE_ENTRY, SHA1 context(s), TPM_TRANSHANDLE, testState, NV volatile + flags */ + +#define TPM_TAG_VSTATE_V1 0x0001 + +/* This tag defines the TPM Parameters format */ + +#define TPM_TAG_TPM_PARAMETERS_V1 0x0001 + +/* This tag defines the TPM_STCLEAR_FLAGS format */ + +/* V1 is the TCG standard returned by the getcap. It's unlikely that this will change */ + +#define TPM_TAG_STCLEAR_FLAGS_V1 0x0001 + +/* These tags describe the TPM_STANY_FLAGS format */ + +/* For the first release, use the standard TPM_TAG_STANY_FLAGS tag. Since this tag is never visible + outside the TPM, the tag value can be changed if the format changes. +*/ + +/* This tag defines the TPM_STCLEAR_DATA format */ + +/* V2 deleted the ordinalResponse, responseCount */ + +#define TPM_TAG_STCLEAR_DATA_V2 0X0024 + +/* These tags describe the TPM_STANY_DATA format */ + +/* For the first release, use the standard TPM_TAG_STANY_DATA tag. Since this tag is never visible + outside the TPM, the tag value can be changed if the format changes. +*/ + +/* This tag defines the key handle entries format */ + +#define TPM_TAG_KEY_HANDLE_ENTRIES_V1 0x0001 + +/* This tag defines the SHA-1 context format */ + +#define TPM_TAG_SHA1CONTEXT_OSSL_V1 0x0001 /* for openssl */ + +#define TPM_TAG_SHA1CONTEXT_FREEBL_V1 0x0101 /* for freebl */ + +/* This tag defines the NV index entries volatile format */ + +#define TPM_TAG_NV_INDEX_ENTRIES_VOLATILE_V1 0x0001 + +/* 4. Types + */ + +/* 4.1 TPM_RESOURCE_TYPE rev 87 */ + +#define TPM_RT_KEY 0x00000001 /* The handle is a key handle and is the result of a LoadKey + type operation */ + +#define TPM_RT_AUTH 0x00000002 /* The handle is an authorization handle. Auth handles come from + TPM_OIAP, TPM_OSAP and TPM_DSAP */ + +#define TPM_RT_HASH 0X00000003 /* Reserved for hashes */ + +#define TPM_RT_TRANS 0x00000004 /* The handle is for a transport session. Transport handles come + from TPM_EstablishTransport */ + +#define TPM_RT_CONTEXT 0x00000005 /* Resource wrapped and held outside the TPM using the context + save/restore commands */ + +#define TPM_RT_COUNTER 0x00000006 /* Reserved for counters */ + +#define TPM_RT_DELEGATE 0x00000007 /* The handle is for a delegate row. These are the internal rows + held in NV storage by the TPM */ + +#define TPM_RT_DAA_TPM 0x00000008 /* The value is a DAA TPM specific blob */ + +#define TPM_RT_DAA_V0 0x00000009 /* The value is a DAA V0 parameter */ + +#define TPM_RT_DAA_V1 0x0000000A /* The value is a DAA V1 parameter */ + +/* 4.2 TPM_PAYLOAD_TYPE rev 87 + + This structure specifies the type of payload in various messages. +*/ + +#define TPM_PT_ASYM 0x01 /* The entity is an asymmetric key */ +#define TPM_PT_BIND 0x02 /* The entity is bound data */ +#define TPM_PT_MIGRATE 0x03 /* The entity is a migration blob */ +#define TPM_PT_MAINT 0x04 /* The entity is a maintenance blob */ +#define TPM_PT_SEAL 0x05 /* The entity is sealed data */ +#define TPM_PT_MIGRATE_RESTRICTED 0x06 /* The entity is a restricted-migration asymmetric key */ +#define TPM_PT_MIGRATE_EXTERNAL 0x07 /* The entity is a external migratable key */ +#define TPM_PT_CMK_MIGRATE 0x08 /* The entity is a CMK migratable blob */ +/* 0x09 - 0x7F Reserved for future use by TPM */ +/* 0x80 - 0xFF Vendor specific payloads */ + +/* 4.3 TPM_ENTITY_TYPE rev 100 + + This specifies the types of entity 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, this mapping is maintained: + + 0x0001 specifies a keyHandle entity with XOR encryption + 0x0002 specifies an owner entity with XOR encryption + 0x0003 specifies some data entity with XOR encryption + 0x0004 specifies the SRK entity with XOR encryption + 0x0005 specifies a key entity with XOR encryption + + When the entity is not being used for ADIP encryption, the MSB MUST be 0x00. +*/ + +/* TPM_ENTITY_TYPE LSB Values (entity type) */ + +#define TPM_ET_KEYHANDLE 0x01 /* The entity is a keyHandle or key */ +#define TPM_ET_OWNER 0x02 /*0x40000001 The entity is the TPM Owner */ +#define TPM_ET_DATA 0x03 /* The entity is some data */ +#define TPM_ET_SRK 0x04 /*0x40000000 The entity is the SRK */ +#define TPM_ET_KEY 0x05 /* The entity is a key or keyHandle */ +#define TPM_ET_REVOKE 0x06 /*0x40000002 The entity is the RevokeTrust value */ +#define TPM_ET_DEL_OWNER_BLOB 0x07 /* The entity is a delegate owner blob */ +#define TPM_ET_DEL_ROW 0x08 /* The entity is a delegate row */ +#define TPM_ET_DEL_KEY_BLOB 0x09 /* The entity is a delegate key blob */ +#define TPM_ET_COUNTER 0x0A /* The entity is a counter */ +#define TPM_ET_NV 0x0B /* The entity is a NV index */ +#define TPM_ET_OPERATOR 0x0C /* The entity is the operator */ +#define TPM_ET_RESERVED_HANDLE 0x40 /* Reserved. This value avoids collisions with the handle + MSB setting.*/ + +/* TPM_ENTITY_TYPE MSB Values (ADIP encryption scheme) */ + +#define TPM_ET_XOR 0x00 /* XOR */ +#define TPM_ET_AES128_CTR 0x06 /* AES 128 bits in CTR mode */ + +/* 4.4 Handles rev 88 + + Handles provides pointers to TPM internal resources. Handles should provide the ability to locate + a value without collision. + + 1. The TPM MAY order and set a handle to any value the TPM determines is appropriate + + 2. The handle value SHALL provide assurance that collisions SHOULD not occur in 2^24 handles + + 4.4.1 Reserved Key Handles + + The reserved key handles. These values specify specific keys or specific actions for the TPM. +*/ + +/* 4.4.1 Reserved Key Handles rev 87 + + The reserved key handles. These values specify specific keys or specific actions for the TPM. + + TPM_KH_TRANSPORT indicates to TPM_EstablishTransport that there is no encryption key, and that + the "secret" wrapped parameters are actually passed unencrypted. +*/ + +#define TPM_KH_SRK 0x40000000 /* The handle points to the SRK */ +#define TPM_KH_OWNER 0x40000001 /* The handle points to the TPM Owner */ +#define TPM_KH_REVOKE 0x40000002 /* The handle points to the RevokeTrust value */ +#define TPM_KH_TRANSPORT 0x40000003 /* The handle points to the TPM_EstablishTransport static + authorization */ +#define TPM_KH_OPERATOR 0x40000004 /* The handle points to the Operator auth */ +#define TPM_KH_ADMIN 0x40000005 /* The handle points to the delegation administration + auth */ +#define TPM_KH_EK 0x40000006 /* The handle points to the PUBEK, only usable with + TPM_OwnerReadInternalPub */ + +/* 4.5 TPM_STARTUP_TYPE rev 87 + + To specify what type of startup is occurring. +*/ + +#define TPM_ST_CLEAR 0x0001 /* The TPM is starting up from a clean state */ +#define TPM_ST_STATE 0x0002 /* The TPM is starting up from a saved state */ +#define TPM_ST_DEACTIVATED 0x0003 /* The TPM is to startup and set the deactivated flag to + TRUE */ + +/* 4.6 TPM_STARTUP_EFFECTS rev 101 + + This structure lists for the various resources and sessions on a TPM the affect that TPM_Startup + has on the values. + + There are three ST_STATE options for keys (restore all, restore non-volatile, or restore none) + and two ST_CLEAR options (restore non-volatile or restore none). As bit 4 was insufficient to + describe the possibilities, it is deprecated. Software should use TPM_CAP_KEY_HANDLE to + determine which keys are loaded after TPM_Startup. + + 31-9 No information and MUST be FALSE + + 8 TPM_RT_DAA_TPM resources are initialized by TPM_Startup(ST_STATE) + 7 TPM_Startup has no effect on auditDigest + 6 auditDigest is set to all zeros on TPM_Startup(ST_CLEAR) but not on other types of TPM_Startup + 5 auditDigest is set to all zeros on TPM_Startup(any) + 4 TPM_RT_KEY Deprecated, as the meaning was subject to interpretation. (Was:TPM_RT_KEY resources + are initialized by TPM_Startup(ST_ANY)) + 3 TPM_RT_AUTH resources are initialized by TPM_Startup(ST_STATE) + 2 TPM_RT_HASH resources are initialized by TPM_Startup(ST_STATE) + 1 TPM_RT_TRANS resources are initialized by TPM_Startup(ST_STATE) + 0 TPM_RT_CONTEXT session (but not key) resources are initialized by TPM_Startup(ST_STATE) +*/ + + +#define TPM_STARTUP_EFFECTS_ST_STATE_RT_DAA 0x00000100 /* bit 8 */ +#define TPM_STARTUP_EFFECTS_STARTUP_NO_AUDITDIGEST 0x00000080 /* bit 7 */ +#define TPM_STARTUP_EFFECTS_ST_CLEAR_AUDITDIGEST 0x00000040 /* bit 6 */ +#define TPM_STARTUP_EFFECTS_STARTUP_AUDITDIGEST 0x00000020 /* bit 5 */ +#define TPM_STARTUP_EFFECTS_ST_ANY_RT_KEY 0x00000010 /* bit 4 */ +#define TPM_STARTUP_EFFECTS_ST_STATE_RT_AUTH 0x00000008 /* bit 3 */ +#define TPM_STARTUP_EFFECTS_ST_STATE_RT_HASH 0x00000004 /* bit 2 */ +#define TPM_STARTUP_EFFECTS_ST_STATE_RT_TRANS 0x00000002 /* bit 1 */ +#define TPM_STARTUP_EFFECTS_ST_STATE_RT_CONTEXT 0x00000001 /* bit 0 */ + +/* 4.7 TPM_PROTOCOL_ID rev 87 + + This value identifies the protocol in use. +*/ + +#define TPM_PID_NONE 0x0000 /* kgold - added */ +#define TPM_PID_OIAP 0x0001 /* The OIAP protocol. */ +#define TPM_PID_OSAP 0x0002 /* The OSAP protocol. */ +#define TPM_PID_ADIP 0x0003 /* The ADIP protocol. */ +#define TPM_PID_ADCP 0X0004 /* The ADCP protocol. */ +#define TPM_PID_OWNER 0X0005 /* The protocol for taking ownership of a TPM. */ +#define TPM_PID_DSAP 0x0006 /* The DSAP protocol */ +#define TPM_PID_TRANSPORT 0x0007 /*The transport protocol */ + +/* 4.8 TPM_ALGORITHM_ID rev 99 + + This table defines the types of algorithms that may be supported by the TPM. + + The TPM MUST support the algorithms TPM_ALG_RSA, TPM_ALG_SHA, TPM_ALG_HMAC, and TPM_ALG_MGF1 +*/ + +#define TPM_ALG_RSA 0x00000001 /* The RSA algorithm. */ +/* #define TPM_ALG_DES 0x00000002 (was the DES algorithm) */ +/* #define TPM_ALG_3DES 0X00000003 (was the 3DES algorithm in EDE mode) */ +#define TPM_ALG_SHA 0x00000004 /* The SHA1 algorithm */ +#define TPM_ALG_HMAC 0x00000005 /* The RFC 2104 HMAC algorithm */ +#define TPM_ALG_AES128 0x00000006 /* The AES algorithm, key size 128 */ +#define TPM_ALG_MGF1 0x00000007 /* The XOR algorithm using MGF1 to create a string the size + of the encrypted block */ +#define TPM_ALG_AES192 0x00000008 /* AES, key size 192 */ +#define TPM_ALG_AES256 0x00000009 /* AES, key size 256 */ +#define TPM_ALG_XOR 0x0000000A /* XOR using the rolling nonces */ + +/* 4.9 TPM_PHYSICAL_PRESENCE rev 87 + +*/ + +#define TPM_PHYSICAL_PRESENCE_HW_DISABLE 0x0200 /* Sets the physicalPresenceHWEnable to FALSE + */ +#define TPM_PHYSICAL_PRESENCE_CMD_DISABLE 0x0100 /* Sets the physicalPresenceCMDEnable to + FALSE */ +#define TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK 0x0080 /* Sets the physicalPresenceLifetimeLock to + TRUE */ +#define TPM_PHYSICAL_PRESENCE_HW_ENABLE 0x0040 /* Sets the physicalPresenceHWEnable to TRUE + */ +#define TPM_PHYSICAL_PRESENCE_CMD_ENABLE 0x0020 /* Sets the physicalPresenceCMDEnable to TRUE + */ +#define TPM_PHYSICAL_PRESENCE_NOTPRESENT 0x0010 /* Sets PhysicalPresence = FALSE */ +#define TPM_PHYSICAL_PRESENCE_PRESENT 0x0008 /* Sets PhysicalPresence = TRUE */ +#define TPM_PHYSICAL_PRESENCE_LOCK 0x0004 /* Sets PhysicalPresenceLock = TRUE */ + +#define TPM_PHYSICAL_PRESENCE_MASK 0xfc03 /* ~ OR of all above bits */ + +/* 4.10 TPM_MIGRATE_SCHEME rev 103 + + The scheme indicates how the StartMigrate command should handle the migration of the encrypted + blob. +*/ + +#define TPM_MS_MIGRATE 0x0001 /* A public key that can be used with all TPM + migration commands other than 'ReWrap' mode. */ +#define TPM_MS_REWRAP 0x0002 /* A public key that can be used for the ReWrap mode + of TPM_CreateMigrationBlob. */ +#define TPM_MS_MAINT 0x0003 /* A public key that can be used for the Maintenance + commands */ +#define TPM_MS_RESTRICT_MIGRATE 0x0004 /* The key is to be migrated to a Migration + Authority. */ +#define TPM_MS_RESTRICT_APPROVE 0x0005 /* The key is to be migrated to an entity approved by + a Migration Authority using double wrapping */ + +/* 4.11 TPM_EK_TYPE rev 87 + + This structure indicates what type of information that the EK is dealing with. +*/ + +#define TPM_EK_TYPE_ACTIVATE 0x0001 /* The blob MUST be TPM_EK_BLOB_ACTIVATE */ +#define TPM_EK_TYPE_AUTH 0x0002 /* The blob MUST be TPM_EK_BLOB_AUTH */ + +/* 4.12 TPM_PLATFORM_SPECIFIC rev 87 + + This enumerated type indicates the platform specific spec that the information relates to. +*/ + +#define TPM_PS_PC_11 0x0001 /* PC Specific version 1.1 */ +#define TPM_PS_PC_12 0x0002 /* PC Specific version 1.2 */ +#define TPM_PS_PDA_12 0x0003 /* PDA Specific version 1.2 */ +#define TPM_PS_Server_12 0x0004 /* Server Specific version 1.2 */ +#define TPM_PS_Mobile_12 0x0005 /* Mobil Specific version 1.2 */ + +/* 5.8 TPM_KEY_USAGE rev 101 + + This table defines the types of keys that are possible. Each value defines for what operation + the key can be used. Most key usages can be CMKs. See 4.2, TPM_PAYLOAD_TYPE. + + Each key has a setting defining the encryption and signature scheme to use. The selection of a + key usage value limits the choices of encryption and signature schemes. +*/ + +#define TPM_KEY_UNINITIALIZED 0x0000 /* NOTE: Added. This seems like a good place to indicate + that a TPM_KEY structure has not been initialized */ + +#define TPM_KEY_SIGNING 0x0010 /* This SHALL indicate a signing key. The [private] key + SHALL be used for signing operations, only. This means + that it MUST be a leaf of the Protected Storage key + hierarchy. */ + +#define TPM_KEY_STORAGE 0x0011 /* This SHALL indicate a storage key. The key SHALL be used + to wrap and unwrap other keys in the Protected Storage + hierarchy */ + +#define TPM_KEY_IDENTITY 0x0012 /* This SHALL indicate an identity key. The key SHALL be + used for operations that require a TPM identity, only. */ + +#define TPM_KEY_AUTHCHANGE 0X0013 /* This SHALL indicate an ephemeral key that is in use + during the ChangeAuthAsym process, only. */ + +#define TPM_KEY_BIND 0x0014 /* This SHALL indicate a key that can be used for TPM_Bind + and TPM_Unbind operations only. */ + +#define TPM_KEY_LEGACY 0x0015 /* This SHALL indicate a key that can perform signing and + binding operations. The key MAY be used for both signing + and binding operations. The TPM_KEY_LEGACY key type is to + allow for use by applications where both signing and + encryption operations occur with the same key. */ + +#define TPM_KEY_MIGRATE 0x0016 /* This SHALL indicate a key in use for TPM_MigrateKey */ + +/* 5.8.1 TPM_ENC_SCHEME Mandatory Key Usage Schemes rev 99 + + The TPM MUST check that the encryption scheme defined for use with the key is a valid scheme for + the key type, as follows: +*/ + +#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 + +/* 5.8.1 TPM_SIG_SCHEME Mandatory Key Usage Schemes rev 99 + + The TPM MUST check that the signature scheme defined for use with the key is a valid scheme for + the key type, as follows: +*/ + +#define TPM_SS_NONE 0x0001 +#define TPM_SS_RSASSAPKCS1v15_SHA1 0x0002 +#define TPM_SS_RSASSAPKCS1v15_DER 0x0003 +#define TPM_SS_RSASSAPKCS1v15_INFO 0x0004 + +/* 5.9 TPM_AUTH_DATA_USAGE rev 110 + + The indication to the TPM when authorization sessions for an entity are required. Future + versions may allow for more complex decisions regarding AuthData checking. +*/ + +#define TPM_AUTH_NEVER 0x00 /* This SHALL indicate that usage of the key without + authorization is permitted. */ + +#define TPM_AUTH_ALWAYS 0x01 /* This SHALL indicate that on each usage of the key the + authorization MUST be performed. */ + +#define TPM_NO_READ_PUBKEY_AUTH 0x03 /* This SHALL indicate that on commands that require the TPM to + use the the key, the authorization MUST be performed. For + commands that cause the TPM to read the public portion of the + key, but not to use the key (e.g. TPM_GetPubKey), the + authorization may be omitted. */ + +/* 5.10 TPM_KEY_FLAGS rev 110 + + This table defines the meanings of the bits in a TPM_KEY_FLAGS structure, used in + TPM_STORE_ASYMKEY and TPM_CERTIFY_INFO. + + The value of TPM_KEY_FLAGS MUST be decomposed into individual mask values. The presence of a mask + value SHALL have the effect described in the above table + + On input, all undefined bits MUST be zero. The TPM MUST return an error if any undefined bit is + set. On output, the TPM MUST set all undefined bits to zero. +*/ + +#ifdef TPM_V12 +#define TPM_KEY_FLAGS_MASK 0x0000001f +#else +#define TPM_KEY_FLAGS_MASK 0x00000007 +#endif + +#define TPM_REDIRECTION 0x00000001 /* This mask value SHALL indicate the use of redirected + output. */ + +#define TPM_MIGRATABLE 0x00000002 /* This mask value SHALL indicate that the key is + migratable. */ + +#define TPM_ISVOLATILE 0x00000004 /* This mask value SHALL indicate that the key MUST be + unloaded upon execution of the + TPM_Startup(ST_Clear). This does not indicate that a + non-volatile key will remain loaded across + TPM_Startup(ST_Clear) events. */ + +#define TPM_PCRIGNOREDONREAD 0x00000008 /* When TRUE the TPM MUST NOT check digestAtRelease or + localityAtRelease for commands that read the public + portion of the key (e.g., TPM_GetPubKey) and MAY NOT + check digestAtRelease or localityAtRelease for + commands that use the public portion of the key + (e.g. TPM_Seal) + + When FALSE the TPM MUST check digestAtRelease and + localityAtRelease for commands that read or use the + public portion of the key */ + +#define TPM_MIGRATEAUTHORITY 0x00000010 /* When set indicates that the key is under control of a + migration authority. The TPM MUST only allow the + creation of a key with this flag in + TPM_MA_CreateKey */ + +/* 5.17 TPM_CMK_DELEGATE values rev 89 + + The bits of TPM_CMK_DELEGATE are flags that determine how the TPM responds to delegated requests + to manipulate a certified-migration-key, a loaded key with payload type TPM_PT_MIGRATE_RESTRICTED + or TPM_PT_MIGRATE_EXTERNAL.. + + 26:0 reserved MUST be 0 + + The default value of TPM_CMK_Delegate is zero (0) +*/ + +#define TPM_CMK_DELEGATE_SIGNING 0x80000000 /* When set to 1, this bit SHALL indicate that a + delegated command may manipulate a CMK of + TPM_KEY_USAGE == TPM_KEY_SIGNING */ +#define TPM_CMK_DELEGATE_STORAGE 0x40000000 /* When set to 1, this bit SHALL indicate that a + delegated command may manipulate a CMK of + TPM_KEY_USAGE == TPM_KEY_STORAGE */ +#define TPM_CMK_DELEGATE_BIND 0x20000000 /* When set to 1, this bit SHALL indicate that a + delegated command may manipulate a CMK of + TPM_KEY_USAGE == TPM_KEY_BIND */ +#define TPM_CMK_DELEGATE_LEGACY 0x10000000 /* When set to 1, this bit SHALL indicate that a + delegated command may manipulate a CMK of + TPM_KEY_USAGE == TPM_KEY_LEGACY */ +#define TPM_CMK_DELEGATE_MIGRATE 0x08000000 /* When set to 1, this bit SHALL indicate that a + delegated command may manipulate a CMK of + TPM_KEY_USAGE == TPM_KEY_MIGRATE */ + +/* 6. TPM_TAG (Command and Response Tags) rev 100 + + These tags indicate to the TPM the construction of the command either as input or as output. The + AUTH indicates that there are one or more AuthData values that follow the command + parameters. +*/ + +#define TPM_TAG_RQU_COMMAND 0x00C1 /* A command with no authentication. */ +#define TPM_TAG_RQU_AUTH1_COMMAND 0x00C2 /* An authenticated command with one authentication + handle */ +#define TPM_TAG_RQU_AUTH2_COMMAND 0x00C3 /* An authenticated command with two authentication + handles */ +#define TPM_TAG_RSP_COMMAND 0x00C4 /* A response from a command with no authentication + */ +#define TPM_TAG_RSP_AUTH1_COMMAND 0x00C5 /* An authenticated response with one authentication + handle */ +#define TPM_TAG_RSP_AUTH2_COMMAND 0x00C6 /* An authenticated response with two authentication + handles */ + +/* TIS 7.2 PCR Attributes + +*/ + +#define TPM_DEBUG_PCR 16 +#define TPM_LOCALITY_4_PCR 17 +#define TPM_LOCALITY_3_PCR 18 +#define TPM_LOCALITY_2_PCR 19 +#define TPM_LOCALITY_1_PCR 20 + +/* 10.9 TPM_KEY_CONTROL rev 87 + + Attributes that can control various aspects of key usage and manipulation. + + Allows for controlling of the key when loaded and how to handle TPM_Startup issues. +*/ + +#define TPM_KEY_CONTROL_OWNER_EVICT 0x00000001 /* Owner controls when the key is evicted + from the TPM. When set the TPM MUST + preserve key the key across all TPM_Init + invocations. */ + +/* 13.1.1 TPM_TRANSPORT_ATTRIBUTES Definitions */ + +#define TPM_TRANSPORT_ENCRYPT 0x00000001 /* The session will provide encryption using + the internal encryption algorithm */ +#define TPM_TRANSPORT_LOG 0x00000002 /* The session will provide a log of all + operations that occur in the session */ +#define TPM_TRANSPORT_EXCLUSIVE 0X00000004 /* The transport session is exclusive and + any command executed outside the + transport session causes the invalidation + of the session */ + +/* 21.1 TPM_CAPABILITY_AREA rev 115 + + To identify a capability to be queried. +*/ + +#define TPM_CAP_ORD 0x00000001 /* Boolean value. TRUE indicates that the TPM supports + the ordinal. FALSE indicates that the TPM does not + support the ordinal. Unimplemented optional ordinals + and unused (unassigned) ordinals return FALSE. */ +#define TPM_CAP_ALG 0x00000002 /* Boolean value. TRUE means that the TPM supports the + asymmetric algorithm for TPM_Sign, TPM_Seal, + TPM_UnSeal and TPM_UnBind and related commands. FALSE + indicates that the asymmetric algorithm is not + supported for these types of commands. The TPM MAY + return TRUE or FALSE for other than asymmetric + algoroithms that it supports. Unassigned and + unsupported algorithm IDs return FALSE.*/ + +#define TPM_CAP_PID 0x00000003 /* Boolean value. TRUE indicates that the TPM supports + the protocol, FALSE indicates that the TPM does not + support the protocol. */ +#define TPM_CAP_FLAG 0x00000004 /* Return the TPM_PERMANENT_FLAGS structure or Return the + TPM_STCLEAR_FLAGS structure */ +#define TPM_CAP_PROPERTY 0x00000005 /* See following table for the subcaps */ +#define TPM_CAP_VERSION 0x00000006 /* TPM_STRUCT_VER structure. The Major and Minor must + indicate 1.1. The firmware revision MUST indicate + 0.0 */ +#define TPM_CAP_KEY_HANDLE 0x00000007 /* A TPM_KEY_HANDLE_LIST structure that enumerates all + key handles loaded on the TPM. */ +#define TPM_CAP_CHECK_LOADED 0x00000008 /* A Boolean value. TRUE indicates that the TPM has + enough memory available to load a key of the type + specified by TPM_KEY_PARMS. FALSE indicates that the + TPM does not have enough memory. */ +#define TPM_CAP_SYM_MODE 0x00000009 /* Subcap TPM_SYM_MODE + A Boolean value. TRUE indicates that the TPM supports + the TPM_SYM_MODE, FALSE indicates the TPM does not + support the mode. */ +#define TPM_CAP_KEY_STATUS 0x0000000C /* Boolean value of ownerEvict. The handle MUST point to + a valid key handle.*/ +#define TPM_CAP_NV_LIST 0x0000000D /* A list of TPM_NV_INDEX values that are currently + allocated NV storage through TPM_NV_DefineSpace. */ +#define TPM_CAP_MFR 0x00000010 /* Manufacturer specific. The manufacturer may provide + any additional information regarding the TPM and the + TPM state but MUST not expose any sensitive + information. */ +#define TPM_CAP_NV_INDEX 0x00000011 /* A TPM_NV_DATA_PUBLIC structure that indicates the + values for the TPM_NV_INDEX. Returns TPM_BADINDEX if + the index is not in the TPM_CAP_NV_LIST list. */ +#define TPM_CAP_TRANS_ALG 0x00000012 /* Boolean value. TRUE means that the TPM supports the + algorithm for TPM_EstablishTransport, + TPM_ExecuteTransport and + TPM_ReleaseTransportSigned. FALSE indicates that for + these three commands the algorithm is not supported." + */ +#define TPM_CAP_HANDLE 0x00000014 /* A TPM_KEY_HANDLE_LIST structure that enumerates all + handles currently loaded in the TPM for the given + resource type. */ +#define TPM_CAP_TRANS_ES 0x00000015 /* Boolean value. TRUE means the TPM supports the + encryption scheme in a transport session for at least + one algorithm.. */ +#define TPM_CAP_AUTH_ENCRYPT 0x00000017 /* Boolean value. TRUE indicates that the TPM supports + the encryption algorithm in OSAP encryption of + AuthData values */ +#define TPM_CAP_SELECT_SIZE 0x00000018 /* Boolean value. TRUE indicates that the TPM supports + the size for the given version. For instance a request + could ask for version 1.1 size 2 and the TPM would + indicate TRUE. For 1.1 size 3 the TPM would indicate + FALSE. For 1.2 size 3 the TPM would indicate TRUE. */ +#define TPM_CAP_DA_LOGIC 0x00000019 /* (OPTIONAL) + A TPM_DA_INFO or TPM_DA_INFO_LIMITED structure that + returns data according to the selected entity type + (e.g., TPM_ET_KEYHANDLE, TPM_ET_OWNER, TPM_ET_SRK, + TPM_ET_COUNTER, TPM_ET_OPERATOR, etc.). If the + implemented dictionary attack logic does not support + different secret types, the entity type can be + ignored. */ +#define TPM_CAP_VERSION_VAL 0x0000001A /* TPM_CAP_VERSION_INFO structure. The TPM fills in the + structure and returns the information indicating what + the TPM currently supports. */ + +#define TPM_CAP_FLAG_PERMANENT 0x00000108 /* Return the TPM_PERMANENT_FLAGS structure */ +#define TPM_CAP_FLAG_VOLATILE 0x00000109 /* Return the TPM_STCLEAR_FLAGS structure */ + +/* 21.2 CAP_PROPERTY Subcap values for CAP_PROPERTY rev 105 + + The TPM_CAP_PROPERTY capability has numerous subcap values. The definition for all subcap values + occurs in this table. + + TPM_CAP_PROP_MANUFACTURER returns a vendor ID unique to each manufacturer. The same value is + returned as the TPM_CAP_VERSION_INFO -> tpmVendorID. A company abbreviation such as a null + terminated stock ticker is a typical choice. However, there is no requirement that the value + contain printable characters. The document "TCG Vendor Naming" lists the vendor ID values. + + TPM_CAP_PROP_MAX_xxxSESS is a constant. At TPM_Startup(ST_CLEAR) TPM_CAP_PROP_xxxSESS == + TPM_CAP_PROP_MAX_xxxSESS. As sessions are created on the TPM, TPM_CAP_PROP_xxxSESS decreases + toward zero. As sessions are terminated, TPM_CAP_PROP_xxxSESS increases toward + TPM_CAP_PROP_MAX_xxxSESS. + + There is a similar relationship between the constants TPM_CAP_PROP_MAX_COUNTERS and + TPM_CAP_PROP_MAX_CONTEXT and the varying TPM_CAP_PROP_COUNTERS and TPM_CAP_PROP_CONTEXT. + + In one typical implementation where authorization and transport sessions reside in separate + pools, TPM_CAP_PROP_SESSIONS will be the sum of TPM_CAP_PROP_AUTHSESS and TPM_CAP_PROP_TRANSESS. + In another typical implementation where authorization and transport sessions share the same pool, + TPM_CAP_PROP_SESSIONS, TPM_CAP_PROP_AUTHSESS, and TPM_CAP_PROP_TRANSESS will all be equal. +*/ + +#define TPM_CAP_PROP_PCR 0x00000101 /* uint32_t value. Returns the number of PCR + registers supported by the TPM */ +#define TPM_CAP_PROP_DIR 0x00000102 /* uint32_t. Deprecated. Returns the number of + DIR, which is now fixed at 1 */ +#define TPM_CAP_PROP_MANUFACTURER 0x00000103 /* uint32_t value. Returns the vendor ID + unique to each TPM manufacturer. */ +#define TPM_CAP_PROP_KEYS 0x00000104 /* uint32_t value. Returns the number of 2048- + bit RSA keys that can be loaded. This may + vary with time and circumstances. */ +#define TPM_CAP_PROP_MIN_COUNTER 0x00000107 /* uint32_t. The minimum amount of time in + 10ths of a second that must pass between + invocations of incrementing the monotonic + counter. */ +#define TPM_CAP_PROP_AUTHSESS 0x0000010A /* uint32_t. The number of available + authorization sessions. This may vary with + time and circumstances. */ +#define TPM_CAP_PROP_TRANSESS 0x0000010B /* uint32_t. The number of available transport + sessions. This may vary with time and + circumstances. */ +#define TPM_CAP_PROP_COUNTERS 0x0000010C /* uint32_t. The number of available monotonic + counters. This may vary with time and + circumstances. */ +#define TPM_CAP_PROP_MAX_AUTHSESS 0x0000010D /* uint32_t. The maximum number of loaded + authorization sessions the TPM supports */ +#define TPM_CAP_PROP_MAX_TRANSESS 0x0000010E /* uint32_t. The maximum number of loaded + transport sessions the TPM supports. */ +#define TPM_CAP_PROP_MAX_COUNTERS 0x0000010F /* uint32_t. The maximum number of monotonic + counters under control of TPM_CreateCounter + */ +#define TPM_CAP_PROP_MAX_KEYS 0x00000110 /* uint32_t. The maximum number of 2048 RSA + keys that the TPM can support. The number + does not include the EK or SRK. */ +#define TPM_CAP_PROP_OWNER 0x00000111 /* BOOL. A value of TRUE indicates that the + TPM has successfully installed an owner. */ +#define TPM_CAP_PROP_CONTEXT 0x00000112 /* uint32_t. The number of available saved + session slots. This may vary with time and + circumstances. */ +#define TPM_CAP_PROP_MAX_CONTEXT 0x00000113 /* uint32_t. The maximum number of saved + session slots. */ +#define TPM_CAP_PROP_FAMILYROWS 0x00000114 /* uint32_t. The maximum number of rows in the + family table */ +#define TPM_CAP_PROP_TIS_TIMEOUT 0x00000115 /* A 4 element array of uint32_t values each + denoting the timeout value in microseconds + for the following in this order: + + TIMEOUT_A, TIMEOUT_B, TIMEOUT_C, TIMEOUT_D + + Where these timeouts are to be used is + determined by the platform specific TPM + Interface Specification. */ +#define TPM_CAP_PROP_STARTUP_EFFECT 0x00000116 /* The TPM_STARTUP_EFFECTS structure */ +#define TPM_CAP_PROP_DELEGATE_ROW 0x00000117 /* uint32_t. The maximum size of the delegate + table in rows. */ +#define TPM_CAP_PROP_MAX_DAASESS 0x00000119 /* uint32_t. The maximum number of loaded DAA + sessions (join or sign) that the TPM + supports */ +#define TPM_CAP_PROP_DAASESS 0x0000011A /* uint32_t. The number of available DAA + sessions. This may vary with time and + circumstances */ +#define TPM_CAP_PROP_CONTEXT_DIST 0x0000011B /* uint32_t. The maximum distance between + context count values. This MUST be at least + 2^16-1. */ +#define TPM_CAP_PROP_DAA_INTERRUPT 0x0000011C /* BOOL. 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 */ +#define TPM_CAP_PROP_SESSIONS 0X0000011D /* uint32_t. The number of available sessions + from the pool. This MAY vary with time and + circumstances. Pool sessions include + authorization and transport sessions. */ +#define TPM_CAP_PROP_MAX_SESSIONS 0x0000011E /* uint32_t. The maximum number of sessions + the TPM supports. */ +#define TPM_CAP_PROP_CMK_RESTRICTION 0x0000011F /* uint32_t TPM_Permanent_Data -> + restrictDelegate + */ +#define TPM_CAP_PROP_DURATION 0x00000120 /* A 3 element array of uint32_t values each + denoting the duration value in microseconds + of the duration of the three classes of + commands: Small, Medium and Long in the + following in this order: SMALL_DURATION, + MEDIUM_DURATION, LONG_DURATION */ +#define TPM_CAP_PROP_ACTIVE_COUNTER 0x00000122 /* TPM_COUNT_ID. The id of the current + counter. 0xff..ff if no counter is active + */ +#define TPM_CAP_PROP_MAX_NV_AVAILABLE 0x00000123 /*uint32_t. Deprecated. The maximum number + of NV space that can be allocated, MAY + vary with time and circumstances. This + capability was not implemented + consistently, and is replaced by + TPM_NV_INDEX_TRIAL. */ +#define TPM_CAP_PROP_INPUT_BUFFER 0x00000124 /* uint32_t. The maximum size of the TPM + input buffer or output buffer in + bytes. */ + +/* 21.4 Set_Capability Values rev 107 + */ + +#define TPM_SET_PERM_FLAGS 0x00000001 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_PERM_DATA 0x00000002 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_STCLEAR_FLAGS 0x00000003 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_STCLEAR_DATA 0x00000004 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_STANY_FLAGS 0x00000005 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_STANY_DATA 0x00000006 /* The ability to set a value is field specific and + a review of the structure will disclose the + ability and requirements to set a value */ +#define TPM_SET_VENDOR 0x00000007 /* This area allows the vendor to set specific areas + in the TPM according to the normal shielded + location requirements */ + +/* Set Capability sub caps */ + +/* TPM_PERMANENT_FLAGS */ + +#define TPM_PF_DISABLE 1 +#define TPM_PF_OWNERSHIP 2 +#define TPM_PF_DEACTIVATED 3 +#define TPM_PF_READPUBEK 4 +#define TPM_PF_DISABLEOWNERCLEAR 5 +#define TPM_PF_ALLOWMAINTENANCE 6 +#define TPM_PF_PHYSICALPRESENCELIFETIMELOCK 7 +#define TPM_PF_PHYSICALPRESENCEHWENABLE 8 +#define TPM_PF_PHYSICALPRESENCECMDENABLE 9 +#define TPM_PF_CEKPUSED 10 +#define TPM_PF_TPMPOST 11 +#define TPM_PF_TPMPOSTLOCK 12 +#define TPM_PF_FIPS 13 +#define TPM_PF_OPERATOR 14 +#define TPM_PF_ENABLEREVOKEEK 15 +#define TPM_PF_NV_LOCKED 16 +#define TPM_PF_READSRKPUB 17 +#define TPM_PF_TPMESTABLISHED 18 +#define TPM_PF_MAINTENANCEDONE 19 +#define TPM_PF_DISABLEFULLDALOGICINFO 20 + +/* TPM_STCLEAR_FLAGS */ + +#define TPM_SF_DEACTIVATED 1 +#define TPM_SF_DISABLEFORCECLEAR 2 +#define TPM_SF_PHYSICALPRESENCE 3 +#define TPM_SF_PHYSICALPRESENCELOCK 4 +#define TPM_SF_BGLOBALLOCK 5 + +/* TPM_STANY_FLAGS */ + +#define TPM_AF_POSTINITIALISE 1 +#define TPM_AF_LOCALITYMODIFIER 2 +#define TPM_AF_TRANSPORTEXCLUSIVE 3 +#define TPM_AF_TOSPRESENT 4 + +/* TPM_PERMANENT_DATA */ + +#define TPM_PD_REVMAJOR 1 +#define TPM_PD_REVMINOR 2 +#define TPM_PD_TPMPROOF 3 +#define TPM_PD_OWNERAUTH 4 +#define TPM_PD_OPERATORAUTH 5 +#define TPM_PD_MANUMAINTPUB 6 +#define TPM_PD_ENDORSEMENTKEY 7 +#define TPM_PD_SRK 8 +#define TPM_PD_DELEGATEKEY 9 +#define TPM_PD_CONTEXTKEY 10 +#define TPM_PD_AUDITMONOTONICCOUNTER 11 +#define TPM_PD_MONOTONICCOUNTER 12 +#define TPM_PD_PCRATTRIB 13 +#define TPM_PD_ORDINALAUDITSTATUS 14 +#define TPM_PD_AUTHDIR 15 +#define TPM_PD_RNGSTATE 16 +#define TPM_PD_FAMILYTABLE 17 +#define TPM_DELEGATETABLE 18 +#define TPM_PD_EKRESET 19 +#define TPM_PD_LASTFAMILYID 21 +#define TPM_PD_NOOWNERNVWRITE 22 +#define TPM_PD_RESTRICTDELEGATE 23 +#define TPM_PD_TPMDAASEED 24 +#define TPM_PD_DAAPROOF 25 + +/* TPM_STCLEAR_DATA */ + +#define TPM_SD_CONTEXTNONCEKEY 1 +#define TPM_SD_COUNTID 2 +#define TPM_SD_OWNERREFERENCE 3 +#define TPM_SD_DISABLERESETLOCK 4 +#define TPM_SD_PCR 5 +#define TPM_SD_DEFERREDPHYSICALPRESENCE 6 + +/* TPM_STCLEAR_DATA -> deferredPhysicalPresence bits */ + +#define TPM_DPP_UNOWNED_FIELD_UPGRADE 0x00000001 /* bit 0 TPM_FieldUpgrade */ + +/* TPM_STANY_DATA */ + +#define TPM_AD_CONTEXTNONCESESSION 1 +#define TPM_AD_AUDITDIGEST 2 +#define TPM_AD_CURRENTTICKS 3 +#define TPM_AD_CONTEXTCOUNT 4 +#define TPM_AD_CONTEXTLIST 5 +#define TPM_AD_SESSIONS 6 + +/* 17. Ordinals rev 110 + + Ordinals are 32 bit values of type TPM_COMMAND_CODE. The upper byte contains values that serve + as flag indicators, the next byte contains values indicating what committee designated the + ordinal, and the final two bytes contain the Command Ordinal Index. + + 3 2 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |P|C|V| Reserved| Purview | Command Ordinal Index | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Where: + + P is Protected/Unprotected command. When 0 the command is a Protected command, when 1 the + command is an Unprotected command. + + C is Non-Connection/Connection related command. When 0 this command passes through to either the + protected (TPM) or unprotected (TSS) components. + + V is TPM/Vendor command. When 0 the command is TPM defined, when 1 the command is vendor + defined. + + All reserved area bits are set to 0. +*/ + +/* The following masks are created to allow for the quick definition of the commands */ + +#define TPM_PROTECTED_COMMAND 0x00000000 /* TPM protected command, specified in main specification + */ +#define TPM_UNPROTECTED_COMMAND 0x80000000 /* TSS command, specified in the TSS specification */ +#define TPM_CONNECTION_COMMAND 0x40000000 /* TSC command, protected connection commands are + specified in the main specification Unprotected + connection commands are specified in the TSS */ +#define TPM_VENDOR_COMMAND 0x20000000 /* Command that is vendor specific for a given TPM or + TSS. */ + + +/* The following Purviews have been defined: */ + +#define TPM_MAIN 0x00 /* Command is from the main specification */ +#define TPM_PC 0x01 /* Command is specific to the PC */ +#define TPM_PDA 0x02 /* Command is specific to a PDA */ +#define TPM_CELL_PHONE 0x03 /* Command is specific to a cell phone */ +#define TPM_SERVER 0x04 /* Command is specific to servers */ +#define TPM_PERIPHERAL 0x05 /* Command is specific to peripherals */ +#define TPM_TSS 0x06 /* Command is specific to TSS */ + +/* Combinations for the main specification would be: */ + +#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) + +/* Command ordinals */ + +#define TPM_ORD_ActivateIdentity 0x0000007A +#define TPM_ORD_AuthorizeMigrationKey 0x0000002B +#define TPM_ORD_CertifyKey 0x00000032 +#define TPM_ORD_CertifyKey2 0x00000033 +#define TPM_ORD_CertifySelfTest 0x00000052 +#define TPM_ORD_ChangeAuth 0x0000000C +#define TPM_ORD_ChangeAuthAsymFinish 0x0000000F +#define TPM_ORD_ChangeAuthAsymStart 0x0000000E +#define TPM_ORD_ChangeAuthOwner 0x00000010 +#define TPM_ORD_CMK_ApproveMA 0x0000001D +#define TPM_ORD_CMK_ConvertMigration 0x00000024 +#define TPM_ORD_CMK_CreateBlob 0x0000001B +#define TPM_ORD_CMK_CreateKey 0x00000013 +#define TPM_ORD_CMK_CreateTicket 0x00000012 +#define TPM_ORD_CMK_SetRestrictions 0x0000001C +#define TPM_ORD_ContinueSelfTest 0x00000053 +#define TPM_ORD_ConvertMigrationBlob 0x0000002A +#define TPM_ORD_CreateCounter 0x000000DC +#define TPM_ORD_CreateEndorsementKeyPair 0x00000078 +#define TPM_ORD_CreateMaintenanceArchive 0x0000002C +#define TPM_ORD_CreateMigrationBlob 0x00000028 +#define TPM_ORD_CreateRevocableEK 0x0000007F +#define TPM_ORD_CreateWrapKey 0x0000001F +#define TPM_ORD_DAA_Join 0x00000029 +#define TPM_ORD_DAA_Sign 0x00000031 +#define TPM_ORD_Delegate_CreateKeyDelegation 0x000000D4 +#define TPM_ORD_Delegate_CreateOwnerDelegation 0x000000D5 +#define TPM_ORD_Delegate_LoadOwnerDelegation 0x000000D8 +#define TPM_ORD_Delegate_Manage 0x000000D2 +#define TPM_ORD_Delegate_ReadTable 0x000000DB +#define TPM_ORD_Delegate_UpdateVerification 0x000000D1 +#define TPM_ORD_Delegate_VerifyDelegation 0x000000D6 +#define TPM_ORD_DirRead 0x0000001A +#define TPM_ORD_DirWriteAuth 0x00000019 +#define TPM_ORD_DisableForceClear 0x0000005E +#define TPM_ORD_DisableOwnerClear 0x0000005C +#define TPM_ORD_DisablePubekRead 0x0000007E +#define TPM_ORD_DSAP 0x00000011 +#define TPM_ORD_EstablishTransport 0x000000E6 +#define TPM_ORD_EvictKey 0x00000022 +#define TPM_ORD_ExecuteTransport 0x000000E7 +#define TPM_ORD_Extend 0x00000014 +#define TPM_ORD_FieldUpgrade 0x000000AA +#define TPM_ORD_FlushSpecific 0x000000BA +#define TPM_ORD_ForceClear 0x0000005D +#define TPM_ORD_GetAuditDigest 0x00000085 +#define TPM_ORD_GetAuditDigestSigned 0x00000086 +#define TPM_ORD_GetAuditEvent 0x00000082 +#define TPM_ORD_GetAuditEventSigned 0x00000083 +#define TPM_ORD_GetCapability 0x00000065 +#define TPM_ORD_GetCapabilityOwner 0x00000066 +#define TPM_ORD_GetCapabilitySigned 0x00000064 +#define TPM_ORD_GetOrdinalAuditStatus 0x0000008C +#define TPM_ORD_GetPubKey 0x00000021 +#define TPM_ORD_GetRandom 0x00000046 +#define TPM_ORD_GetTestResult 0x00000054 +#define TPM_ORD_GetTicks 0x000000F1 +#define TPM_ORD_IncrementCounter 0x000000DD +#define TPM_ORD_Init 0x00000097 +#define TPM_ORD_KeyControlOwner 0x00000023 +#define TPM_ORD_KillMaintenanceFeature 0x0000002E +#define TPM_ORD_LoadAuthContext 0x000000B7 +#define TPM_ORD_LoadContext 0x000000B9 +#define TPM_ORD_LoadKey 0x00000020 +#define TPM_ORD_LoadKey2 0x00000041 +#define TPM_ORD_LoadKeyContext 0x000000B5 +#define TPM_ORD_LoadMaintenanceArchive 0x0000002D +#define TPM_ORD_LoadManuMaintPub 0x0000002F +#define TPM_ORD_MakeIdentity 0x00000079 +#define TPM_ORD_MigrateKey 0x00000025 +#define TPM_ORD_NV_DefineSpace 0x000000CC +#define TPM_ORD_NV_ReadValue 0x000000CF +#define TPM_ORD_NV_ReadValueAuth 0x000000D0 +#define TPM_ORD_NV_WriteValue 0x000000CD +#define TPM_ORD_NV_WriteValueAuth 0x000000CE +#define TPM_ORD_OIAP 0x0000000A +#define TPM_ORD_OSAP 0x0000000B +#define TPM_ORD_OwnerClear 0x0000005B +#define TPM_ORD_OwnerReadInternalPub 0x00000081 +#define TPM_ORD_OwnerReadPubek 0x0000007D +#define TPM_ORD_OwnerSetDisable 0x0000006E +#define TPM_ORD_PCR_Reset 0x000000C8 +#define TPM_ORD_PcrRead 0x00000015 +#define TPM_ORD_PhysicalDisable 0x00000070 +#define TPM_ORD_PhysicalEnable 0x0000006F +#define TPM_ORD_PhysicalSetDeactivated 0x00000072 +#define TPM_ORD_Quote 0x00000016 +#define TPM_ORD_Quote2 0x0000003E +#define TPM_ORD_ReadCounter 0x000000DE +#define TPM_ORD_ReadManuMaintPub 0x00000030 +#define TPM_ORD_ReadPubek 0x0000007C +#define TPM_ORD_ReleaseCounter 0x000000DF +#define TPM_ORD_ReleaseCounterOwner 0x000000E0 +#define TPM_ORD_ReleaseTransportSigned 0x000000E8 +#define TPM_ORD_Reset 0x0000005A +#define TPM_ORD_ResetLockValue 0x00000040 +#define TPM_ORD_RevokeTrust 0x00000080 +#define TPM_ORD_SaveAuthContext 0x000000B6 +#define TPM_ORD_SaveContext 0x000000B8 +#define TPM_ORD_SaveKeyContext 0x000000B4 +#define TPM_ORD_SaveState 0x00000098 +#define TPM_ORD_Seal 0x00000017 +#define TPM_ORD_Sealx 0x0000003D +#define TPM_ORD_SelfTestFull 0x00000050 +#define TPM_ORD_SetCapability 0x0000003F +#define TPM_ORD_SetOperatorAuth 0x00000074 +#define TPM_ORD_SetOrdinalAuditStatus 0x0000008D +#define TPM_ORD_SetOwnerInstall 0x00000071 +#define TPM_ORD_SetOwnerPointer 0x00000075 +#define TPM_ORD_SetRedirection 0x0000009A +#define TPM_ORD_SetTempDeactivated 0x00000073 +#define TPM_ORD_SHA1Complete 0x000000A2 +#define TPM_ORD_SHA1CompleteExtend 0x000000A3 +#define TPM_ORD_SHA1Start 0x000000A0 +#define TPM_ORD_SHA1Update 0x000000A1 +#define TPM_ORD_Sign 0x0000003C +#define TPM_ORD_Startup 0x00000099 +#define TPM_ORD_StirRandom 0x00000047 +#define TPM_ORD_TakeOwnership 0x0000000D +#define TPM_ORD_Terminate_Handle 0x00000096 +#define TPM_ORD_TickStampBlob 0x000000F2 +#define TPM_ORD_UnBind 0x0000001E +#define TPM_ORD_Unseal 0x00000018 + +#define TSC_ORD_PhysicalPresence 0x4000000A +#define TSC_ORD_ResetEstablishmentBit 0x4000000B + +/* 19. NV storage structures */ + +/* 19.1 TPM_NV_INDEX rev 110 + + The index provides the handle to identify the area of storage. The reserved bits allow for a + segregation of the index name space to avoid name collisions. + + The TPM may check the resvd bits for zero. Thus, applications should set the bits to zero. + + The TCG defines the space where the high order bits (T, P, U) are 0. The other spaces are + controlled by the indicated entity. + + T is the TPM manufacturer reserved bit. 0 indicates a TCG defined value. 1 indicates a TPM + manufacturer specific value. + + P is the platform manufacturer reserved bit. 0 indicates a TCG defined value. 1 indicates that + the index is controlled by the platform manufacturer. + + U is for the platform user. 0 indicates a TCG defined value. 1 indicates that the index is + controlled by the platform user. + + The TPM_NV_INDEX is a 32-bit value. + 3 2 1 + 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |T|P|U|D| resvd | Purview | Index | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Where: + + 1. The TPM MAY return an error if the reserved area bits are not set to 0. + + 2. The TPM MUST accept all values for T, P, and U + + 3. D indicates defined. 1 indicates that the index is permanently defined and that any + TPM_NV_DefineSpace operation will fail after nvLocked is set TRUE. + + a. TCG reserved areas MAY have D set to 0 or 1 + + 4. Purview is the value used to indicate the platform specific area. This value is the + same as used for command ordinals. + + a. The TPM MUST reject purview values that the TPM cannot support. This means that an + index value for a PDA MUST be rejected by a TPM designed to work only on the PC Client. +*/ + +#define TPM_NV_INDEX_T_BIT 0x80000000 +#define TPM_NV_INDEX_P_BIT 0x40000000 +#define TPM_NV_INDEX_U_BIT 0x20000000 +#define TPM_NV_INDEX_D_BIT 0x10000000 +/* added kgold */ +#define TPM_NV_INDEX_RESVD 0x0f000000 +#define TPM_NV_INDEX_PURVIEW_BIT 16 +#define TPM_NV_INDEX_PURVIEW_MASK 0x00ff0000 + +/* 19.1.1 Required TPM_NV_INDEX values rev 97 + + The required index values must be found on each TPM regardless of platform. These areas are + always present and do not require a TPM_DefineSpace command to allocate. + + A platform specific specification may add additional required index values for the platform. + + The TPM MUST reserve the space as indicated for the required index values +*/ + +#define TPM_NV_INDEX_LOCK 0xFFFFFFFF /* This value turns on the NV authorization + protections. Once executed all NV areas use the + protections as defined. This value never resets. + + Attempting to execute TPM_NV_DefineSpace on this value + with non-zero size MAY result in a TPM_BADINDEX + response. + */ + +#define TPM_NV_INDEX0 0x00000000 /* This value allows for the setting of the bGlobalLock + flag, which is only reset on TPM_Startup(ST_Clear) + + Attempting to execute TPM_NV_WriteValue with a size other + than zero MAY result in the TPM_BADINDEX error code. + */ + +#define TPM_NV_INDEX_DIR 0x10000001 /* Size MUST be 20. This index points to the deprecated DIR + command area from 1.1. The TPM MUST map this reserved + space to be the area operated on by the 1.1 DIR commands. + */ + +/* 19.1.2 Reserved Index values rev 116 + + The reserved values are defined to avoid index collisions. These values are not in each and every + TPM. + + 1. The reserved index values are to avoid index value collisions. + 2. These index values require a TPM_DefineSpace to have the area for the index allocated + 3. A platform specific specification MAY indicate that reserved values are required. + 4. The reserved index values MAY have their D bit set by the TPM vendor to permanently +*/ + +#define TPM_NV_INDEX_TPM 0x0000Fxxx /* Reserved for TPM use */ +#define TPM_NV_INDEX_EKCert 0x0000F000 /* The Endorsement credential */ + +#define TPM_NV_INDEX_TPM_CC 0x0000F001 /* The TPM Conformance credential */ +#define TPM_NV_INDEX_PlatformCert 0x0000F002 /* The platform credential */ +#define TPM_NV_INDEX_Platform_CC 0x0000F003 /* The Platform conformance credential */ +#define TPM_NV_INDEX_TRIAL 0x0000F004 /* To try TPM_NV_DefineSpace without + actually allocating NV space */ + +#if 0 +#define TPM_NV_INDEX_PC 0x0001xxxx /* Reserved for PC Client use */ +#define TPM_NV_INDEX_GPIO_xx 0x000116xx /* Reserved for GPIO pins */ +#define TPM_NV_INDEX_PDA 0x0002xxxx /* Reserved for PDA use */ +#define TPM_NV_INDEX_MOBILE 0x0003xxxx /* Reserved for mobile use */ +#define TPM_NV_INDEX_SERVER 0x0004xxxx /* Reserved for Server use */ +#define TPM_NV_INDEX_PERIPHERAL 0x0005xxxx /* Reserved for peripheral use */ +#define TPM_NV_INDEX_TSS 0x0006xxxx /* Reserved for TSS use */ +#define TPM_NV_INDEX_GROUP_RESV 0x00xxxxxx /* Reserved for TCG WG use */ +#endif + +#define TPM_NV_INDEX_GPIO_00 0x00011600 /* GPIO-Express-00 */ + +#define TPM_NV_INDEX_GPIO_START 0x00011600 /* Reserved for GPIO pins */ +#define TPM_NV_INDEX_GPIO_END 0x000116ff /* Reserved for GPIO pins */ + +/* 19.2 TPM_NV_ATTRIBUTES rev 99 + + The attributes TPM_NV_PER_AUTHREAD and TPM_NV_PER_OWNERREAD cannot both be set to TRUE. + Similarly, the attributes TPM_NV_PER_AUTHWRITE and TPM_NV_PER_OWNERWRITE cannot both be set to + TRUE. +*/ + +#define TPM_NV_PER_READ_STCLEAR 0x80000000 /* 31: The value can be read until locked by a + read with a data size of 0. It can only be + unlocked by TPM_Startup(ST_Clear) or a + successful write. Lock held for each area in + bReadSTClear. */ +/* #define 30:19 Reserved */ +#define TPM_NV_PER_AUTHREAD 0x00040000 /* 18: The value requires authorization to read + */ +#define TPM_NV_PER_OWNERREAD 0x00020000 /* 17: The value requires TPM Owner authorization + to read. */ +#define TPM_NV_PER_PPREAD 0x00010000 /* 16: The value requires physical presence to + read */ +#define TPM_NV_PER_GLOBALLOCK 0x00008000 /* 15: The value is writable until a write to + index 0 is successful. The lock of this + attribute is reset by + TPM_Startup(ST_CLEAR). Lock held by SF -> + bGlobalLock */ +#define TPM_NV_PER_WRITE_STCLEAR 0x00004000 /* 14: The value is writable until a write to + the specified index with a datasize of 0 is + successful. The lock of this attribute is + reset by TPM_Startup(ST_CLEAR). Lock held for + each area in bWriteSTClear. */ +#define TPM_NV_PER_WRITEDEFINE 0x00002000 /* 13: Lock set by writing to the index with a + datasize of 0. Lock held for each area in + bWriteDefine. This is a persistent lock. */ +#define TPM_NV_PER_WRITEALL 0x00001000 /* 12: The value must be written in a single + operation */ +/* #define 11:3 Reserved for write additions */ +#define TPM_NV_PER_AUTHWRITE 0x00000004 /* 2: The value requires authorization to write + */ +#define TPM_NV_PER_OWNERWRITE 0x00000002 /* 1: The value requires TPM Owner authorization + to write */ +#define TPM_NV_PER_PPWRITE 0x00000001 /* 0: The value requires physical presence to + write */ + +/* 20.2.1 Owner Permission Settings rev 87 */ + +/* Per1 bits */ + +#define TPM_DELEGATE_PER1_MASK 0xffffffff /* mask of legal bits */ +#define TPM_DELEGATE_KeyControlOwner 31 +#define TPM_DELEGATE_SetOrdinalAuditStatus 30 +#define TPM_DELEGATE_DirWriteAuth 29 +#define TPM_DELEGATE_CMK_ApproveMA 28 +#define TPM_DELEGATE_NV_WriteValue 27 +#define TPM_DELEGATE_CMK_CreateTicket 26 +#define TPM_DELEGATE_NV_ReadValue 25 +#define TPM_DELEGATE_Delegate_LoadOwnerDelegation 24 +#define TPM_DELEGATE_DAA_Join 23 +#define TPM_DELEGATE_AuthorizeMigrationKey 22 +#define TPM_DELEGATE_CreateMaintenanceArchive 21 +#define TPM_DELEGATE_LoadMaintenanceArchive 20 +#define TPM_DELEGATE_KillMaintenanceFeature 19 +#define TPM_DELEGATE_OwnerReadInternalPub 18 +#define TPM_DELEGATE_ResetLockValue 17 +#define TPM_DELEGATE_OwnerClear 16 +#define TPM_DELEGATE_DisableOwnerClear 15 +#define TPM_DELEGATE_NV_DefineSpace 14 +#define TPM_DELEGATE_OwnerSetDisable 13 +#define TPM_DELEGATE_SetCapability 12 +#define TPM_DELEGATE_MakeIdentity 11 +#define TPM_DELEGATE_ActivateIdentity 10 +#define TPM_DELEGATE_OwnerReadPubek 9 +#define TPM_DELEGATE_DisablePubekRead 8 +#define TPM_DELEGATE_SetRedirection 7 +#define TPM_DELEGATE_FieldUpgrade 6 +#define TPM_DELEGATE_Delegate_UpdateVerification 5 +#define TPM_DELEGATE_CreateCounter 4 +#define TPM_DELEGATE_ReleaseCounterOwner 3 +#define TPM_DELEGATE_Delegate_Manage 2 +#define TPM_DELEGATE_Delegate_CreateOwnerDelegation 1 +#define TPM_DELEGATE_DAA_Sign 0 + +/* Per2 bits */ +#define TPM_DELEGATE_PER2_MASK 0x00000000 /* mask of legal bits */ +/* All reserved */ + +/* 20.2.3 Key Permission settings rev 85 */ + +/* Per1 bits */ + +#define TPM_KEY_DELEGATE_PER1_MASK 0x1fffffff /* mask of legal bits */ +#define TPM_KEY_DELEGATE_CMK_ConvertMigration 28 +#define TPM_KEY_DELEGATE_TickStampBlob 27 +#define TPM_KEY_DELEGATE_ChangeAuthAsymStart 26 +#define TPM_KEY_DELEGATE_ChangeAuthAsymFinish 25 +#define TPM_KEY_DELEGATE_CMK_CreateKey 24 +#define TPM_KEY_DELEGATE_MigrateKey 23 +#define TPM_KEY_DELEGATE_LoadKey2 22 +#define TPM_KEY_DELEGATE_EstablishTransport 21 +#define TPM_KEY_DELEGATE_ReleaseTransportSigned 20 +#define TPM_KEY_DELEGATE_Quote2 19 +#define TPM_KEY_DELEGATE_Sealx 18 +#define TPM_KEY_DELEGATE_MakeIdentity 17 +#define TPM_KEY_DELEGATE_ActivateIdentity 16 +#define TPM_KEY_DELEGATE_GetAuditDigestSigned 15 +#define TPM_KEY_DELEGATE_Sign 14 +#define TPM_KEY_DELEGATE_CertifyKey2 13 +#define TPM_KEY_DELEGATE_CertifyKey 12 +#define TPM_KEY_DELEGATE_CreateWrapKey 11 +#define TPM_KEY_DELEGATE_CMK_CreateBlob 10 +#define TPM_KEY_DELEGATE_CreateMigrationBlob 9 +#define TPM_KEY_DELEGATE_ConvertMigrationBlob 8 +#define TPM_KEY_DELEGATE_Delegate_CreateKeyDelegation 7 +#define TPM_KEY_DELEGATE_ChangeAuth 6 +#define TPM_KEY_DELEGATE_GetPubKey 5 +#define TPM_KEY_DELEGATE_UnBind 4 +#define TPM_KEY_DELEGATE_Quote 3 +#define TPM_KEY_DELEGATE_Unseal 2 +#define TPM_KEY_DELEGATE_Seal 1 +#define TPM_KEY_DELEGATE_LoadKey 0 + +/* Per2 bits */ +#define TPM_KEY_DELEGATE_PER2_MASK 0x00000000 /* mask of legal bits */ +/* All reserved */ + +/* 20.3 TPM_FAMILY_FLAGS rev 87 + + These flags indicate the operational state of the delegation and family table. These flags + are additions to TPM_PERMANENT_FLAGS and are not stand alone values. +*/ + +#define TPM_DELEGATE_ADMIN_LOCK 0x00000002 /* TRUE: Some TPM_Delegate_XXX commands are locked and + return TPM_DELEGATE_LOCK + + FALSE: TPM_Delegate_XXX commands are available + + Default is FALSE */ +#define TPM_FAMFLAG_ENABLED 0x00000001 /* When TRUE the table is enabled. The default value is + FALSE. */ + +/* 20.14 TPM_FAMILY_OPERATION Values rev 87 + + These are the opFlag values used by TPM_Delegate_Manage. +*/ + +#define TPM_FAMILY_CREATE 0x00000001 /* Create a new family */ +#define TPM_FAMILY_ENABLE 0x00000002 /* Set or reset the enable flag for this family. */ +#define TPM_FAMILY_ADMIN 0x00000003 /* Prevent administration of this family. */ +#define TPM_FAMILY_INVALIDATE 0x00000004 /* Invalidate a specific family row. */ + +/* 21.9 TPM_DA_STATE rev 100 + + TPM_DA_STATE enumerates the possible states of the dictionary attack mitigation logic. +*/ + +#define TPM_DA_STATE_INACTIVE 0x00 /* The dictionary attack mitigation logic is currently + inactive */ +#define TPM_DA_STATE_ACTIVE 0x01 /* The dictionary attack mitigation logic is + active. TPM_DA_ACTION_TYPE (21.10) is in progress. */ + +/* 21.10 TPM_DA_ACTION_TYPE rev 100 + */ + +/* 31-4 Reserved No information and MUST be FALSE */ + +#define TPM_DA_ACTION_FAILURE_MODE 0x00000008 /* bit 3: The TPM is in failure mode. */ +#define TPM_DA_ACTION_DEACTIVATE 0x00000004 /* bit 2: The TPM is in the deactivated state. */ +#define TPM_DA_ACTION_DISABLE 0x00000002 /* bit 1: The TPM is in the disabled state. */ +#define TPM_DA_ACTION_TIMEOUT 0x00000001 /* bit 0: The TPM will be in a locked state for + TPM_DA_INFO -> actionDependValue seconds. This + value is dynamic, depending on the time the + lock has been active. */ + +/* 22. DAA Structures rev 91 + + All byte and bit areas are byte arrays treated as large integers +*/ + +#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 + +/* check that DAA_SIZE_issuerModulus will fit in DAA_scratch */ +#if (DAA_SIZE_issuerModulus != 256) +#error "DAA_SIZE_issuerModulus must be 256" +#endif + +/* 22.2 Constant definitions rev 91 */ + +#define DAA_power0 104 +#define DAA_power1 1024 + +#endif diff --git a/src/tpm_counter.c b/src/tpm_counter.c new file mode 100644 index 00000000..18a1f71a --- /dev/null +++ b/src/tpm_counter.c @@ -0,0 +1,1565 @@ +/********************************************************************************/ +/* */ +/* Counter Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_counter.c 4539 2011-04-04 21:44:22Z kgoldman $ */ +/* */ +//* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_secret.h" + +#include "tpm_counter.h" + +/* + Monotonic Counter Resource Handling +*/ + +/* TPM_Counters_Init() initializes the monotonic counters + */ + +void TPM_Counters_Init(TPM_COUNTER_VALUE *monotonicCounters) +{ + uint32_t i; + + for (i = 0 ; i < TPM_MIN_COUNTERS ; i++) { + TPM_CounterValue_Init(&(monotonicCounters[i])); + } + return; +} + +/* TPM_Counters_Load() loads the monotonic counters + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_Counters_Load(TPM_COUNTER_VALUE *monotonicCounters, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t i; + + /* load the counters */ + for (i = 0 ; (rc == 0) && (i < TPM_MIN_COUNTERS) ; i++) { + rc = TPM_CounterValue_Load(&(monotonicCounters[i]), stream, stream_size); + } + return rc; +} + +TPM_RESULT TPM_Counters_Store(TPM_STORE_BUFFER *sbuffer, + TPM_COUNTER_VALUE *monotonicCounters) +{ + TPM_RESULT rc = 0; + uint32_t i; + + /* store the counters */ + for (i = 0 ; (rc == 0) && (i < TPM_MIN_COUNTERS) ; i++) { + rc = TPM_CounterValue_Store(sbuffer, &(monotonicCounters[i])); + } + return rc; +} + +/* TPM_Counters_StoreHandles() stores a count of the created counters and a list of created counter + handles. +*/ + +TPM_RESULT TPM_Counters_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_COUNTER_VALUE *monotonicCounters) +{ + TPM_RESULT rc = 0; + uint16_t loaded; + uint32_t i; + + printf(" TPM_Counters_StoreHandles:\n"); + if (rc == 0) { + loaded = 0; + /* count the number of loaded counters */ + for (i = 0 ; i < TPM_MIN_COUNTERS ; i++) { + if ((monotonicCounters[i]).valid) { + loaded++; + } + } + /* store created handle count */ + rc = TPM_Sbuffer_Append16(sbuffer, loaded); + } + for (i = 0 ; (rc == 0) && (i < TPM_MIN_COUNTERS) ; i++) { + if ((monotonicCounters[i]).valid) { + /* the handle is just the index */ + rc = TPM_Sbuffer_Append32(sbuffer, i); /* store it */ + } + } + return rc; +} + +/* TPM_Counters_GetSpace() returns the number of unused monotonicCounters. + */ + +void TPM_Counters_GetSpace(uint32_t *space, + TPM_COUNTER_VALUE *monotonicCounters) +{ + uint32_t i; + + printf(" TPM_Counters_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_MIN_COUNTERS ; i++) { + if (!(monotonicCounters[i]).valid) { + (*space)++; + } + } + return; +} + + +/* TPM_Counters_GetNewHandle() checks for space in the monotonicCounters table. + + If there is space, it returns a TPM_COUNTER_VALUE entry in 'tpm_counter_value' and its + handle in 'countID'. The entry is marked 'valid'. + + Returns TPM_RESOURCES if there is no space in the sessions table. monotonicCounters is not + altered on error. +*/ + +TPM_RESULT TPM_Counters_GetNewHandle(TPM_COUNTER_VALUE **tpm_counter_value, + TPM_COUNT_ID *countID, + TPM_COUNTER_VALUE *monotonicCounters) +{ + TPM_RESULT rc = 0; + TPM_BOOL is_space; + + printf(" TPM_Counters_GetNewHandle:\n"); + for (*countID = 0, is_space = FALSE ; + *countID < TPM_MIN_COUNTERS ; + (*countID)++) { + + if (!(monotonicCounters[*countID]).valid) { + is_space = TRUE; + break; + } + } + /* NOTE: According to TPMWG email, TPM_COUNT_ID can be an index */ + if (is_space) { + printf(" TPM_Counters_GetNewHandle: Assigned handle %u\n", *countID); + *tpm_counter_value = &(monotonicCounters[*countID]); + (*tpm_counter_value)->valid = TRUE; /* mark it occupied */ + } + else { + printf("TPM_Counters_GetNewHandle: Error, no space in monotonicCounters table\n"); + rc = TPM_RESOURCES; + } + return rc; +} + +/* TPM_Counters_GetNextCount() searches the monotonicCounters for the maximum count, and returns + nextCount equal to the incremented maximum count. + + The counter does not have to be valid (created). It can be invalid (released). +*/ + +void TPM_Counters_GetNextCount(TPM_ACTUAL_COUNT *nextCount, + TPM_COUNTER_VALUE *monotonicCounters) +{ + TPM_COUNT_ID countID; + TPM_ACTUAL_COUNT maxCount = 0; + + printf(" TPM_Counters_GetNextCount:\n"); + for (countID = 0 ; countID < TPM_MIN_COUNTERS ; countID++) { + if (monotonicCounters[countID].counter > maxCount) { + maxCount = monotonicCounters[countID].counter; + } + } + *nextCount = maxCount + 1; + printf(" TPM_Counters_GetNextCount: Next count %u\n", *nextCount); + return; +} + +/* TPM_Counters_IsValidId() verifies that countID is in range and a created counter + */ + +TPM_RESULT TPM_Counters_IsValidId(TPM_COUNTER_VALUE *monotonicCounters, + TPM_COUNT_ID countID) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Counters_IsValidId: countID %u\n", countID); + /* range check */ + if (rc == 0) { + if (countID >= TPM_MIN_COUNTERS) { + printf("TPM_Counters_IsValidId: Error countID %u out of range\n", countID); + rc = TPM_BAD_COUNTER ; + } + } + /* validity (creation) check */ + if (rc == 0) { + if (!(monotonicCounters[countID].valid)) { + printf("TPM_Counters_IsValidId: Error countID %u invalid\n", countID); + rc = TPM_BAD_COUNTER ; + } + } + return rc; +} + + +/* TPM_Counters_GetCounterValue() gets the TPM_COUNTER_VALUE associated with the countID. + + */ + +TPM_RESULT TPM_Counters_GetCounterValue(TPM_COUNTER_VALUE **tpm_counter_value, + TPM_COUNTER_VALUE *monotonicCounters, + TPM_COUNT_ID countID) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Counters_GetCounterValue: countID %u\n", countID); + /* valid counter check */ + if (rc == 0) { + rc = TPM_Counters_IsValidId(monotonicCounters, countID); + } + if (rc == 0) { + *tpm_counter_value = &(monotonicCounters[countID]); + } + return rc; +} + +/* TPM_Counters_Release() iterates through all monotonicCounter's, and releases those that are + created. + + The resource is set invalid, and the authorization data and digest are cleared. + + a. This includes invalidating all currently allocated counters. The result will be no + currently allocated counters and the new owner will need to allocate counters. The actual + count value will continue to increase. +*/ + +TPM_RESULT TPM_Counters_Release(TPM_COUNTER_VALUE *monotonicCounters) +{ + TPM_RESULT rc = 0; + TPM_COUNT_ID i; + + printf(" TPM_Counters_Release:\n"); + for (i = 0 ; i < TPM_MIN_COUNTERS ; i++) { + if (monotonicCounters[i].valid) { + /* the actual count value does not reset to zero */ + printf(" TPM_Counters_Release: Releasing %u\n", i); + TPM_Secret_Init(monotonicCounters[i].authData); + TPM_Digest_Init(monotonicCounters[i].digest); + monotonicCounters[i].valid = FALSE; + } + } + return rc; +} + +/* TPM_Counters_GetActiveCounter() gets the active counter based on the value in TPM_STCLEAR_DATA -> + countID */ + +void TPM_Counters_GetActiveCounter(TPM_COUNT_ID *activeCounter, + TPM_COUNT_ID countID) +{ + if (countID < TPM_MIN_COUNTERS) { + *activeCounter = countID; + } + else { + *activeCounter = TPM_COUNT_ID_NULL; + } +} + +/* + TPM_COUNTER_VALUE +*/ + +/* TPM_CounterValue_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CounterValue_Init(TPM_COUNTER_VALUE *tpm_counter_value) +{ + printf(" TPM_CounterValue_Init:\n"); + memset(tpm_counter_value->label, 0, TPM_COUNTER_LABEL_SIZE); + tpm_counter_value->counter = 0; + TPM_Secret_Init(tpm_counter_value->authData); + tpm_counter_value->valid = FALSE; + return; +} + +/* TPM_CounterValue_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_CounterValue_Load(TPM_COUNTER_VALUE *tpm_counter_value, /* result */ + unsigned char **stream, /* pointer to next + parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_CounterValue_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_COUNTER_VALUE, stream, stream_size); + } + /* load label */ + if (rc == 0) { + rc = TPM_Loadn(tpm_counter_value->label, TPM_COUNTER_LABEL_SIZE, stream, stream_size); + } + /* load counter */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_counter_value->counter), stream, stream_size); + } + /* load authData */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_counter_value->authData, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_counter_value->valid), stream, stream_size); + } + return rc; +} + +/* TPM_CounterValue_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + It is typically used to store the structure in the permanent data file. +*/ + +TPM_RESULT TPM_CounterValue_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_COUNTER_VALUE *tpm_counter_value) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CounterValue_Store:\n"); + /* store tag, label, counter */ + if (rc == 0) { + rc = TPM_CounterValue_StorePublic(sbuffer, tpm_counter_value); + } + /* store authData */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_counter_value->authData); + } + /* store valid */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_counter_value->valid), sizeof(TPM_BOOL)); + } + return rc; +} + +/* TPM_CounterValue_StorePublic() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + This version only stores the public, externally visible fields: tag, label, counter. It is + typically used to return outgoing parameters. +*/ + +TPM_RESULT TPM_CounterValue_StorePublic(TPM_STORE_BUFFER *sbuffer, + const TPM_COUNTER_VALUE *tpm_counter_value) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CounterValue_StorePublic:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_COUNTER_VALUE); + } + /* store label */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_counter_value->label, TPM_COUNTER_LABEL_SIZE); + } + /* store counter */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_counter_value->counter); + } + return rc; +} + +/* TPM_CounterValue_CopyPublic() copies the public, externally visible fields: tag, label, counter. + */ + +void TPM_CounterValue_CopyPublic(TPM_COUNTER_VALUE *dst_tpm_counter_value, + TPM_COUNTER_VALUE *src_tpm_counter_value) +{ + memcpy(dst_tpm_counter_value->label, src_tpm_counter_value->label, TPM_COUNTER_LABEL_SIZE); + dst_tpm_counter_value->counter = src_tpm_counter_value->counter; + return; +} + +/* TPM_CounterValue_Set() + + Sets the label, counter, and authData members from input parameters, and sets the digest from + members. +*/ + +TPM_RESULT TPM_CounterValue_Set(TPM_COUNTER_VALUE *tpm_counter_value, + TPM_COUNT_ID countID, + BYTE *label, + TPM_ACTUAL_COUNT counter, + TPM_SECRET authData) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CounterValue_Set:\n"); + tpm_counter_value->counter = counter; + memcpy(tpm_counter_value->label, label, TPM_COUNTER_LABEL_SIZE); + TPM_Secret_Copy(tpm_counter_value->authData, authData); + /* create a hopefully unique digest of the object for the OSAP setup. The cast is OK here since + the actual value of the digest is never verified. */ + rc = TPM_SHA1(tpm_counter_value->digest, + sizeof(TPM_COUNT_ID), (unsigned char *)&countID, + TPM_COUNTER_LABEL_SIZE, label, + TPM_SECRET_SIZE, authData, + 0, NULL); + return rc; + +} + +/* TPM_CounterValue_Release() releases a counter. + + The resource is set invalid, and the authorization data and digest are cleared. +*/ + +TPM_RESULT TPM_CounterValue_Release(TPM_COUNTER_VALUE *tpm_counter_value, + TPM_COUNT_ID countID) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CounterValue_Release: countID %u\n", countID); + /* sanity check */ + if (rc == 0) { + if (!tpm_counter_value->valid) { + printf("TPM_CounterValue_Release: Error (fatal), countID %u not valid\n", countID); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + TPM_Secret_Init(tpm_counter_value->authData); + TPM_Digest_Init(tpm_counter_value->digest); + tpm_counter_value->valid = FALSE; + } + return rc; +} + +/* + Processing Functions +*/ + +/* 25.1 TPM_CreateCounter rev 98 + + This command creates the counter but does not select the counter. Counter creation assigns an + AuthData value to the counter and sets the counters original start value. The original start value + is the current internal base value plus one. Setting the new counter to the internal base avoids + attacks on the system that are attempting to use old counter values. + + This command creates a new monotonic counter. The TPM MUST support a minimum of 4 concurrent + counters. +*/ + +TPM_RESULT TPM_Process_CreateCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_ENCAUTH encAuth; /* The encrypted auth data for the new counter */ + BYTE label[TPM_COUNTER_LABEL_SIZE]; /* Label to associate with counter */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA ownerAuth; /* Authorization ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey = NULL; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET a1Auth; + TPM_ACTUAL_COUNT nextCount; + TPM_BOOL writeAllNV= FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_COUNT_ID countID = 0; /* The handle for the counter */ + TPM_COUNTER_VALUE *counterValue = NULL; /* The starting counter value */ + + printf("TPM_Process_CreateCounter: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get authData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(encAuth, &command, ¶mSize); + } + /* get label */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Loadn(label, TPM_COUNTER_LABEL_SIZE, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateCounter: label", label); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateCounter: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Using the authHandle field, validate the owner's AuthData to execute the command and all + of the incoming parameters. The authorization session MUST be OSAP or DSAP. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_OWNER, + ordinal, + NULL, + NULL, + tpm_state->tpm_permanent_data.ownerAuth); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Ignore continueAuthSession on input and set continueAuthSession to FALSE on output */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 3. Create a1 by decrypting encAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + encAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 4. Validate that there is sufficient internal space in the TPM to create a new counter. If + there is insufficient space the command returns an error. */ + /* a. The TPM MUST provide storage for a1, TPM_COUNTER_VALUE, countID, and any other internal + data the TPM needs to associate with the counter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Counters_GetNewHandle(&counterValue, /* structure */ + &countID, /* index */ + tpm_state->tpm_permanent_data.monotonicCounter); + } + if (returnCode == TPM_SUCCESS) { + writeAllNV = TRUE; + /* 5. Increment the max counter value */ + TPM_Counters_GetNextCount(&nextCount, + tpm_state->tpm_permanent_data.monotonicCounter); + /* 6. Set the counter to the max counter value */ + /* 7. Set the counter label to label */ + returnCode = TPM_CounterValue_Set(counterValue, + countID, + label, + nextCount, + a1Auth); + /* 8. Create a countID */ + /* NOTE Done in TPM_Counters_GetNewHandle() */ + } + /* save the permanent data structure in NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateCounter: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the countID */ + returnCode = TPM_Sbuffer_Append32(response, countID); + } + if (returnCode == TPM_SUCCESS) { + /* Return the TPM_COUNTER_VALUE publicly visible members */ + returnCode = TPM_CounterValue_StorePublic(response, counterValue); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 25.2 TPM_IncrementCounter rev 87 + + 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. + + The order for checking validation of the command parameters when no counter is active, keeps an + attacker from creating a denial-of-service attack. + + This function increments the counter by 1. + The TPM MAY implement increment throttling to avoid burn problems +*/ + +TPM_RESULT TPM_Process_IncrementCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_COUNT_ID countID; /* The handle of a valid counter */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for counter + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA counterAuth; /* The authorization session digest that authorizes the use + of countID. HMAC key: countID -> authData */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_COUNTER_VALUE *counterValue; /* The counter value */ + + printf("TPM_Process_IncrementCounter: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&countID, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_IncrementCounter: countID %u\n", countID); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + counterAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_IncrementCounter: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* The first check is that either there is no active counter and the countID has been created + or that the countID is the active counter */ + if (returnCode == TPM_SUCCESS) { + /* 1. If TPM_STCLEAR_DATA -> countID is NULL */ + if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_NULL) { + /* a. Validate that countID is a valid counter, return TPM_BAD_COUNTER on mismatch */ + returnCode = TPM_Counters_IsValidId(tpm_state->tpm_permanent_data.monotonicCounter, + countID); + } + /* 2. else (TPM_STCLEAR_DATA -> countID is not NULL */ + else { + /* a. If TPM_STCLEAR_DATA -> countID does not equal countID */ + if (tpm_state->tpm_stclear_data.countID != countID) { + if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_ILLEGAL) { + printf("TPM_Process_IncrementCounter: Error, counter has been released\n"); + } + else { + printf("TPM_Process_IncrementCounter: Error, %u is already active\n", + tpm_state->tpm_stclear_data.countID); + } + /* i. Return TPM_BAD_COUNTER */ + returnCode = TPM_BAD_COUNTER; + } + } + } + /* b. Validate the command parameters using counterAuth */ + /* Get the TPM_COUNTER_VALUE associated with the countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Counters_GetCounterValue(&counterValue, + tpm_state->tpm_permanent_data.monotonicCounter, + countID); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_COUNTER, + ordinal, + NULL, + &(counterValue->authData), /* OIAP */ + counterValue->digest); /* OSAP */ + } + /* Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + counterAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + /* 1. If TPM_STCLEAR_DATA -> countID is NULL */ + if (tpm_state->tpm_stclear_data.countID == TPM_COUNT_ID_NULL) { + /* c. Set TPM_STCLEAR_DATA -> countID to countID */ + tpm_state->tpm_stclear_data.countID = countID; + printf("TPM_Process_IncrementCounter: Setting %u as active counter\n", countID); + } + } + if (returnCode == TPM_SUCCESS) { + /* 3. Increments the counter by 1 */ + counterValue->counter++; /* in TPM_PERMANENT_DATA */ + /* save the permanent data structure in NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_IncrementCounter: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 4. Return new count value in count */ + returnCode = TPM_CounterValue_StorePublic(response, counterValue); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 25.3 TPM_ReadCounter rev 87 + + Reading the counter provides the caller with the current number in the sequence. + + This returns the current value for the counter indicated. The counter MAY be any valid counter. +*/ + +TPM_RESULT TPM_Process_ReadCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_COUNT_ID countID; /* ID value of the counter */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ReadCounter: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&countID, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReadCounter: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that countID points to a valid counter. Return TPM_BAD_COUNTER on error. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReadCounter: countID %u\n", countID); + returnCode = TPM_Counters_IsValidId(tpm_state->tpm_permanent_data.monotonicCounter, + countID); + } + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReadCounter: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 2. Return count (directly from TPM_PERMANENT_DATA) */ + returnCode = TPM_CounterValue_StorePublic + (response, &(tpm_state->tpm_permanent_data.monotonicCounter[countID])); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 25.4 TPM_ReleaseCounter rev 87 + + This command releases a counter such that no reads or increments of the indicated counter will + succeed. + + The TPM uses countID to locate a valid counter. +*/ + +TPM_RESULT TPM_Process_ReleaseCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_COUNT_ID countID; /* ID value of the counter */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for countID + authorization */ + TPM_NONCE nonceOdd; /* Nonce associated with countID */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA counterAuth; /* The authorization session digest that authorizes the use + of countID. HMAC key: countID -> authData */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_COUNTER_VALUE *counterValue; /* associated with countID */ + TPM_SECRET savedAuth; /* saved copy for response */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV*/ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ReleaseCounter: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&countID, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReleaseCounter: countID %u\n", countID); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + counterAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReleaseCounter: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Authenticate the command and the parameters using the AuthData pointed to by + countID. Return TPM_AUTHFAIL on error */ + /* Get the TPM_COUNTER_VALUE associated with the countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Counters_GetCounterValue(&counterValue, + tpm_state->tpm_permanent_data.monotonicCounter, + countID); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_COUNTER, + ordinal, + NULL, + &(counterValue->authData), /* OIAP */ + counterValue->digest); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + /* make a copy of the HMAC key for the response, since it gets invalidated */ + TPM_Secret_Copy(savedAuth, *hmacKey); + /* Validate the authorization to use the key pointed to by countID */ + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + counterAuth); /* Authorization digest for input */ + } + /* 3. The TPM invalidates sessions */ + /* a. MUST invalidate all OSAP sessions associated with the counter */ + /* b. MAY invalidate any other session */ + /* NOTE: Actions reversed because the sessions can't be found after the digest is initialized */ + if (returnCode == TPM_SUCCESS) { + TPM_AuthSessions_TerminateEntity(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions, + TPM_ET_COUNTER, /* TPM_ENTITY_TYPE */ + &(counterValue->digest)); /* entityDigest */ + } + /* 2. The TPM invalidates all internal information regarding the counter. This includes + releasing countID such that any subsequent attempts to use countID will fail. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReleaseCounter: Releasing counter %u\n", countID); + returnCode = TPM_CounterValue_Release(counterValue, countID); + } + if (returnCode == TPM_SUCCESS) { + writeAllNV= TRUE; + /* 4. If TPM_STCLEAR_DATA -> countID equals countID, */ + if (tpm_state->tpm_stclear_data.countID == countID ) { + printf("TPM_Process_ReleaseCounter: Deactivating counter %u\n", countID); + /* a. Set TPM_STCLEAR_DATA -> countID to an illegal value (not the NULL value) */ + tpm_state->tpm_stclear_data.countID = TPM_COUNT_ID_ILLEGAL; + } + } + /* save the permanent data structure in NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReleaseCounter: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + savedAuth, /* saved countID HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 25.5 TPM_ReleaseCounterOwner rev 101 + + This command releases a counter such that no reads or increments of the indicated counter will + succeed. + + This invalidates all information regarding a counter. +*/ + +TPM_RESULT TPM_Process_ReleaseCounterOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + TPM_COUNT_ID countID; /* ID value of the counter */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = FALSE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest that authorizes the + inputs. HMAC key: ownerAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = TRUE; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey = NULL; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_COUNTER_VALUE *counterValue; /* associated with countID */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ReleaseCounterOwner: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&countID, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReleaseCounterOwner: countID %u\n", countID); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReleaseCounterOwner: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate that ownerAuth properly authorizes the command and parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. The TPM uses countID to locate a valid counter. Return TPM_BAD_COUNTER if not found. */ + /* Get the TPM_COUNTER_VALUE associated with the countID */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Counters_GetCounterValue(&counterValue, + tpm_state->tpm_permanent_data.monotonicCounter, + countID); + } + /* NOTE: Actions reversed because the sessions can't be found after the digest is initialized */ + if (returnCode == TPM_SUCCESS) { + TPM_AuthSessions_TerminateEntity(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions, + TPM_ET_COUNTER, /* TPM_ENTITY_TYPE */ + &(counterValue->digest)); /* entityDigest */ + } + /* 3. The TPM invalidates all internal information regarding the counter. This includes + releasing countID such that any subsequent attempts to use countID will fail. */ + /* NOTE: This function can only return a TPM_FAIL error, so that the failure to store + TPM_PERMANENT_DATA will already be reported as fatal. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CounterValue_Release(counterValue, countID); + } + /* 4. The TPM invalidates sessions */ + /* a. MUST invalidate all OSAP sessions associated with the counter */ + /* b. MAY invalidate any other session */ + if (returnCode == TPM_SUCCESS) { + writeAllNV = TRUE; + /* 5. If TPM_STCLEAR_DATA -> countID equals countID, */ + if (tpm_state->tpm_stclear_data.countID == countID ) { + printf("TPM_Process_ReleaseCounterOwner: Deactivating counter %u\n", countID); + /* a. Set TPM_STCLEAR_DATA -> countID to an illegal value (not the zero value) */ + tpm_state->tpm_stclear_data.countID = TPM_COUNT_ID_ILLEGAL; + } + } + /* save the permanent data structure in NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReleaseCounterOwner: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} diff --git a/src/tpm_counter.h b/src/tpm_counter.h new file mode 100644 index 00000000..18709d2b --- /dev/null +++ b/src/tpm_counter.h @@ -0,0 +1,140 @@ +/********************************************************************************/ +/* */ +/* Counter Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_counter.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_COUNTER_H +#define TPM_COUNTER_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_structures.h" + +/* + Counter Resource Handling +*/ + +void TPM_Counters_Init(TPM_COUNTER_VALUE *monotonicCounters); +TPM_RESULT TPM_Counters_Load(TPM_COUNTER_VALUE *monotonicCountersa, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Counters_Store(TPM_STORE_BUFFER *sbuffer, + TPM_COUNTER_VALUE *monotonicCounters); + +TPM_RESULT TPM_Counters_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_COUNTER_VALUE *monotonicCounters); +TPM_RESULT TPM_Counters_GetNewHandle(TPM_COUNTER_VALUE **tpm_counter_value, + TPM_COUNT_ID *countID, + TPM_COUNTER_VALUE *monotonicCounters); +void TPM_Counters_GetSpace(uint32_t *space, + TPM_COUNTER_VALUE *monotonicCounters); +void TPM_Counters_GetNextCount(TPM_ACTUAL_COUNT *nextCount, + TPM_COUNTER_VALUE *monotonicCounters); +TPM_RESULT TPM_Counters_IsValidId(TPM_COUNTER_VALUE *monotonicCounters, + TPM_COUNT_ID countID); +TPM_RESULT TPM_Counters_GetCounterValue(TPM_COUNTER_VALUE **tpm_counter_value, + TPM_COUNTER_VALUE *monotonicCounters, + TPM_COUNT_ID countID); +TPM_RESULT TPM_Counters_Release(TPM_COUNTER_VALUE *monotonicCounters); +void TPM_Counters_GetActiveCounter(TPM_COUNT_ID *activeCounter, + TPM_COUNT_ID countID); + + +/* + TPM_COUNTER_VALUE +*/ + +void TPM_CounterValue_Init(TPM_COUNTER_VALUE *tpm_counter_value); +TPM_RESULT TPM_CounterValue_Load(TPM_COUNTER_VALUE *tpm_counter_value, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CounterValue_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_COUNTER_VALUE *tpm_counter_value); + +TPM_RESULT TPM_CounterValue_StorePublic(TPM_STORE_BUFFER *sbuffer, + const TPM_COUNTER_VALUE *tpm_counter_value); +void TPM_CounterValue_CopyPublic(TPM_COUNTER_VALUE *dst_tpm_counter_value, + TPM_COUNTER_VALUE *src_tpm_counter_value); +TPM_RESULT TPM_CounterValue_Set(TPM_COUNTER_VALUE *tpm_counter_value, + TPM_COUNT_ID countID, + BYTE *label, + TPM_ACTUAL_COUNT counter, + TPM_SECRET authData); +TPM_RESULT TPM_CounterValue_Release(TPM_COUNTER_VALUE *tpm_counter_value, + TPM_COUNT_ID countID); +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_CreateCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_IncrementCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ReadCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ReleaseCounter(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ReleaseCounterOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + +#endif diff --git a/src/tpm_crypto.c b/src/tpm_crypto.c new file mode 100644 index 00000000..b1e4949e --- /dev/null +++ b/src/tpm_crypto.c @@ -0,0 +1,2778 @@ +/********************************************************************************/ +/* */ +/* Platform Dependent Crypto */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_crypto.c 4603 2011-08-16 20:40:26Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +/* This is the openSSL implementation */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_io.h" +#include "tpm_load.h" +#include "tpm_memory.h" +#include "tpm_process.h" +#include "tpm_types.h" + +#include "tpm_crypto.h" + + +/* The TPM OAEP encoding parameter */ +static const unsigned char tpm_oaep_pad_str[] = { 'T', 'C', 'P', 'A' }; + + +/* local prototypes */ + +static void TPM_OpenSSL_PrintError(void); + +static TPM_RESULT TPM_RSAGeneratePublicToken(RSA **rsa_pub_key, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); +static TPM_RESULT TPM_RSAGeneratePrivateToken(RSA **rsa_pri_key, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes, + unsigned char *darr, + uint32_t dbytes); +static TPM_RESULT TPM_RSASignSHA1(unsigned char *signature, + unsigned int *signature_length, + const unsigned char *message, + size_t message_size, + RSA *rsa_pri_key); +static TPM_RESULT TPM_RSASignDER(unsigned char *signature, + unsigned int *signature_length, + const unsigned char *message, + size_t message_size, + RSA *rsa_pri_key); + +static TPM_RESULT TPM_BN_CTX_new(BN_CTX **ctx); + + + +/* TPM_SYMMETRIC_KEY_DATA is a crypto library platform dependent symmetric key structure + */ +#ifdef TPM_DES + +/* local prototype and structure for DES */ + +#include + +/* DES requires data lengths that are a multiple of the block size */ +#define TPM_DES_BLOCK_SIZE 8 + +typedef struct tdTPM_SYMMETRIC_KEY_DATA { + TPM_TAG tag; + TPM_BOOL valid; + BYTE fill; + DES_cblock des_cblock1; + DES_cblock des_cblock2; + DES_cblock des_cblock3; +} TPM_SYMMETRIC_KEY_DATA; + +static TPM_RESULT TPM_SymmetricKeyData_Crypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t length, + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data, + int enc, + TPM_RESULT error); + +#endif + +#ifdef TPM_AES + +/* local prototype and structure for AES */ + +#include + +/* AES requires data lengths that are a multiple of the block size */ +#define TPM_AES_BITS 128 +/* The AES block size is always 16 bytes */ +#define TPM_AES_BLOCK_SIZE 16 + +/* Since the AES key is often derived by truncating the session shared secret, test that it's not + too large +*/ + +#if (TPM_AES_BLOCK_SIZE > TPM_SECRET_SIZE) +#error TPM_AES_BLOCK_SIZE larger than TPM_SECRET_SIZE +#endif + +/* The AES initial CTR value is derived from a nonce. */ + +#if (TPM_AES_BLOCK_SIZE > TPM_NONCE_SIZE) +#error TPM_AES_BLOCK_SIZE larger than TPM_NONCE_SIZE +#endif + +typedef struct tdTPM_SYMMETRIC_KEY_DATA { + TPM_TAG tag; + TPM_BOOL valid; + TPM_BOOL fill; + unsigned char userKey[TPM_AES_BLOCK_SIZE]; + /* For performance, generate these once from userKey */ + AES_KEY aes_enc_key; + AES_KEY aes_dec_key; +} TPM_SYMMETRIC_KEY_DATA; + +static TPM_RESULT TPM_SymmetricKeyData_SetKeys(TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data); +static TPM_RESULT TPM_SymmetricKeyData_SetKey(TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data, + const unsigned char *key_data, + uint32_t key_data_size); +static TPM_RESULT TPM_AES_ctr128_encrypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t data_size, + const AES_KEY *aes_enc_key, + unsigned char ctr[TPM_AES_BLOCK_SIZE]); + +#endif + +/* + Initialization function +*/ + +TPM_RESULT TPM_Crypto_Init() +{ + TPM_RESULT rc = 0; + + printf("TPM_Crypto_Init: OpenSSL library %08lx\n", (unsigned long)OPENSSL_VERSION_NUMBER); + OpenSSL_add_all_algorithms(); + /* sanity check that the SHA1 context handling remains portable */ + if (rc == 0) { + if ((sizeof(SHA_LONG) != sizeof(uint32_t)) || + (sizeof(unsigned int) != sizeof(uint32_t)) || + (sizeof(SHA_CTX) != (sizeof(uint32_t) * (8 + SHA_LBLOCK)))) { + printf("TPM_Crypto_Init: Error(fatal), SHA_CTX has unexpected structure\n"); + rc = TPM_FAIL; + } + } + return rc; +} + +/* TPM_Crypto_TestSpecific() performs any library specific tests + + For OpenSSL + */ + +TPM_RESULT TPM_Crypto_TestSpecific() +{ + TPM_RESULT rc = 0; + + /* Saving the SHA-1 context is fragile code, so test at startup */ + void *context1; + void *context2; + unsigned char buffer1[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + unsigned char expect1[] = {0x84,0x98,0x3E,0x44,0x1C, + 0x3B,0xD2,0x6E,0xBA,0xAE, + 0x4A,0xA1,0xF9,0x51,0x29, + 0xE5,0xE5,0x46,0x70,0xF1}; + TPM_DIGEST actual; + int not_equal; + TPM_STORE_BUFFER sbuffer; + const unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_Crypto_TestSpecific: Test 1 - SHA1 two parts\n"); + context1 = NULL; /* freed @1 */ + context2 = NULL; /* freed @2 */ + TPM_Sbuffer_Init(&sbuffer); /* freed @3 */ + + if (rc== 0) { + rc = TPM_Malloc((unsigned char **)&context1, sizeof(SHA_CTX)); /* freed @1 */ + } + /* digest the first part of the array */ + if (rc== 0) { + SHA1_Init(context1); + SHA1_Update(context1, buffer1, 16); + } + /* store the SHA1 context */ + if (rc== 0) { + rc = TPM_Sha1Context_Store(&sbuffer, context1); + } + /* load the SHA1 context */ + if (rc== 0) { + TPM_Sbuffer_Get(&sbuffer, &stream, &stream_size); + rc = TPM_Sha1Context_Load + (&context2, (unsigned char **)&stream, &stream_size); /* freed @2 */ + } + /* digest the rest of the array */ + if (rc== 0) { + SHA1_Update(context2, buffer1 + 16, sizeof(buffer1) - 17); + SHA1_Final(actual, context2); + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_Crypto_TestSpecific: Error in test 1\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + free(context1); /* @1 */ + free(context2); /* @2 */ + TPM_Sbuffer_Delete(&sbuffer); /* @3 */ + return rc; +} + + + +/* + Random Number Functions +*/ + +/* TPM_Random() fills 'buffer' with 'bytes' bytes. + */ + +TPM_RESULT TPM_Random(BYTE *buffer, size_t bytes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Random: Requesting %lu bytes\n", (unsigned long)bytes); + + if (rc == 0) { + /* openSSL call */ + rc = RAND_bytes(buffer, bytes); + if (rc == 1) { /* OSSL success */ + rc = 0; + } + else { /* OSSL failure */ + printf("TPM_Random: Error (fatal) calling RAND_bytes()\n"); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_StirRandomCmd(TPM_SIZED_BUFFER *inData) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StirRandomCmd:\n"); + if (rc == 0) { + /* NOTE: The TPM command does not give an entropy estimate. This assumes the best case */ + /* openSSL call */ + RAND_add(inData->buffer, /* buf mixed into PRNG state*/ + inData->size, /* number of bytes */ + inData->size); /* entropy, the lower bound of an estimate of how much randomness is + contained in buf */ + } + return rc; +} + +/* + RSA Functions +*/ + +/* Generate an RSA key pair. + + 'n', 'p', 'q', 'd' must be freed by the caller +*/ + +TPM_RESULT TPM_RSAGenerateKeyPair(unsigned char **n, /* public key - modulus */ + unsigned char **p, /* private key prime */ + unsigned char **q, /* private key prime */ + unsigned char **d, /* private key (private exponent) */ + int num_bits, /* key size in bits */ + const unsigned char *earr, /* public exponent as an array */ + uint32_t e_size) +{ + TPM_RESULT rc = 0; + RSA *rsa = NULL; + uint32_t nbytes; + uint32_t pbytes; + uint32_t qbytes; + uint32_t dbytes; + + unsigned long e; + + /* initialize in case of error */ + printf(" TPM_RSAGenerateKeyPair:\n"); + *n = NULL; + *p = NULL; + *q = NULL; + *d = NULL; + + /* check that num_bits is a multiple of 16. If not, the primes p and q will not be a multiple of + 8 and will not fit well in a byte */ + if (rc == 0) { + if ((num_bits % 16) != 0) { + printf("TPM_RSAGenerateKeyPair: Error, num_bits %d is not a multiple of 16\n", + num_bits); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* convert the e array to an unsigned long */ + if (rc == 0) { + rc = TPM_LoadLong(&e, earr, e_size); + } + /* validate the public exponent against a list of legal values. Some values (e.g. even numbers) + will hang the key generator. */ + if (rc == 0) { + rc = TPM_RSA_exponent_verify(e); + } + if (rc == 0) { + printf(" TPM_RSAGenerateKeyPair: num_bits %d exponent %08lx\n", num_bits, e); + rsa = RSA_generate_key(num_bits, e, NULL, NULL); /* freed @1 */ + if (rsa == NULL) { + printf("TPM_RSAGenerateKeyPair: Error calling RSA_generate_key()\n"); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* load n */ + if (rc == 0) { + rc = TPM_bn2binMalloc(n, &nbytes, (TPM_BIGNUM)rsa->n, num_bits/8); /* freed by caller */ + } + /* load p */ + if (rc == 0) { + rc = TPM_bn2binMalloc(p, &pbytes, (TPM_BIGNUM)rsa->p, num_bits/16); /* freed by caller */ + } + /* load q */ + if (rc == 0) { + rc = TPM_bn2binMalloc(q, &qbytes, (TPM_BIGNUM)rsa->q, num_bits/16); /* freed by caller */ + } + /* load d */ + if (rc == 0) { + rc = TPM_bn2binMalloc(d, &dbytes, (TPM_BIGNUM)rsa->d, num_bits/8); /* freed by caller */ + } + if (rc == 0) { + printf(" TPM_RSAGenerateKeyPair: length of n,p,q,d = %d / %d / %d / %d\n", + nbytes, pbytes, qbytes, dbytes); + } + if (rc != 0) { + free(*n); + free(*p); + free(*q); + free(*d); + *n = NULL; + *p = NULL; + *q = NULL; + *d = NULL; + } + if (rsa != NULL) { + RSA_free(rsa); /* @1 */ + } + return rc; +} + +/* TPM_RSAGeneratePublicToken() generates an RSA key token from n and e + */ + +static TPM_RESULT TPM_RSAGeneratePublicToken(RSA **rsa_pub_key, /* freed by caller */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + BIGNUM * n = NULL; + BIGNUM * e = NULL; + + /* sanity check for the free */ + if (rc == 0) { + if (*rsa_pub_key != NULL) { + printf("TPM_RSAGeneratePublicToken: Error (fatal), token %p should be NULL\n", + *rsa_pub_key ); + rc = TPM_FAIL; + + } + } + /* construct the OpenSSL private key object */ + if (rc == 0) { + *rsa_pub_key = RSA_new(); /* freed by caller */ + if (*rsa_pub_key == NULL) { + printf("TPM_RSAGeneratePublicToken: Error in RSA_new()\n"); + rc = TPM_SIZE; + } + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&n, narr, nbytes); /* freed by caller */ + } + if (rc == 0) { + (*rsa_pub_key)->n = n; + rc = TPM_bin2bn((TPM_BIGNUM *)&e, earr, ebytes); /* freed by caller */ + } + if (rc == 0) { + (*rsa_pub_key)->e = e; + (*rsa_pub_key)->d = NULL; + } + return rc; +} + +/* TPM_RSAGeneratePrivateToken() generates an RSA key token from n,e,d + */ + +static TPM_RESULT TPM_RSAGeneratePrivateToken(RSA **rsa_pri_key, /* freed by caller */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + BIGNUM * n = NULL; + BIGNUM * e = NULL; + BIGNUM * d = NULL; + + /* sanity check for the free */ + if (rc == 0) { + if (*rsa_pri_key != NULL) { + printf("TPM_RSAGeneratePrivateToken: Error (fatal), token %p should be NULL\n", + *rsa_pri_key ); + rc = TPM_FAIL; + + } + } + /* construct the OpenSSL private key object */ + if (rc == 0) { + *rsa_pri_key = RSA_new(); /* freed by caller */ + if (*rsa_pri_key == NULL) { + printf("TPM_RSAGeneratePrivateToken: Error in RSA_new()\n"); + rc = TPM_SIZE; + } + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&n, narr, nbytes); /* freed by caller */ + } + if (rc == 0) { + (*rsa_pri_key)->n = n; + rc = TPM_bin2bn((TPM_BIGNUM *)&e, earr, ebytes); /* freed by caller */ + } + if (rc == 0) { + (*rsa_pri_key)->e = e; + rc = TPM_bin2bn((TPM_BIGNUM *)&d, darr, dbytes); /* freed by caller */ + } + if (rc == 0) { + (*rsa_pri_key)->d = d; + } + return rc; +} + +/* TPM_RSAPrivateDecrypt() decrypts 'encrypt_data' using the private key 'n, e, d'. The OAEP + padding is removed and 'decrypt_data_length' bytes are moved to 'decrypt_data'. + + 'decrypt_data_length' is at most 'decrypt_data_size'. +*/ + +TPM_RESULT TPM_RSAPrivateDecrypt(unsigned char *decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + size_t decrypt_data_size, /* size of decrypt_data buffer */ + TPM_ENC_SCHEME encScheme, /* encryption scheme */ + unsigned char *encrypt_data, /* encrypted data */ + uint32_t encrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + int irc; + RSA * rsa_pri_key = NULL; /* freed @1 */ + + unsigned char *padded_data = NULL; + int padded_data_size = 0; + + printf(" TPM_RSAPrivateDecrypt:\n"); + /* construct the OpenSSL private key object */ + if (rc == 0) { + rc = TPM_RSAGeneratePrivateToken(&rsa_pri_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + /* intermediate buffer for the decrypted but still padded data */ + if (rc == 0) { + /* the size of the decrypted data is guaranteed to be less than this */ + padded_data_size = RSA_size(rsa_pri_key); + rc = TPM_Malloc(&padded_data, padded_data_size); + } + if (rc == 0) { + /* decrypt with private key. Must decrypt first and then remove padding because the decrypt + call cannot specify an encoding parameter */ + /* returns the size of the encrypted data. On error, -1 is returned */ + irc = RSA_private_decrypt(encrypt_data_size, /* length */ + encrypt_data, /* from - the encrypted data */ + padded_data, /* to - the decrypted but padded data */ + rsa_pri_key, /* key */ + RSA_NO_PADDING); /* padding */ + if (irc < 0) { + printf("TPM_RSAPrivateDecrypt: Error in RSA_private_decrypt()\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + printf(" TPM_RSAPrivateDecrypt: RSA_private_decrypt() success\n"); + printf(" TPM_RSAPrivateDecrypt: Padded data size %u\n", padded_data_size); + TPM_PrintFour(" TPM_RSAPrivateDecrypt: Decrypt padded data", padded_data); + if (encScheme == TPM_ES_RSAESOAEP_SHA1_MGF1) { + /* openSSL expects the padded data to skip the first 0x00 byte, since it expects the + padded data to come from a bignum via bn2bin. */ + irc = RSA_padding_check_PKCS1_OAEP(decrypt_data, /* to */ + decrypt_data_size, /* to length */ + padded_data + 1, /* from */ + padded_data_size - 1, /* from length */ + encrypt_data_size, /* rsa_len */ + tpm_oaep_pad_str, /* encoding parameter */ + sizeof(tpm_oaep_pad_str) /* encoding parameter length + */ + ); + if (irc < 0) { + printf("TPM_RSAPrivateDecrypt: Error in RSA_padding_check_PKCS1_OAEP()\n"); + rc = TPM_DECRYPT_ERROR; + } + } + else if (encScheme == TPM_ES_RSAESPKCSv15) { + irc = RSA_padding_check_PKCS1_type_2(decrypt_data, /* to */ + decrypt_data_size, /* to length */ + padded_data + 1, /* from */ + padded_data_size - 1, /* from length */ + encrypt_data_size /* rsa_len */ + ); + if (irc < 0) { + printf("TPM_RSAPrivateDecrypt: Error in RSA_padding_check_PKCS1_type_2()\n"); + rc = TPM_DECRYPT_ERROR; + } + } + else { + printf("TPM_RSAPrivateDecrypt: Error, unknown encryption scheme %04x\n", encScheme); + rc = TPM_INAPPROPRIATE_ENC; + } + } + if (rc == 0) { + *decrypt_data_length = irc; + printf(" TPM_RSAPrivateDecrypt: RSA_padding_check_PKCS1_OAEP() recovered %d bytes\n", irc); + TPM_PrintFour(" TPM_RSAPrivateDecrypt: Decrypt data", decrypt_data); + } + if (rsa_pri_key != NULL) { + RSA_free(rsa_pri_key); /* @1 */ + } + free(padded_data); /* @2 */ + return rc; +} + +/* TPM_RSAPublicEncrypt() pads 'decrypt_data' to 'encrypt_data_size' and encrypts using the public + key 'n, e'. +*/ + +TPM_RESULT TPM_RSAPublicEncrypt(unsigned char* encrypt_data, /* encrypted data */ + size_t encrypt_data_size, /* size of encrypted data buffer */ + TPM_ENC_SCHEME encScheme, + const unsigned char *decrypt_data, /* decrypted data */ + size_t decrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + int irc; + RSA *rsa_pub_key = NULL; + unsigned char *padded_data = NULL; + + printf(" TPM_RSAPublicEncrypt: Input data size %lu\n", (unsigned long)decrypt_data_size); + /* intermediate buffer for the decrypted by still padded data */ + if (rc == 0) { + rc = TPM_Malloc(&padded_data, encrypt_data_size); /* freed @2 */ + } + /* construct the OpenSSL public key object */ + if (rc == 0) { + rc = TPM_RSAGeneratePublicToken(&rsa_pub_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + if (rc == 0) { + if (encScheme == TPM_ES_RSAESOAEP_SHA1_MGF1) { + irc = RSA_padding_add_PKCS1_OAEP(padded_data, /* to */ + encrypt_data_size, /* to length */ + decrypt_data, /* from */ + decrypt_data_size, /* from length */ + tpm_oaep_pad_str, /* encoding parameter */ + sizeof(tpm_oaep_pad_str) /* encoding parameter length + */ + ); + if (irc != 1) { + printf("TPM_RSAPublicEncrypt: Error in RSA_padding_add_PKCS1_OAEP()\n"); + rc = TPM_ENCRYPT_ERROR; + } + else { + printf(" TPM_RSAPublicEncrypt: RSA_padding_add_PKCS1_OAEP() success\n"); + } + } + else if (encScheme == TPM_ES_RSAESPKCSv15) { + irc = RSA_padding_add_PKCS1_type_2(padded_data, /* to */ + encrypt_data_size, /* to length */ + decrypt_data, /* from */ + decrypt_data_size); /* from length */ + if (irc != 1) { + printf("TPM_RSAPublicEncrypt: Error in RSA_padding_add_PKCS1_type_2()\n"); + rc = TPM_ENCRYPT_ERROR; + } + else { + printf(" TPM_RSAPublicEncrypt: RSA_padding_add_PKCS1_type_2() success\n"); + } + } + else { + printf("TPM_RSAPublicEncrypt: Error, unknown encryption scheme %04x\n", encScheme); + rc = TPM_INAPPROPRIATE_ENC; + } + } + if (rc == 0) { + printf(" TPM_RSAPublicEncrypt: Padded data size %lu\n", (unsigned long)encrypt_data_size); + TPM_PrintFour(" TPM_RSAPublicEncrypt: Padded data", padded_data); + /* encrypt with public key. Must pad first and then encrypt because the encrypt + call cannot specify an encoding parameter */ + /* returns the size of the encrypted data. On error, -1 is returned */ + irc = RSA_public_encrypt(encrypt_data_size, /* from length */ + padded_data, /* from - the clear text data */ + encrypt_data, /* the padded and encrypted data */ + rsa_pub_key, /* key */ + RSA_NO_PADDING); /* padding */ + if (irc < 0) { + printf("TPM_RSAPublicEncrypt: Error in RSA_public_encrypt()\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + printf(" TPM_RSAPublicEncrypt: RSA_public_encrypt() success\n"); + } + if (rsa_pub_key != NULL) { + RSA_free(rsa_pub_key); /* @1 */ + } + free(padded_data); /* @2 */ + return rc; +} + +/* TPM_RSAPublicEncryptRaw() does a raw public key operation without any padding. + +*/ + +TPM_RESULT TPM_RSAPublicEncryptRaw(unsigned char *encrypt_data, /* output */ + uint32_t encrypt_data_size, /* input, size of message buffer */ + unsigned char *decrypt_data, /* input */ + uint32_t decrypt_data_size, /* input, size of sig buffer */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + int irc; + RSA *rsa_pub_key = NULL; + + printf(" TPM_RSAPublicEncryptRaw:\n"); + /* the input data size must equal the public key size */ + if (rc == 0) { + if (decrypt_data_size != nbytes) { + printf("TPM_RSAPublicEncryptRaw: Error, decrypt data size is %u not %u\n", + decrypt_data_size, nbytes); + rc = TPM_ENCRYPT_ERROR; + } + } + /* the output data size must equal the public key size */ + if (rc == 0) { + if (encrypt_data_size != nbytes) { + printf("TPM_RSAPublicEncryptRaw: Error, Encrypted data size is %u not %u\n", + decrypt_data_size, nbytes); + rc = TPM_ENCRYPT_ERROR; + } + } + /* construct the OpenSSL public key object */ + if (rc == 0) { + rc = TPM_RSAGeneratePublicToken(&rsa_pub_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncryptRaw: Public modulus", narr); + TPM_PrintAll(" TPM_RSAPublicEncryptRaw: Public exponent", earr, ebytes); + TPM_PrintFour(" TPM_RSAPublicEncryptRaw: Decrypt data", decrypt_data); + /* encrypt the decrypt_data */ + irc = RSA_public_encrypt(decrypt_data_size, /* from length */ + decrypt_data, /* from - the clear text data */ + encrypt_data, /* to - the padded and encrypted data */ + rsa_pub_key, /* key */ + RSA_NO_PADDING); /* padding */ + if (irc < 0) { + printf("TPM_RSAPublicEncryptRaw: Error in RSA_public_encrypt()\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncryptRaw: Encrypt data", encrypt_data); +#if 0 /* NOTE: Uncomment as a debug aid for signature verification */ + TPM_PrintAll(" TPM_RSAPublicEncryptRaw: Padded signed data", + encrypt_data, encrypt_data_size); +#endif + } + if (rsa_pub_key != NULL) { + RSA_free(rsa_pub_key); /* @1 */ + } + return rc; +} + +/* TPM_RSASign() signs 'message' of size 'message_size' using the private key n,e,d and the + signature scheme 'sigScheme' as specified in PKCS #1 v2.0. + + 'signature_length' bytes are moved to 'signature'. 'signature_length' is at most + 'signature_size'. signature must point to RSA_size(rsa) bytes of memory. +*/ + +TPM_RESULT TPM_RSASign(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + unsigned int signature_size, /* input, size of signature buffer */ + TPM_SIG_SCHEME sigScheme, /* input, type of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + RSA * rsa_pri_key = NULL; /* freed @1 */ + unsigned int key_size; + + printf(" TPM_RSASign:\n"); + /* construct the OpenSSL private key object */ + if (rc == 0) { + rc = TPM_RSAGeneratePrivateToken(&rsa_pri_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + /* check the size of the output signature buffer */ + if (rc == 0) { + key_size = (unsigned int)RSA_size(rsa_pri_key); /* openSSL returns an int, but never + negative */ + if (signature_size < key_size) { + printf("TPM_RSASign: Error (fatal), buffer %u too small for signature %u\n", + signature_size, key_size); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + /* determine the signature scheme for the key */ + if (rc == 0) { + switch(sigScheme) { + case TPM_SS_NONE: + printf("TPM_RSASign: Error, sigScheme TPM_SS_NONE\n"); + rc = TPM_INVALID_KEYUSAGE; + break; + case TPM_SS_RSASSAPKCS1v15_SHA1: + case TPM_SS_RSASSAPKCS1v15_INFO: + rc = TPM_RSASignSHA1(signature, + signature_length, + message, + message_size, + rsa_pri_key); + break; + case TPM_SS_RSASSAPKCS1v15_DER: + rc = TPM_RSASignDER(signature, + signature_length, + message, + message_size, + rsa_pri_key); + break; + default: + printf("TPM_RSASign: Error, sigScheme %04hx unknown\n", sigScheme); + rc = TPM_INVALID_KEYUSAGE; + break; + } + } + if (rsa_pri_key != NULL) { + RSA_free(rsa_pri_key); /* @1 */ + } + return rc; +} + +/* TPM_RSASignSHA1() performs the following: + prepend a DER encoded algorithm ID + prepend a type 1 pad + encrypt with the private key +*/ + +static TPM_RESULT TPM_RSASignSHA1(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + RSA *rsa_pri_key) /* signing private key */ +{ + TPM_RESULT rc = 0; + int irc; + + printf(" TPM_RSASignSHA1:\n"); + /* sanity check, SHA1 messages must be 20 bytes */ + if (rc == 0) { + if (message_size != TPM_DIGEST_SIZE) { + printf("TPM_RSASignSHA1: Error, message size %lu not TPM_DIGEST_SIZE\n", + (unsigned long)message_size ); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* type NID_sha1, adds the algorithm identifier and type 1 pad */ + irc = RSA_sign(NID_sha1, /* type */ + message, message_size, + signature, signature_length, + rsa_pri_key); + /* RSA_sign() returns 1 on success, 0 otherwise. */ + if (irc != 1) { + printf("TPM_RSASignSHA1: Error in RSA_sign()\n"); + rc = TPM_DECRYPT_ERROR; + } + } + return rc; +} + +/* TPM_RSASignDER() performs the following: + + prepend a type 1 pad + encrypt with the private key + + The caller must check that the signature buffer is >= the key size. +*/ + +static TPM_RESULT TPM_RSASignDER(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + RSA *rsa_pri_key) /* signing private key */ +{ + TPM_RESULT rc = 0; + int irc; + int key_size; + unsigned char *message_pad; + int int_sig_len; /* openSSL overloads RSA_private_decrypt return code */ + + printf(" TPM_RSASignDER:\n"); + message_pad = NULL; /* freed @1 */ + /* the padded message size is the same as the key size */ + if (rc == 0) { + key_size = RSA_size(rsa_pri_key); + if (key_size < 0) { + printf(" TPM_RSASignDER: Error (fatal), negative key size %d\n", key_size); + rc = TPM_FAIL; /* should never occur */ + } + } + /* allocate memory for the padded message */ + if (rc == 0) { + printf(" TPM_RSASignDER: key size %d\n", key_size); + rc = TPM_Malloc(&message_pad, key_size); /* freed @1 */ + } + /* PKCS1 type 1 pad the message */ + if (rc == 0) { + printf(" TPM_RSASignDER: Applying PKCS1 type 1 padding, size from %lu to %u\n", + (unsigned long)message_size, key_size); + TPM_PrintFour(" TPM_RSASignDER: Input message", message); + /* This call checks that the message will fit with the padding */ + irc = RSA_padding_add_PKCS1_type_1(message_pad, /* to */ + key_size, + message, /* from */ + message_size); + if (irc != 1) { + printf("TPM_RSASignDER: Error padding message, size %lu key size %u\n", + (unsigned long)message_size, key_size); + rc = TPM_DECRYPT_ERROR; + } + } + /* raw sign with private key */ + if (rc == 0) { + printf(" TPM_RSASignDER: Encrypting with private key, message size %d\n", key_size); + TPM_PrintFour(" TPM_RSASignDER: Padded message", message_pad); + /* returns the size of the encrypted data. On error, -1 is returned */ + int_sig_len = RSA_private_encrypt(key_size, /* int flen */ + message_pad, /* unsigned char *from, */ + signature, /* unsigned char *to, */ + rsa_pri_key, /* RSA *rsa, */ + RSA_NO_PADDING); /* int padding); */ + if (int_sig_len >= 0) { + *signature_length = (unsigned int)int_sig_len; + } + else { + printf("TPM_RSASignDER: Error in RSA_private_encrypt()\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSASignDER: signature", signature); + } + free(message_pad); /* @1 */ + return rc; +} + +/* TPM_RSAVerifySHA1() performs the following: + decrypt the signature + verify and remove type 1 pad + verify and remove DER encoded algorithm ID + verify the signature on the message +*/ + +TPM_RESULT TPM_RSAVerifySHA1(unsigned char *signature, /* input */ + unsigned int signature_size, /* input, size of signature + buffer */ + const unsigned char *message, /* input */ + uint32_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + TPM_BOOL valid; + RSA * rsa_pub_key = NULL; + + printf(" TPM_RSAVerifySHA1:\n"); + /* construct the openSSL public key object from n and e */ + if (rc == 0) { + rc = TPM_RSAGeneratePublicToken(&rsa_pub_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + if (rc == 0) { + /* RSA_verify() returns 1 on successful verification, 0 otherwise. */ + valid = RSA_verify(NID_sha1, + message, message_size, + signature, signature_size, rsa_pub_key); + if (valid != 1) { + printf("TPM_RSAVerifySHA1: Error, bad signature\n"); + rc = TPM_BAD_SIGNATURE; + } + } + if (rsa_pub_key != NULL) { + RSA_free(rsa_pub_key); /* @1 */ + } + return rc; +} + +/* TPM_RSAGetPrivateKey recalculates q (2nd prime factor) and d (private key) from n (public key), e + (public exponent), and p (1st prime factor) + + The private key is validated by dividing the RSA product n by the RSA prime p and verifying that + the remainder is 0. + + 'qarr', darr' must be freed by the caller. +*/ + +TPM_RESULT TPM_RSAGetPrivateKey(uint32_t *qbytes, unsigned char **qarr, + uint32_t *dbytes, unsigned char **darr, + uint32_t nbytes, unsigned char *narr, + uint32_t ebytes, unsigned char *earr, + uint32_t pbytes, unsigned char *parr) +{ + TPM_RESULT rc = 0; /* TPM return code */ + int irc; /* openSSL return code */ + BIGNUM *brc; /* BIGNUM return code */ + + BIGNUM *n = NULL; /* public modulus */ + BIGNUM *e = NULL; /* public exponent */ + BIGNUM *d = NULL; /* private exponent */ + BIGNUM *p = NULL; /* secret prime factor */ + BIGNUM *q = NULL; /* secret prime factor */ + /* temporary variables */ + BN_CTX *ctx = NULL; /* freed @5, @6 */ + BIGNUM *r0 = NULL; /* n/p remainder */ + BIGNUM *r1 = NULL; + BIGNUM *r2 = NULL; + + /* set to NULL so caller can free after failure */ + printf(" TPM_RSAGetPrivateKey:\n"); + *qarr = NULL; + *darr = NULL; + /* check input parameters */ + if (rc == 0) { + if ((narr == NULL) || (nbytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing n\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* check input parameters */ + if (rc == 0) { + if ((earr == NULL) || (ebytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing e\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* check input parameters */ + if (rc == 0) { + if ((parr == NULL) || (pbytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing p\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* get some temporary BIGNUM's for use in the calculations */ + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); + } + if (rc == 0) { + BN_CTX_start(ctx); /* no return code */ + r0 = BN_CTX_get(ctx); /* sufficient to test return of last 'get' call */ + r1 = BN_CTX_get(ctx); + r2 = BN_CTX_get(ctx); + if (r2 == 0) { + printf("TPM_RSAGetPrivateKey: Error in BN_CTX_get()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_SIZE; + } + } + /* allocate BIGNUM's for q, d */ + if (rc == 0) { + rc = TPM_BN_new((TPM_BIGNUM *)&q); + } + if (rc == 0) { + rc = TPM_BN_new((TPM_BIGNUM *)&d); + } + /* convert n, e, p to BIGNUM's */ + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&n, narr, nbytes); /* freed @1 */ + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&e, earr, ebytes); /* freed @2 */ + } + if (rc == 0) { + rc = TPM_bin2bn((TPM_BIGNUM *)&p, parr, pbytes); /* freed @3 */ + } + /* calculate q = n/p */ + if (rc == 0) { + irc = BN_div(q, r0, n, p, ctx); /* q = n/p freed @4 */ + if (irc != 1) { /* 1 is success */ + printf("TPM_RSAGetPrivateKey: Error in BN_div()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_BAD_PARAMETER; + } + } + /* remainder should be zero */ + if (rc == 0) { + irc = BN_is_zero(r0); + if (irc != 1) { /* 1 is success */ + printf("TPM_RSAGetPrivateKey: Error in BN_is_zero()\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* calculate r0 = p-1 */ + if (rc == 0) { + irc = BN_sub(r0, p, BN_value_one()); /* r0 = p-1 freed @6 */ + if (irc != 1) { /* 1 is success */ + printf("TPM_RSAGetPrivateKey: Error in BN_sub()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_BAD_PARAMETER; + } + } + /* calculate r1 = q-1 */ + if (rc == 0) { + irc = BN_sub(r1, q, BN_value_one()); /* freed @6 */ + if (irc != 1) { /* 1 is success */ + printf("TPM_RSAGetPrivateKey: Error in BN_sub()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_BAD_PARAMETER; + } + } + /* calculate r2 = (p-1)(q-1) */ + if (rc == 0) { + irc = BN_mul(r2, r0, r1, ctx); /* freed @6 */ + if (irc != 1) { /* 1 is success */ + printf("TPM_RSAGetPrivateKey: Error in BN_mul()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_BAD_PARAMETER; + } + } + /* calculate d = multiplicative inverse e mod r0 */ + if (rc == 0) { + brc = BN_mod_inverse(d, e, r2, ctx); /* feed @5 */ + if (brc == NULL) { + printf("TPM_RSAGetPrivateKey: Error in BN_mod_inverse()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_BAD_PARAMETER; + } + } + /* get q as an array */ + if (rc == 0) { + rc = TPM_bn2binMalloc(qarr, qbytes, (TPM_BIGNUM)q, pbytes); /* freed by caller */ + } + /* get d as an array */ + if (rc == 0) { + TPM_PrintFour(" TPM_RSAGetPrivateKey: Calculated q", *qarr); + rc = TPM_bn2binMalloc(darr, dbytes, (TPM_BIGNUM)d, nbytes); /* freed by caller */ + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAGetPrivateKey: Calculated d", *darr); + printf(" TPM_RSAGetPrivateKey: length of n,p,q,d = %u / %u / %u / %u\n", + nbytes, pbytes, *qbytes, *dbytes); + } + BN_free(n); /* @1 */ + BN_free(e); /* @2 */ + BN_free(p); /* @3 */ + BN_free(q); /* @4 */ + BN_free(d); /* @3 */ + BN_CTX_end(ctx); /* @5 */ + BN_CTX_free(ctx); /* @6 */ + return rc; +} + +/* + openSSL wrappers do error logging and transformation of openSSL errors to TPM type errors +*/ + +/* TPM_OpenSSL_PrintError() prints a detailed openSSL error trace. + +*/ + +static void TPM_OpenSSL_PrintError() +{ + /* openssl error printing */ + unsigned long error; + const char *file; + int line; + const char *data; + int flags; + + error = ERR_get_error_line_data(&file, &line, &data, &flags); + printf("\terror %08lx file %s line %d data %s flags %08x\n", + error, file, line, data, flags); + return; +} + +/* TPM_BN_num_bytes() wraps the openSSL function in a TPM error handler + + Returns number of bytes in the input +*/ + +TPM_RESULT TPM_BN_num_bytes(unsigned int *numBytes, TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + int i; + BIGNUM *bn = (BIGNUM *)bn_in; + + i = BN_num_bytes(bn); + if (i >= 0) { + *numBytes = (unsigned int)i; + } + else { + printf("TPM_BN_num_bytes: Error (fatal), bytes in BIGNUM is negative\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_FAIL; + } + return rc; +} + +/* TPM_BN_is_one() wraps the openSSL function in a TPM error handler + + Returns success if input is 1 + */ + +TPM_RESULT TPM_BN_is_one(TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM *bn = (BIGNUM *)bn_in; + + /* int BN_is_one(BIGNUM *a); + BN_is_one() tests if a equals 0, 1, + BN_is_one() returns 1 if the condition is true, 0 otherwise. */ + irc = BN_is_one(bn); + if (irc != 1) { + printf("TPM_BN_is_one: Error, result is not 1\n"); + rc = TPM_DAA_WRONG_W; + } + return rc; +} + +/* TPM_BN_mod() wraps the openSSL function in a TPM error handler + + r = a mod m + */ + +TPM_RESULT TPM_BN_mod(TPM_BIGNUM rem_in, + const TPM_BIGNUM a_in, + const TPM_BIGNUM m_in) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM *rem = (BIGNUM *)rem_in; + BIGNUM *a = (BIGNUM *)a_in; + BIGNUM *m = (BIGNUM *)m_in; + BN_CTX *ctx = NULL; /* freed @1 */ + + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); /* freed @1 */ + } + /*int BN_mod(BIGNUM *rem, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx); + BN_mod() corresponds to BN_div() with dv set to NULL. + + int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *a, const BIGNUM *d, BN_CTX *ctx); + + BN_div() divides a by d and places the result in dv and the remainder in rem (dv=a/d, + rem=a%d). Either of dv and rem may be NULL, in which case the respective value is not + returned. The result is rounded towards zero; thus if a is negative, the remainder will be + zero or negative. For division by powers of 2, use BN_rshift(3). + + For all functions, 1 is returned for success, 0 on error. The return value should always be + checked + */ + irc = BN_mod(rem, a, m, ctx); + if (irc != 1) { + printf("TPM_BN_mod: Error performing BN_mod()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + BN_CTX_free(ctx); /* @1 */ + return rc; +} + +/* TPM_BN_mask_bits() wraps the openSSL function in a TPM error handler + + erase all but the lowest n bits of bn + bn = bn mod 2^^n +*/ + +TPM_RESULT TPM_BN_mask_bits(TPM_BIGNUM bn_in, unsigned int n) +{ + TPM_RESULT rc = 0; + int irc; + unsigned int numBytes; + BIGNUM *bn = (BIGNUM *)bn_in; + + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, bn_in); + } + /* if the BIGNUM is already the correct number of bytes, no need to mask, and BN_mask_bits() + will fail. */ + if (rc == 0) { + if (numBytes > (n / 8)) { + /* BN_mask_bits() truncates a to an n bit number (a&=~((~0)>>;n)). An error occurs if a + already is shorter than n bits. + + int BN_mask_bits(BIGNUM *a, int n); + return 1 for success, 0 on error. + */ + irc = BN_mask_bits(bn, n); + if (irc != 1) { + printf("TPM_BN_mask_bits: Error performing BN_mask_bits()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + } + return rc; +} + +/* TPM_BN_rshift() wraps the openSSL function in a TPM error handler + + Shift a right by n bits (discard the lowest n bits) and label the result r +*/ + +TPM_RESULT TPM_BN_rshift(TPM_BIGNUM *rBignum_in, /* freed by caller */ + TPM_BIGNUM aBignum_in, + int n) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM **rBignum = (BIGNUM **)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + + printf(" TPM_BN_rshift: n %d\n", n); + if (rc == 0) { + rc = TPM_BN_new(rBignum_in); + } + if (rc == 0) { + /* BN_rshift() shifts a right by n bits and places the result in r (r=a/2^n). + int BN_rshift(BIGNUM *r, BIGNUM *a, int n); + return 1 for success, 0 on error. + */ + irc = BN_rshift(*rBignum, aBignum, n); + if (irc != 1) { + printf("TPM_BN_rshift: Error performing BN_rshift()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + return rc; +} + +/* TPM_BN_lshift() wraps the openSSL function in a TPM error handler + + Shift a left by n bits and label the result r +*/ + +TPM_RESULT TPM_BN_lshift(TPM_BIGNUM *rBignum_in, /* freed by caller */ + TPM_BIGNUM aBignum_in, + int n) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM **rBignum = (BIGNUM **)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + + printf(" TPM_BN_lshift: n %d\n", n); + if (rc == 0) { + rc = TPM_BN_new(rBignum_in); + } + if (rc == 0) { + /* BN_lshift() shifts a left by n bits and places the result in r (r=a*2^n). + int BN_lshift(BIGNUM *r, const BIGNUM *a, int n); + return 1 for success, 0 on error. + */ + irc = BN_lshift(*rBignum, aBignum, n); + if (irc != 1) { + printf("TPM_lshift: Error performing BN_lshift()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + return rc; +} + +/* TPM_BN_add() wraps the openSSL function in a TPM error handler + + Performs R = A + B + + R may be the same as A or B +*/ + +TPM_RESULT TPM_BN_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in) +{ + TPM_RESULT rc = 0; + int irc; + BIGNUM *rBignum = (BIGNUM *)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + BIGNUM *bBignum = (BIGNUM *)bBignum_in; + + printf(" TPM_BN_add:\n"); + /* int BN_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b); + BN_add() adds a and b and places the result in r (r=a+b). r may be the same BIGNUM as a or b. + 1 is returned for success, 0 on error. + */ + irc = BN_add(rBignum, aBignum, bBignum); + if (irc != 1) { + printf("TPM_BN_add: Error performing BN_add()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + return rc; +} + +/* TPM_BN_mul() wraps the openSSL function in a TPM error handler + + r = a * b +*/ + +TPM_RESULT TPM_BN_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in) +{ + TPM_RESULT rc = 0; + int irc; + BN_CTX *ctx; + BIGNUM *rBignum = (BIGNUM *)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + BIGNUM *bBignum = (BIGNUM *)bBignum_in; + + printf(" TPM_BN_mul:\n"); + ctx = NULL; /* freed @1 */ + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); /* freed @1 */ + } + /* int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, BN_CTX *ctx); + BN_mul() multiplies a and b and places the result in r (r=a*b). r may be the same BIGNUM as a + or b. + 1 is returned for success, 0 on error. + */ + if (rc == 0) { + irc = BN_mul(rBignum, aBignum, bBignum, ctx); + if (irc != 1) { + printf("TPM_BN_add: Error performing BN_mul()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + BN_CTX_free(ctx); /* @1 */ + return rc; +} + +/* TPM_BN_mod_exp() wraps the openSSL function in a TPM error handler + + computes a to the p-th power modulo m (r=a^p % n) +*/ + +TPM_RESULT TPM_BN_mod_exp(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM pBignum_in, + TPM_BIGNUM nBignum_in) +{ + TPM_RESULT rc = 0; + int irc; + BN_CTX *ctx; + BIGNUM *rBignum = (BIGNUM *)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + BIGNUM *pBignum = (BIGNUM *)pBignum_in; + BIGNUM *nBignum = (BIGNUM *)nBignum_in; + + printf(" TPM_BN_mod_exp:\n"); + ctx = NULL; /* freed @1 */ + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); + } + /* BIGNUM calculation */ + /* int BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p, const BIGNUM *m, BN_CTX *ctx); + + BN_mod_exp() computes a to the p-th power modulo m (r=a^p % m). This function uses less time + and space than BN_exp(). + + 1 is returned for success, 0 on error. + */ + if (rc == 0) { + printf(" TPM_BN_mod_exp: Calculate mod_exp\n"); + irc = BN_mod_exp(rBignum, aBignum, pBignum, nBignum, ctx); + if (irc != 1) { + printf("TPM_BN_mod_exp: Error performing BN_mod_exp()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + BN_CTX_free(ctx); /* @1 */ + return rc; +} + +/* TPM_BN_Mod_add() wraps the openSSL function in a TPM error handler + + adds a to b modulo m +*/ + +TPM_RESULT TPM_BN_mod_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in) +{ + TPM_RESULT rc = 0; + int irc; + BN_CTX *ctx; + BIGNUM *rBignum = (BIGNUM *)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + BIGNUM *bBignum = (BIGNUM *)bBignum_in; + BIGNUM *mBignum = (BIGNUM *)mBignum_in; + + printf(" TPM_BN_mod_add:\n"); + ctx = NULL; /* freed @1 */ + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); + } + /* int BN_mod_add(BIGNUM *r, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); + BN_mod_add() adds a to b modulo m and places the non-negative result in r. + 1 is returned for success, 0 on error. + */ + if (rc == 0) { + irc = BN_mod_add(rBignum, aBignum, bBignum, mBignum, ctx); + if (irc != 1) { + printf("TPM_BN_mod_add: Error performing BN_mod_add()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + + BN_CTX_free(ctx); /* @1 */ + return rc; +} + +/* TPM_BN_mod_mul() wraps the openSSL function in a TPM error handler + + r = (a * b) mod m + */ + +TPM_RESULT TPM_BN_mod_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in) +{ + TPM_RESULT rc = 0; + int irc; + BN_CTX *ctx; + BIGNUM *rBignum = (BIGNUM *)rBignum_in; + BIGNUM *aBignum = (BIGNUM *)aBignum_in; + BIGNUM *bBignum = (BIGNUM *)bBignum_in; + BIGNUM *mBignum = (BIGNUM *)mBignum_in; + + printf(" TPM_BN_mod_mul:\n"); + ctx = NULL; /* freed @1 */ + if (rc == 0) { + rc = TPM_BN_CTX_new(&ctx); + } + /* int BN_mod_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b, const BIGNUM *m, BN_CTX *ctx); + BN_mod_mul() multiplies a by b and finds the non-negative remainder respective to modulus m + (r=(a*b) mod m). r may be the same BIGNUM as a or b. + 1 is returned for success, 0 on error. + */ + if (rc == 0) { + irc = BN_mod_mul(rBignum, aBignum, bBignum, mBignum, ctx); + if (irc != 1) { + printf("TPM_BN_mod_mul: Error performing BN_mod_mul()\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_DAA_WRONG_W; + } + } + BN_CTX_free(ctx); /* @1 */ + return rc; +} + +/* TPM_BN_CTX_new() wraps the openSSL function in a TPM error handler */ + +static TPM_RESULT TPM_BN_CTX_new(BN_CTX **ctx) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if (*ctx != NULL) { + printf("TPM_BN_CTX_new: Error (fatal), *ctx %p should be NULL before BN_CTX_new \n", + *ctx); + rc = TPM_FAIL; + } + } + if (rc == 0) { + *ctx = BN_CTX_new(); + if (*ctx == NULL) { + printf("TPM_BN_CTX_new: Error, context is NULL\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_SIZE; + + } + } + return rc; +} + +/* TPM_BN_new() wraps the openSSL function in a TPM error handler + + Allocates a new bignum +*/ + +TPM_RESULT TPM_BN_new(TPM_BIGNUM *bn_in) +{ + TPM_RESULT rc = 0; + BIGNUM **bn = (BIGNUM **)bn_in; + + *bn = BN_new(); + if (*bn == NULL) { + printf("TPM_BN_new: Error, bn is NULL\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_SIZE; + } + return rc; +} + +/* TPM_BN_free() wraps the openSSL function + + Frees the bignum +*/ + +void TPM_BN_free(TPM_BIGNUM bn_in) +{ + BIGNUM *bn = (BIGNUM *)bn_in; + + BN_free(bn); + return; +} + +/* TPM_bn2bin wraps the openSSL function in a TPM error handler. + + Converts a bignum to char array + + 'bin' must already be checked for sufficient size. + + int BN_bn2bin(const BIGNUM *a, unsigned char *to); + BN_bn2bin() returns the length of the big-endian number placed at to +*/ + +TPM_RESULT TPM_bn2bin(unsigned char *bin, + TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + BN_bn2bin((BIGNUM *)bn_in, bin); + return rc; +} + + +/* TPM_bin2bn() wraps the openSSL function in a TPM error handler + + Converts a char array to bignum + + bn must be freed by the caller. +*/ + +TPM_RESULT TPM_bin2bn(TPM_BIGNUM *bn_in, const unsigned char *bin, unsigned int bytes) +{ + TPM_RESULT rc = 0; + BIGNUM **bn = (BIGNUM **)bn_in; + + /* BIGNUM *BN_bin2bn(const unsigned char *s, int len, BIGNUM *ret); + + BN_bin2bn() converts the positive integer in big-endian form of length len at s into a BIGNUM + and places it in ret. If ret is NULL, a new BIGNUM is created. + + BN_bin2bn() returns the BIGNUM, NULL on error. + */ + if (rc == 0) { + *bn = BN_bin2bn(bin, bytes, *bn); + if (*bn == NULL) { + printf("TPM_bin2bn: Error in BN_bin2bn\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_SIZE; + } + } + return rc; +} + +/* + Hash Functions +*/ + +/* for the openSSL version, TPM_SHA1Context is a SHA_CTX structure */ + +/* TPM_SHA1InitCmd() initializes a platform dependent TPM_SHA1Context structure. + + The structure must be freed using TPM_SHA1Delete() +*/ + +TPM_RESULT TPM_SHA1InitCmd(void **context) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SHA1InitCmd:\n"); + if (rc== 0) { + rc = TPM_Malloc((unsigned char **)context, sizeof(SHA_CTX)); + } + if (rc== 0) { + SHA1_Init(*context); + } + return rc; +} + +/* TPM_SHA1UpdateCmd() adds 'data' of 'length' to the SHA-1 context + */ + +TPM_RESULT TPM_SHA1UpdateCmd(void *context, const unsigned char *data, uint32_t length) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SHA1Update: length %u\n", length); + if (context != NULL) { + SHA1_Update(context, data, length); + } + else { + printf("TPM_SHA1Update: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + return rc; +} + +/* TPM_SHA1FinalCmd() extracts the SHA-1 digest 'md' from the context + */ + +TPM_RESULT TPM_SHA1FinalCmd(unsigned char *md, void *context) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SHA1FinalCmd:\n"); + if (context != NULL) { + SHA1_Final(md, context); + } + else { + printf("TPM_SHA1FinalCmd: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + return rc; +} + +/* TPM_SHA1Delete() zeros and frees the SHA1 context */ + +void TPM_SHA1Delete(void **context) +{ + if (*context != NULL) { + printf(" TPM_SHA1Delete:\n"); + /* zero because the SHA1 context might have data left from an HMAC */ + memset(*context, 0, sizeof(SHA_CTX)); + free(*context); + *context = NULL; + } + return; +} + +/* TPM_Sha1Context_Load() is non-portable code to deserialize the OpenSSL SHA1 context. + + If the contextPresent prepended by TPM_Sha1Context_Store() is FALSE, context remains NULL. If + TRUE, context is allocated and loaded. +*/ + +TPM_RESULT TPM_Sha1Context_Load(void **context, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + SHA_CTX *sha_ctx = NULL; /* initialize to silence hopefully bogus gcc 4.4.4 + warning */ + TPM_BOOL contextPresent; /* is there a context to be loaded */ + + printf(" TPM_Sha1Context_Load: OpenSSL\n"); + /* TPM_Sha1Context_Store() stored a flag to indicate whether a context should be stored */ + if (rc== 0) { + rc = TPM_LoadBool(&contextPresent, stream, stream_size); + printf(" TPM_Sha1Context_Load: contextPresent %u\n", contextPresent); + } + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if ((rc== 0) && contextPresent) { + rc = TPM_CheckTag(TPM_TAG_SHA1CONTEXT_OSSL_V1, stream, stream_size); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Malloc((unsigned char **)context, sizeof(SHA_CTX)); + sha_ctx = (SHA_CTX *)*context; + } + /* load h0 */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->h0), stream, stream_size); + } + /* load h1 */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->h1), stream, stream_size); + } + /* load h2 */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->h2), stream, stream_size); + } + /* load h3 */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->h3), stream, stream_size); + } + /* load h4 */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->h4), stream, stream_size); + } + /* load Nl */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->Nl), stream, stream_size); + } + /* load Nh */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->Nh), stream, stream_size); + } + /* load data */ + for (i = 0 ; (rc == 0) && contextPresent && (i < SHA_LBLOCK) ; i++) { + rc = TPM_Load32(&(sha_ctx->data[i]), stream, stream_size); + } + /* load num */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&(sha_ctx->num), stream, stream_size); + } + return rc; +} + +/* TPM_Sha1Context_Store() is non-portable code to serialize the OpenSSL SHA1 context. context is + not altered. + + It prepends a contextPresent flag to the stream, FALSE if context is NULL, TRUE if not. +*/ + +TPM_RESULT TPM_Sha1Context_Store(TPM_STORE_BUFFER *sbuffer, + void *context) +{ + TPM_RESULT rc = 0; + size_t i; + SHA_CTX *sha_ctx = (SHA_CTX *)context; + TPM_BOOL contextPresent; /* is there a context to be stored */ + + printf(" TPM_Sha1Context_Store: OpenSSL\n"); + /* store contextPresent */ + if (rc == 0) { + if (sha_ctx != NULL) { + printf(" TPM_Sha1Context_Store: Storing context\n"); + contextPresent = TRUE; + } + else { + printf(" TPM_Sha1Context_Store: No context to store\n"); + contextPresent = FALSE; + } + rc = TPM_Sbuffer_Append(sbuffer, &contextPresent, sizeof(TPM_BOOL)); + } + /* overall format tag */ + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_SHA1CONTEXT_OSSL_V1); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->h0); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->h1); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->h2); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->h3); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->h4); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->Nl); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->Nh); + } + for (i = 0 ; (rc == 0) && contextPresent && (i < SHA_LBLOCK) ; i++) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->data[i]); + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, sha_ctx->num); + } + return rc; +} + +/* + TPM_SYMMETRIC_KEY_DATA +*/ + +/* TPM_SymmetricKeyData_New() allocates memory for and initializes a TPM_SYMMETRIC_KEY_DATA token. + */ + +TPM_RESULT TPM_SymmetricKeyData_New(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKeyData_New:\n"); + if (rc == 0) { + rc = TPM_Malloc(tpm_symmetric_key_data, sizeof(TPM_SYMMETRIC_KEY_DATA)); + } + if (rc == 0) { + TPM_SymmetricKeyData_Init(*tpm_symmetric_key_data); + } + return rc; +} + +/* TPM_SymmetricKeyData_Free() initializes the key token to wipe secrets. It then frees the + TPM_SYMMETRIC_KEY_DATA token and sets it to NULL. +*/ + +void TPM_SymmetricKeyData_Free(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data) +{ + printf(" TPM_SymmetricKeyData_Free:\n"); + if (*tpm_symmetric_key_data != NULL) { + TPM_SymmetricKeyData_Init(*tpm_symmetric_key_data); + free(*tpm_symmetric_key_data); + *tpm_symmetric_key_data = NULL; + } + return; +} + +#ifdef TPM_DES + +/* TPM_SymmetricKeyData_Init() is DES non-portable code to initialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +void TPM_SymmetricKeyData_Init(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Init:\n"); + tpm_symmetric_key_data->tag = TPM_TAG_KEY; + tpm_symmetric_key_data->valid = FALSE; + tpm_symmetric_key_data->fill = 0; + memset(tpm_symmetric_key_data->des_cblock1, 0, sizeof(DES_cblock)); + memset(tpm_symmetric_key_data->des_cblock2, 0, sizeof(DES_cblock)); + memset(tpm_symmetric_key_data->des_cblock3, 0, sizeof(DES_cblock)); + return; +} + +/* TPM_SymmetricKeyData_Load() is DES non-portable code to deserialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Load(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_KEY, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_symmetric_key_data->valid), stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_symmetric_key_data->fill), stream, stream_size); + } + /* this assumes that DES_cblock is a consistently packed structure. It is in fact an array of 8 + bytes for openSSL. */ + if (rc == 0) { + rc = TPM_Loadn(tpm_symmetric_key_data->des_cblock1, sizeof(DES_cblock), + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Loadn(tpm_symmetric_key_data->des_cblock2, sizeof(DES_cblock), + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Loadn(tpm_symmetric_key_data->des_cblock3, sizeof(DES_cblock), + stream, stream_size); + } + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Load: des1", tpm_symmetric_key_data->des_cblock1); + TPM_PrintFour(" TPM_SymmetricKeyData_Load: des2", tpm_symmetric_key_data->des_cblock2); + TPM_PrintFour(" TPM_SymmetricKeyData_Load: des3", tpm_symmetric_key_data->des_cblock3); + } + return rc; +} + +/* TPM_SymmetricKeyData_Store() DES is non-portable code to serialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Store:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Store: des1", tpm_symmetric_key_data->des_cblock1); + TPM_PrintFour(" TPM_SymmetricKeyData_Store: des2", tpm_symmetric_key_data->des_cblock2); + TPM_PrintFour(" TPM_SymmetricKeyData_Store: des3", tpm_symmetric_key_data->des_cblock3); + } + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key_data->tag); + } + /* store valid */s + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->valid), sizeof(TPM_BOOL)); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->fill), sizeof(TPM_BOOL)); + } + /* store DES key */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_symmetric_key_data->des_cblock1, sizeof(DES_cblock)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_symmetric_key_data->des_cblock2, sizeof(DES_cblock)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_symmetric_key_data->des_cblock3, sizeof(DES_cblock)); + } + return rc; +} + +/* TPM_SymmetricKeyData_GenerateKey() is DES non-portable code to generate a symmetric key + + vsymmetric_key must be freed by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_GenerateKey(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_GenerateKey:\n"); + /* generate a random key */ + if (rc == 0) { + DES_random_key(&(tpm_symmetric_key_data->des_cblock1)); + DES_random_key(&(tpm_symmetric_key_data->des_cblock2)); + DES_random_key(&(tpm_symmetric_key_data->des_cblock3)); + /* sets the parity of the passed key to odd. */ + DES_set_odd_parity(&(tpm_symmetric_key_data->des_cblock1)); + DES_set_odd_parity(&(tpm_symmetric_key_data->des_cblock2)); + DES_set_odd_parity(&(tpm_symmetric_key_data->des_cblock3)); + TPM_PrintFour(" TPM_SymmetricKeyData_GenerateKey: des1", + tpm_symmetric_key_data->des_cblock1); + TPM_PrintFour(" TPM_SymmetricKeyData_GenerateKey: des2", + tpm_symmetric_key_data->des_cblock2); + TPM_PrintFour(" TPM_SymmetricKeyData_GenerateKey: des3", + tpm_symmetric_key_data->des_cblock3); + tpm_symmetric_key_data->valid = TRUE; + } + return rc; +} + +/* TPM_SymmetricKeyData_Encrypt() is DES non-portable code to encrypt 'decrypt_data' to + 'encrypt_data' + + The stream is padded as per PKCS#7 / RFC2630 + + 'encrypt_data' must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Encrypt(unsigned char **encrypt_data, /* output, caller frees */ + uint32_t *encrypt_length, /* output */ + const unsigned char *decrypt_data, /* input */ + uint32_t decrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_token) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t pad_length; + unsigned char *decrypt_data_pad; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Encrypt: Length %u\n", decrypt_length); + decrypt_data_pad = NULL; /* freed @1 */ + if (rc == 0) { + /* calculate the pad length and padded data length */ + pad_length = TPM_DES_BLOCK_SIZE - (decrypt_length % TPM_DES_BLOCK_SIZE); + *encrypt_length = decrypt_length + pad_length; + printf(" TPM_SymmetricKeyData_Encrypt: Padded length %u pad length %u\n", + *encrypt_length, pad_length); + /* allocate memory for the encrypted response */ + rc = TPM_Malloc(encrypt_data, *encrypt_length); + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&decrypt_data_pad, *encrypt_length); + } + /* pad the decrypted clear text data */ + if (rc == 0) { + /* unpadded original data */ + memcpy(decrypt_data_pad, decrypt_data, decrypt_length); + /* last gets pad = pad length */ + memset(decrypt_data_pad + decrypt_length, pad_length, pad_length); + /* encrypt the padded input to the output */ + rc = TPM_SymmetricKeyData_Crypt(*encrypt_data, + decrypt_data_pad, + *encrypt_length, + tpm_symmetric_key_data, + DES_ENCRYPT, + TPM_ENCRYPT_ERROR); + } + free(decrypt_data_pad); /* @1 */ + return rc; +} + +/* TPM_SymmetricKeyData_Decrypt() is DES non-portable code to decrypt 'encrypt_data' to + 'decrypt_data' + + The stream must be padded as per PKCS#7 / RFC2630 + + decrypt_data must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Decrypt(unsigned char **decrypt_data, /* output, caller frees */ + uint32_t *decrypt_length, /* output */ + const unsigned char *encrypt_data, /* input */ + uint32_t encrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_data) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t pad_length; + uint32_t i; + unsigned char *pad_data; + + printf(" TPM_SymmetricKeyData_Decrypt: Length %u\n", encrypt_length); + /* sanity check encrypted length */ + if (rc == 0) { + if (encrypt_length < TPM_DES_BLOCK_SIZE) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(decrypt_data, encrypt_length); + } + /* decrypt the input to the padded output */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Crypt(*decrypt_data, + encrypt_data, + encrypt_length, + tpm_symmetric_key_data, + DES_DECRYPT, + TPM_DECRYPT_ERROR); + } + /* get the pad length */ + if (rc == 0) { + /* get the pad length from the last byte */ + pad_length = (uint32_t)*(*decrypt_data + encrypt_length - 1); + /* sanity check the pad length */ + printf(" TPM_SymmetricKeyData_Decrypt: Pad length %u\n", pad_length); + if ((pad_length == 0) || + (pad_length > TPM_DES_BLOCK_SIZE)) { + printf("TPM_SymmetricKeyData_Decrypt: Error, illegal pad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* get the unpadded length */ + *decrypt_length = encrypt_length - pad_length; + /* pad starting point */ + pad_data = *decrypt_data + *decrypt_length; + /* sanity check the pad */ + for (i = 0 ; i < pad_length ; i++, pad_data++) { + if (*pad_data != pad_length) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad pad %02x at index %u\n", + *pad_data, i); + rc = TPM_DECRYPT_ERROR; + } + } + } + return rc; +} + +/* TPM_SymmetricKeyData_Crypt() is DES common code for openSSL, since encrypt and decrypt use the + same function with an 'enc' flag. + + 'data_in' and 'data_out' must be preallocated arrays of 'length' bytes. 'length' must be a + multiple of TPM_DES_BLOCK_SIZE. + + Returns 'error' on error. +*/ + +/* openSSL prototype + + void DES_ede3_cbc_encrypt(const unsigned char *input, + unsigned char *output, long length, DES_key_schedule *ks1, + DES_key_schedule *ks2, DES_key_schedule *ks3, DES_cblock *ivec, + int enc); +*/ + +static TPM_RESULT TPM_SymmetricKeyData_Crypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t length, /* input */ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data, /*in*/ + int enc, /* input */ + TPM_RESULT error) /* input */ +{ + TPM_RESULT rc = 0; + int irc; + DES_key_schedule des_key_schedule1; + DES_key_schedule des_key_schedule2; + DES_key_schedule des_key_schedule3; + DES_cblock ivec; /* initial chaining vector */ + + if (rc == 0) { + if ((length % TPM_DES_BLOCK_SIZE) != 0) { + printf("TPM_SymmetricKeyData_Crypt: Error, illegal length %u\n", length); + rc = error; /* should never occur */ + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Crypt: des1", tpm_symmetric_key_data->des_cblock1); + TPM_PrintFour(" TPM_SymmetricKeyData_Crypt: des2", tpm_symmetric_key_data->des_cblock2); + TPM_PrintFour(" TPM_SymmetricKeyData_Crypt: des3", tpm_symmetric_key_data->des_cblock3); + } + /* Before a DES key can be used, it must be converted into the architecture dependent + DES_key_schedule via the DES_set_key_checked() or DES_set_key_unchecked() function. */ + if (rc == 0) { + irc = DES_set_key_checked(&(tpm_symmetric_key_data->des_cblock1), &des_key_schedule1); + if (irc != 0) { + printf("TPM_SymmetricKeyData_Crypt: Error, DES_set_key_checked rc %d\n", irc); + rc = error; + } + } + if (rc == 0) { + irc = DES_set_key_checked(&(tpm_symmetric_key_data->des_cblock2), &des_key_schedule2); + if (irc != 0) { + printf("TPM_SymmetricKeyData_Crypt: Error, DES_set_key_checked rc %d\n", irc); + rc = error; + } + } + if (rc == 0) { + irc = DES_set_key_checked(&(tpm_symmetric_key_data->des_cblock3), &des_key_schedule3); + if (irc != 0) { + printf("TPM_SymmetricKeyData_Crypt: Error, DES_set_key_checked rc %d\n", irc); + rc = error; + } + } + /* initialize initial chaining vector */ + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Crypt: Input", data_in); + /* encrypt operation */ + memset(&ivec, 0, sizeof(DES_cblock)); + DES_ede3_cbc_encrypt(data_in, + data_out, + length, + &des_key_schedule1, + &des_key_schedule2, + &des_key_schedule3, + &ivec, + enc); + TPM_PrintFour(" TPM_SymmetricKeyData_Crypt: Output", data_out); + } + return rc; +} + +#endif + +#ifdef TPM_AES + +/* TPM_SymmetricKeyData_Init() is AES non-portable code to initialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +void TPM_SymmetricKeyData_Init(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Init:\n"); + tpm_symmetric_key_data->tag = TPM_TAG_KEY; + tpm_symmetric_key_data->valid = FALSE; + tpm_symmetric_key_data->fill = 0; + memset(tpm_symmetric_key_data->userKey, 0, sizeof(tpm_symmetric_key_data->userKey)); + memset(&(tpm_symmetric_key_data->aes_enc_key), 0, sizeof(tpm_symmetric_key_data->aes_enc_key)); + memset(&(tpm_symmetric_key_data->aes_dec_key), 0, sizeof(tpm_symmetric_key_data->aes_dec_key)); + return; +} + +/* TPM_SymmetricKeyData_Load() is AES non-portable code to deserialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the above TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Load(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_KEY, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_symmetric_key_data->valid), stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_symmetric_key_data->fill), stream, stream_size); + } + /* The AES key is a simple array. */ + if (rc == 0) { + rc = TPM_Loadn(tpm_symmetric_key_data->userKey, sizeof(tpm_symmetric_key_data->userKey), + stream, stream_size); + } + /* reconstruct the internal AES keys */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_SetKeys(tpm_symmetric_key_data); + } + return rc; +} + +/* TPM_SymmetricKeyData_Store() is AES non-portable code to serialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the above TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key_data->tag); + } + /* store valid */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->valid), sizeof(TPM_BOOL)); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->fill), sizeof(TPM_BOOL)); + } + /* store AES key */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + tpm_symmetric_key_data->userKey, + sizeof(tpm_symmetric_key_data->userKey)); + } + /* No need to store the internal AES keys. They are reconstructed on load */ + return rc; +} + +/* TPM_SymmetricKeyData_GenerateKey() is AES non-portable code to generate a random symmetric key + + tpm_symmetric_key_data should be initialized before and after use +*/ + +TPM_RESULT TPM_SymmetricKeyData_GenerateKey(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_GenerateKey:\n"); + /* generate a random key */ + if (rc == 0) { + rc = TPM_Random(tpm_symmetric_key_data->userKey, sizeof(tpm_symmetric_key_data->userKey)); + } + /* construct the internal AES keys */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_SetKeys(tpm_symmetric_key_data); + } + if (rc == 0) { + tpm_symmetric_key_data->valid = TRUE; + } + return rc; +} + +/* TPM_SymmetricKeyData_SetKey() is AES non-portable code to set a symmetric key from input data + + tpm_symmetric_key_data should be initialized before and after use +*/ + +TPM_RESULT TPM_SymmetricKeyData_SetKey(TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data, + const unsigned char *key_data, + uint32_t key_data_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKeyData_SetKey:\n"); + /* check the input data size, it can be truncated, but cannot be smaller than the AES key */ + if (rc == 0) { + if (sizeof(tpm_symmetric_key_data->userKey) > key_data_size) { + printf("TPM_SymmetricKeyData_SetKey: Error (fatal), need %lu bytes, received %u\n", + (unsigned long)sizeof(tpm_symmetric_key_data->userKey), key_data_size); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* copy the input data into the AES key structure */ + memcpy(tpm_symmetric_key_data->userKey, key_data, sizeof(tpm_symmetric_key_data->userKey)); + /* construct the internal AES keys */ + rc = TPM_SymmetricKeyData_SetKeys(tpm_symmetric_key_data); + } + if (rc == 0) { + tpm_symmetric_key_data->valid = TRUE; + } + return rc; +} + +/* TPM_SymmetricKeyData_SetKeys() is AES non-portable code to construct the internal AES keys from + the userKey + + tpm_symmetric_key_data should be initialized before and after use +*/ + +static TPM_RESULT TPM_SymmetricKeyData_SetKeys(TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data) +{ + TPM_RESULT rc = 0; + int irc; + + printf(" TPM_SymmetricKeyData_SetKeys:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_SetKeys: userKey", tpm_symmetric_key_data->userKey); + irc = AES_set_encrypt_key(tpm_symmetric_key_data->userKey, + TPM_AES_BITS, + &(tpm_symmetric_key_data->aes_enc_key)); + if (irc != 0) { + printf("TPM_SymmetricKeyData_SetKeys: Error (fatal) generating enc key\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_FAIL; /* should never occur, null pointers or bad bit size */ + } + } + if (rc == 0) { + irc = AES_set_decrypt_key(tpm_symmetric_key_data->userKey, + TPM_AES_BITS, + &(tpm_symmetric_key_data->aes_dec_key)); + if (irc != 0) { + printf("TPM_SymmetricKeyData_SetKeys: Error (fatal) generating dec key\n"); + TPM_OpenSSL_PrintError(); + rc = TPM_FAIL; /* should never occur, null pointers or bad bit size */ + } + } + return rc; +} + +/* TPM_SymmetricKeyData_Encrypt() is AES non-portable code to encrypt 'decrypt_data' to + 'encrypt_data' + + The stream is padded as per PKCS#7 / RFC2630 + + 'encrypt_data' must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Encrypt(unsigned char **encrypt_data, /* output, caller frees */ + uint32_t *encrypt_length, /* output */ + const unsigned char *decrypt_data, /* input */ + uint32_t decrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_token) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t pad_length; + unsigned char *decrypt_data_pad; + unsigned char ivec[TPM_AES_BLOCK_SIZE]; /* initial chaining vector */ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Encrypt: Length %u\n", decrypt_length); + decrypt_data_pad = NULL; /* freed @1 */ + if (rc == 0) { + /* calculate the pad length and padded data length */ + pad_length = TPM_AES_BLOCK_SIZE - (decrypt_length % TPM_AES_BLOCK_SIZE); + *encrypt_length = decrypt_length + pad_length; + printf(" TPM_SymmetricKeyData_Encrypt: Padded length %u pad length %u\n", + *encrypt_length, pad_length); + /* allocate memory for the encrypted response */ + rc = TPM_Malloc(encrypt_data, *encrypt_length); + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&decrypt_data_pad, *encrypt_length); + } + /* pad the decrypted clear text data */ + if (rc == 0) { + /* unpadded original data */ + memcpy(decrypt_data_pad, decrypt_data, decrypt_length); + /* last gets pad = pad length */ + memset(decrypt_data_pad + decrypt_length, pad_length, pad_length); + /* set the IV */ + memset(ivec, 0, sizeof(ivec)); + /* encrypt the padded input to the output */ + TPM_PrintFour(" TPM_SymmetricKeyData_Encrypt: Input", decrypt_data_pad); + AES_cbc_encrypt(decrypt_data_pad, + *encrypt_data, + *encrypt_length, + &(tpm_symmetric_key_data->aes_enc_key), + ivec, + AES_ENCRYPT); + TPM_PrintFour(" TPM_SymmetricKeyData_Encrypt: Output", *encrypt_data); + } + free(decrypt_data_pad); /* @1 */ + return rc; +} + +/* TPM_SymmetricKeyData_Decrypt() is AES non-portable code to decrypt 'encrypt_data' to + 'decrypt_data' + + The stream must be padded as per PKCS#7 / RFC2630 + + decrypt_data must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Decrypt(unsigned char **decrypt_data, /* output, caller frees */ + uint32_t *decrypt_length, /* output */ + const unsigned char *encrypt_data, /* input */ + uint32_t encrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_token) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t pad_length; + uint32_t i; + unsigned char *pad_data; + unsigned char ivec[TPM_AES_BLOCK_SIZE]; /* initial chaining vector */ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Decrypt: Length %u\n", encrypt_length); + /* sanity check encrypted length */ + if (rc == 0) { + if (encrypt_length < TPM_AES_BLOCK_SIZE) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(decrypt_data, encrypt_length); + } + /* decrypt the input to the padded output */ + if (rc == 0) { + /* set the IV */ + memset(ivec, 0, sizeof(ivec)); + /* decrypt the padded input to the output */ + TPM_PrintFour(" TPM_SymmetricKeyData_Decrypt: Input", encrypt_data); + AES_cbc_encrypt(encrypt_data, + *decrypt_data, + encrypt_length, + &(tpm_symmetric_key_data->aes_dec_key), + ivec, + AES_DECRYPT); + TPM_PrintFour(" TPM_SymmetricKeyData_Decrypt: Output", *decrypt_data); + } + /* get the pad length */ + if (rc == 0) { + /* get the pad length from the last byte */ + pad_length = (uint32_t)*(*decrypt_data + encrypt_length - 1); + /* sanity check the pad length */ + printf(" TPM_SymmetricKeyData_Decrypt: Pad length %u\n", pad_length); + if ((pad_length == 0) || + (pad_length > TPM_AES_BLOCK_SIZE)) { + printf("TPM_SymmetricKeyData_Decrypt: Error, illegal pad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* get the unpadded length */ + *decrypt_length = encrypt_length - pad_length; + /* pad starting point */ + pad_data = *decrypt_data + *decrypt_length; + /* sanity check the pad */ + for (i = 0 ; i < pad_length ; i++, pad_data++) { + if (*pad_data != pad_length) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad pad %02x at index %u\n", + *pad_data, i); + rc = TPM_DECRYPT_ERROR; + } + } + } + return rc; +} + +/* TPM_SymmetricKeyData_CtrCrypt() does an encrypt or decrypt (they are the same XOR operation with + a CTR mode pad) of 'data_in' to 'data_out'. + + NOTE: This function looks general, but is currently hard coded to AES128. + + 'symmetric key' is the raw key, not converted to a non-portable form + 'ctr_in' is the initial CTR value before possible truncation +*/ + +TPM_RESULT TPM_SymmetricKeyData_CtrCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + const unsigned char *symmetric_key, /* input */ + uint32_t symmetric_key_size, /* input */ + const unsigned char *ctr_in, /* input */ + uint32_t ctr_in_size) /* input */ +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = NULL; /* freed @1 */ + unsigned char ctr[TPM_AES_BLOCK_SIZE]; + + printf(" TPM_SymmetricKeyData_CtrCrypt: data_size %u\n", data_size); + /* allocate memory for the key token. The token is opaque in the API, but at this low level, + the code understands the TPM_SYMMETRIC_KEY_DATA structure */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_New((TPM_SYMMETRIC_KEY_TOKEN *)&tpm_symmetric_key_data); + } + /* convert the raw key to the AES key, truncating as required */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_SetKey(tpm_symmetric_key_data, + symmetric_key, + symmetric_key_size); + } + /* check the input CTR size, it can be truncated, but cannot be smaller than the AES key */ + if (rc == 0) { + if (ctr_in_size < sizeof(ctr)) { + printf(" TPM_SymmetricKeyData_CtrCrypt: Error (fatal)" + ", CTR size %u too small for AES key\n", ctr_in_size); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* make a truncated copy of CTR, since AES_ctr128_encrypt alters the value */ + memcpy(ctr, ctr_in, sizeof(ctr)); + printf(" TPM_SymmetricKeyData_CtrCrypt: Calling AES in CTR mode\n"); + TPM_PrintFour(" TPM_SymmetricKeyData_CtrCrypt: CTR", ctr); + rc = TPM_AES_ctr128_encrypt(data_out, + data_in, + data_size, + &(tpm_symmetric_key_data->aes_enc_key), + ctr); + } + TPM_SymmetricKeyData_Free((TPM_SYMMETRIC_KEY_TOKEN *)&tpm_symmetric_key_data); /* @1 */ + return rc; +} + +/* TPM_AES_ctr128_encrypt() is a TPM variant of the openSSL AES_ctr128_encrypt() function that + increments only the low 4 bytes of the counter. + + openSSL increments the entire CTR array. The TPM does not follow that convention. +*/ + +static TPM_RESULT TPM_AES_ctr128_encrypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t data_size, + const AES_KEY *aes_enc_key, + unsigned char ctr[TPM_AES_BLOCK_SIZE]) +{ + TPM_RESULT rc = 0; + uint32_t cint; + unsigned char pad_buffer[TPM_AES_BLOCK_SIZE]; /* the XOR pad */ + + printf(" TPM_AES_Ctr128_encrypt:\n"); + while (data_size != 0) { + printf(" TPM_AES_Ctr128_encrypt: data_size %lu\n", (unsigned long)data_size); + /* get an XOR pad array by encrypting the CTR with the AES key */ + AES_encrypt(ctr, pad_buffer, aes_enc_key); + /* partial or full last data block */ + if (data_size <= TPM_AES_BLOCK_SIZE) { + TPM_XOR(data_out, data_in, pad_buffer, data_size); + data_size = 0; + } + /* full block, not the last block */ + else { + TPM_XOR(data_out, data_in, pad_buffer, TPM_AES_BLOCK_SIZE); + data_in += TPM_AES_BLOCK_SIZE; + data_out += TPM_AES_BLOCK_SIZE; + data_size -= TPM_AES_BLOCK_SIZE; + } + /* if not the last block, increment CTR, only the low 4 bytes */ + if (data_size != 0) { + /* CTR is a big endian array, so the low 4 bytes are 12-15 */ + cint = LOAD32(ctr, 12); /* byte array to uint32_t */ + cint++; /* increment */ + STORE32(ctr, 12, cint); /* uint32_t to byte array */ + } + } + return rc; +} + +/* TPM_SymmetricKeyData_OfbCrypt() does an encrypt or decrypt (they are the same XOR operation with + a OFB mode pad) of 'data_in' to 'data_out' + + NOTE: This function looks general, but is currently hard coded to AES128. + + 'symmetric key' is the raw key, not converted to a non-portable form + 'ivec_in' is the initial IV value before possible truncation +*/ + +/* openSSL prototype + + void AES_ofb128_encrypt(const unsigned char *in, + unsigned char *out, + const unsigned long length, + const AES_KEY *key, + unsigned char *ivec, + int *num); +*/ + +TPM_RESULT TPM_SymmetricKeyData_OfbCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + const unsigned char *symmetric_key, /* in */ + uint32_t symmetric_key_size, /* in */ + unsigned char *ivec_in, /* input */ + uint32_t ivec_in_size) /* input */ +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = NULL; /* freed @1 */ + unsigned char ivec[TPM_AES_BLOCK_SIZE]; + int num; + + printf(" TPM_SymmetricKeyData_OfbCrypt: data_size %u\n", data_size); + /* allocate memory for the key token. The token is opaque in the API, but at this low level, + the code understands the TPM_SYMMETRIC_KEY_DATA structure */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_New((TPM_SYMMETRIC_KEY_TOKEN *)&tpm_symmetric_key_data); + } + /* convert the raw key to the AES key, truncating as required */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_SetKey(tpm_symmetric_key_data, + symmetric_key, + symmetric_key_size); + } + /* check the input OFB size, it can be truncated, but cannot be smaller than the AES key */ + if (rc == 0) { + if (ivec_in_size < sizeof(ivec)) { + printf(" TPM_SymmetricKeyData_OfbCrypt: Error (fatal)," + "IV size %u too small for AES key\n", ivec_in_size); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* make a truncated copy of IV, since AES_ofb128_encrypt alters the value */ + memcpy(ivec, ivec_in, sizeof(ivec)); + num = 0; + printf(" TPM_SymmetricKeyData_OfbCrypt: Calling AES in OFB mode\n"); + TPM_PrintFour(" TPM_SymmetricKeyData_OfbCrypt: IV", ivec); + AES_ofb128_encrypt(data_in, + data_out, + data_size, + &(tpm_symmetric_key_data->aes_enc_key), + ivec, + &num); + } + TPM_SymmetricKeyData_Free((TPM_SYMMETRIC_KEY_TOKEN *)&tpm_symmetric_key_data); + return rc; +} + +#endif /* TPM_AES */ diff --git a/src/tpm_crypto.h b/src/tpm_crypto.h new file mode 100644 index 00000000..6361a5dc --- /dev/null +++ b/src/tpm_crypto.h @@ -0,0 +1,219 @@ +/********************************************************************************/ +/* */ +/* Platform Dependent Crypto */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_crypto.h 4406 2011-02-08 22:11:37Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_CRYPTO_H +#define TPM_CRYPTO_H + +#include "tpm_secret.h" +#include "tpm_types.h" + +/* self test */ + +TPM_RESULT TPM_Crypto_Init(void); +TPM_RESULT TPM_Crypto_TestSpecific(void); + +/* random number */ + +TPM_RESULT TPM_Random(BYTE *buffer, size_t bytes); +TPM_RESULT TPM_StirRandomCmd(TPM_SIZED_BUFFER *inData); + +/* + bignum +*/ + +TPM_RESULT TPM_BN_num_bytes(unsigned int *numBytes, TPM_BIGNUM bn_in); +TPM_RESULT TPM_BN_is_one(TPM_BIGNUM bn_in); +TPM_RESULT TPM_BN_mod(TPM_BIGNUM rem_in, + const TPM_BIGNUM a_in, + const TPM_BIGNUM m_in); +TPM_RESULT TPM_BN_mask_bits(TPM_BIGNUM bn_in, unsigned int n); +TPM_RESULT TPM_BN_rshift(TPM_BIGNUM *rBignum_in, + TPM_BIGNUM aBignum_in, + int n); +TPM_RESULT TPM_BN_lshift(TPM_BIGNUM *rBignum_in, + TPM_BIGNUM aBignum_in, + int n); +TPM_RESULT TPM_BN_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in); +TPM_RESULT TPM_BN_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in); +TPM_RESULT TPM_BN_mod_exp(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM pBignum_in, + TPM_BIGNUM nBignum_in); +TPM_RESULT TPM_BN_mod_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in); +TPM_RESULT TPM_BN_mod_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in); + +TPM_RESULT TPM_bin2bn(TPM_BIGNUM *bn_in, + const unsigned char *bin, + unsigned int bytes); +TPM_RESULT TPM_bn2bin(unsigned char *bin, + TPM_BIGNUM bn_in); + +TPM_RESULT TPM_BN_new(TPM_BIGNUM *bn_in); +void TPM_BN_free(TPM_BIGNUM bn_in); + +/* RSA */ + +TPM_RESULT TPM_RSAGenerateKeyPair(unsigned char **n, + unsigned char **p, + unsigned char **q, + unsigned char **d, + int num_bit, + const unsigned char *earr, + uint32_t e_size); + +TPM_RESULT TPM_RSAPrivateDecrypt(unsigned char *decrypt_data, + uint32_t *decrypt_data_length, + size_t decrypt_data_size, + TPM_ENC_SCHEME encScheme, + unsigned char* encrypt_data, + uint32_t encrypt_data_size, + unsigned char *n, + uint32_t nbytes, + unsigned char *e, + uint32_t ebytes, + unsigned char *d, + uint32_t dbytes); + +TPM_RESULT TPM_RSAPublicEncrypt(unsigned char* encrypt_data, + size_t encrypt_data_size, + TPM_ENC_SCHEME encScheme, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); +TPM_RESULT TPM_RSAPublicEncryptRaw(unsigned char *encrypt_data, + uint32_t encrypt_data_size, + unsigned char *decrypt_data, + uint32_t decrypt_data_size, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); + +TPM_RESULT TPM_RSAGetPrivateKey(uint32_t *qbytes, unsigned char **qarr, + uint32_t *dbytes, unsigned char **darr, + uint32_t nbytes, unsigned char *narr, + uint32_t ebytes, unsigned char *earr, + uint32_t pbytes, unsigned char *parr); +TPM_RESULT TPM_RSASign(unsigned char *signature, + unsigned int *signature_length, + unsigned int signature_size, + TPM_SIG_SCHEME sigScheme, + const unsigned char *message, + size_t message_size, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes, + unsigned char *darr, + uint32_t dbytes); +TPM_RESULT TPM_RSAVerifySHA1(unsigned char *signature, + unsigned int signature_size, + const unsigned char *message, + uint32_t message_size, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); + +/* SHA-1 */ + +TPM_RESULT TPM_SHA1InitCmd(void **context); +TPM_RESULT TPM_SHA1UpdateCmd(void *context, const unsigned char *data, uint32_t length); +TPM_RESULT TPM_SHA1FinalCmd(unsigned char *md, void *context); +void TPM_SHA1Delete(void **context); + +/* SHA-1 Context */ + +TPM_RESULT TPM_Sha1Context_Load(void **context, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Sha1Context_Store(TPM_STORE_BUFFER *sbuffer, + void *context); + +/* + TPM_SYMMETRIC_KEY_DATA +*/ + +TPM_RESULT TPM_SymmetricKeyData_New(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data); +void TPM_SymmetricKeyData_Free(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data); +void TPM_SymmetricKeyData_Init(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token); +TPM_RESULT TPM_SymmetricKeyData_Load(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_SymmetricKeyData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token); +TPM_RESULT TPM_SymmetricKeyData_GenerateKey(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token); +TPM_RESULT TPM_SymmetricKeyData_Encrypt(unsigned char **encrypt_data, + uint32_t *encrypt_length, + const unsigned char *decrypt_data, + uint32_t decrypt_length, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token); +TPM_RESULT TPM_SymmetricKeyData_Decrypt(unsigned char **decrypt_data, + uint32_t *decrypt_length, + const unsigned char *encrypt_data, + uint32_t encrypt_length, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token); +TPM_RESULT TPM_SymmetricKeyData_CtrCrypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t data_size, + const unsigned char *symmetric_key, + uint32_t symmetric_key_size, + const unsigned char *ctr_in, + uint32_t ctr_in_size); +TPM_RESULT TPM_SymmetricKeyData_OfbCrypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t data_size, + const unsigned char *symmetric_key, + uint32_t symmetric_key_size, + unsigned char *ivec_in, + uint32_t ivec_in_size); +#endif diff --git a/src/tpm_crypto_freebl.c b/src/tpm_crypto_freebl.c new file mode 100644 index 00000000..c9f13c2b --- /dev/null +++ b/src/tpm_crypto_freebl.c @@ -0,0 +1,2648 @@ +/********************************************************************************/ +/* */ +/* Platform Dependent Crypto */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_crypto_freebl.c 4655 2011-12-21 21:03:15Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +/* This is the FreeBL implementation + + setenv CVSROOT :pserver:anonymous@cvsmirror.mozilla.org:/cvsroot + cvs co mosilla/nsprpub + gmake nss_build_all +*/ + +#include +#include +#include +#include + +#include "blapi.h" +#include + +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_io.h" +#include "tpm_load.h" +#include "tpm_memory.h" +#include "tpm_process.h" +#include "tpm_types.h" + +#include "tpm_crypto.h" + +/* The TPM OAEP encoding parameter */ +static const unsigned char tpm_oaep_pad_str[] = { 'T', 'C', 'P', 'A' }; + +/* pre-calculate hash of the constant tpm_oaep_pad_str, used often in the OAEP padding + calculations */ +static const unsigned char pHashConst[TPM_DIGEST_SIZE]; + +/* ASN.1 industry standard SHA1 with RSA object identifier */ +static unsigned char sha1Oid[] = { + 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, + 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, + 0x00, 0x04, 0x14}; + + +/* + local prototypes +*/ + +static void TPM_RSAPrivateKeyInit(RSAPrivateKey *rsa_pri_key); +static TPM_RESULT TPM_RSAGeneratePublicToken(RSAPublicKey *rsa_pub_key, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); +static TPM_RESULT TPM_RSAGeneratePrivateToken(RSAPrivateKey *rsa_pri_key, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes, + unsigned char *darr, + uint32_t dbytes); +static TPM_RESULT TPM_RSASignSHA1(unsigned char *signature, + unsigned int *signature_length, + const unsigned char *message, + size_t message_size, + RSAPrivateKey *rsa_pri_key); +static TPM_RESULT TPM_RSASignDER(unsigned char *signature, + unsigned int *signature_length, + const unsigned char *message, + size_t message_size, + RSAPrivateKey *rsa_pri_key); + +static TPM_RESULT TPM_RandomNonZero(BYTE *buffer, size_t bytes); + +static TPM_RESULT TPM_PKCS1_PaddingType1Add(unsigned char *output, + uint32_t outputLength, + const unsigned char *input, + uint32_t inputLength); +static TPM_RESULT TPM_PKCS1_PaddingType1Check(uint32_t *padLength, + unsigned char *input, + uint32_t inputLength); +static TPM_RESULT TPM_PKCS1_PaddingType2Add(unsigned char *encodedMessage, + uint32_t encodedMessageLength, + const unsigned char *message, + uint32_t messageLength); +static TPM_RESULT TPM_PKCS1_PaddingType2Check(unsigned char *outputData, + uint32_t *outputDataLength, + uint32_t outputDataSize, + unsigned char *inputData, + uint32_t inputDataLength); + +static TPM_RESULT TPM_memcpyPad(unsigned char **bin_out, + unsigned char *bin_in, + uint32_t bin_in_length, + uint32_t padBytes); + + +/* TPM_SYMMETRIC_KEY_DATA is a crypto library platform dependent symmetric key structure + */ + +#ifdef TPM_AES + +/* local prototype and structure for AES */ + +/* AES requires data lengths that are a multiple of the block size */ +#define TPM_AES_BITS 128 +/* The AES block size is always 16 bytes */ +#define TPM_AES_BLOCK_SIZE 16 + +/* Since the AES key is often derived by truncating the session shared secret, test that it's not + too large +*/ + +#if (TPM_AES_BLOCK_SIZE > TPM_SECRET_SIZE) +#error TPM_AES_BLOCK_SIZE larger than TPM_SECRET_SIZE +#endif + +/* The AES initial CTR value is derived from a nonce. */ + +#if (TPM_AES_BLOCK_SIZE > TPM_NONCE_SIZE) +#error TPM_AES_BLOCK_SIZE larger than TPM_NONCE_SIZE +#endif + +typedef struct tdTPM_SYMMETRIC_KEY_DATA { + TPM_TAG tag; + TPM_BOOL valid; + TPM_BOOL fill; + unsigned char userKey[TPM_AES_BLOCK_SIZE]; +} TPM_SYMMETRIC_KEY_DATA; + +#endif /* TPM_AES */ + +/* + Crypto library Initialization function +*/ + +TPM_RESULT TPM_Crypto_Init() +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + + printf("TPM_Crypto_Init: FreeBL library\n"); + /* initialize the random number generator */ + if (rc == 0) { + printf(" TPM_Crypto_Init: Initializing RNG\n"); + rv = RNG_RNGInit(); + if (rv != SECSuccess) { + printf("TPM_Crypto_Init: Error (fatal), RNG_RNGInit rv %d\n", rv); + rc = TPM_FAIL; + } + } + /* add additional seed entropy to the random number generator */ + if (rc == 0) { + printf(" TPM_Crypto_Init: Seeding RNG\n"); + RNG_SystemInfoForRNG(); + } + if (rc == 0) { + rv = BL_Init(); + if (rv != SECSuccess) { + printf("TPM_Crypto_Init: Error (fatal), BL_Init rv %d\n", rv); + rc =TPM_FAIL ; + } + } + /* pre-calculate hash of the constant tpm_oaep_pad_str, used often in the OAEP padding + calculations */ + if (rc == 0) { + rc = TPM_SHA1((unsigned char *)pHashConst, /* cast once to precalculate the constant */ + sizeof(tpm_oaep_pad_str), tpm_oaep_pad_str, + 0, NULL); + TPM_PrintFour("TPM_Crypto_Init: pHashConst", pHashConst); + } + return rc; +} + +/* TPM_Crypto_TestSpecific() performs any library specific tests + + For FreeBL +*/ + +TPM_RESULT TPM_Crypto_TestSpecific() +{ + TPM_RESULT rc = 0; + + /* Saving the SHA-1 context is fragile code, so test at startup */ + void *context1; + void *context2; + unsigned char buffer1[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + unsigned char expect1[] = {0x84,0x98,0x3E,0x44,0x1C, + 0x3B,0xD2,0x6E,0xBA,0xAE, + 0x4A,0xA1,0xF9,0x51,0x29, + 0xE5,0xE5,0x46,0x70,0xF1}; + TPM_DIGEST actual; + int not_equal; + TPM_STORE_BUFFER sbuffer; + const unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_Crypto_TestSpecific: Test 1 - SHA1 two parts\n"); + context1 = NULL; /* freed @1 */ + context2 = NULL; /* freed @2 */ + TPM_Sbuffer_Init(&sbuffer); /* freed @3 */ + + if (rc== 0) { + rc = TPM_SHA1InitCmd(&context1); /* freed @1 */ + } + /* digest the first part of the array */ + if (rc== 0) { + rc = TPM_SHA1UpdateCmd(context1, buffer1, 16); + } + /* store the SHA1 context */ + if (rc== 0) { + rc = TPM_Sha1Context_Store(&sbuffer, context1); + } + /* load the SHA1 context */ + if (rc== 0) { + TPM_Sbuffer_Get(&sbuffer, &stream, &stream_size); + rc = TPM_Sha1Context_Load + (&context2, (unsigned char **)&stream, &stream_size); /* freed @2 */ + } + /* digest the rest of the array */ + if (rc== 0) { + rc = TPM_SHA1UpdateCmd(context2, buffer1 + 16, sizeof(buffer1) - 17); + } + /* get the digest result */ + if (rc== 0) { + rc = TPM_SHA1FinalCmd(actual, context2); + } + /* check the result */ + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_Crypto_TestSpecific: Error in test 1\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + TPM_SHA1Delete(&context1); /* @1 */ + TPM_SHA1Delete(&context2); /* @2 */ + TPM_Sbuffer_Delete(&sbuffer); /* @3 */ + return rc; +} + +/* + Random Number Functions +*/ + +/* TPM_Random() fills 'buffer' with 'bytes' bytes. + */ + +TPM_RESULT TPM_Random(BYTE *buffer, size_t bytes) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + + printf(" TPM_Random: Requesting %lu bytes\n", (unsigned long)bytes); + /* generate the random bytes */ + if (rc == 0) { + rv = RNG_GenerateGlobalRandomBytes(buffer, bytes); + if (rv != SECSuccess) { + printf("TPM_Random: Error (fatal) in RNG_GenerateGlobalRandomBytes rv %d\n", rv); + rc = TPM_FAIL; + } + } + return rc; +} + +/* TPM_Random() fills 'buffer' with 'bytes' non-zero bytes + + This is used for PKCS padding. +*/ + +static TPM_RESULT TPM_RandomNonZero(BYTE *buffer, size_t bytes) +{ + TPM_RESULT rc = 0; + size_t i; + SECStatus rv = SECSuccess; + + printf(" TPM_RandomNonZero: Requesting %lu bytes\n", (unsigned long)bytes); + for (i = 0 ; (rc == 0) && (i < bytes) ; ) { + rv = RNG_GenerateGlobalRandomBytes(buffer, 1); + if (rv != SECSuccess) { + printf("TPM_Random: Error (fatal) in RNG_GenerateGlobalRandomBytes rv %d\n", rv); + rc = TPM_FAIL; + } + else { + if (*buffer != 0x00) { + buffer++; + i++; + } + } + } + return rc; +} + +/* TPM_StirRandomCmd() adds the supplied entropy to the random number generator + */ + +TPM_RESULT TPM_StirRandomCmd(TPM_SIZED_BUFFER *inData) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + + printf(" TPM_StirRandomCmd:\n"); + if (rc == 0) { + /* add the seeding material */ + rv = RNG_RandomUpdate(inData->buffer, inData->size); + if (rv != SECSuccess) { + printf("TPM_StirRandom: Error (fatal) in RNG_RandomUpdate rv %d\n", rv); + rc = TPM_FAIL; + } + } + return rc; +} + +/* + RSA Functions +*/ + +/* TPM_RSAPrivateKeyInit() NULLs all the structure members in preparation for constructing an RSA + key token from byte arrays using RSA_PopulatePrivateKey() +*/ + +static void TPM_RSAPrivateKeyInit(RSAPrivateKey *rsa_pri_key) +{ + rsa_pri_key->arena = NULL; + rsa_pri_key->publicExponent.type = siBuffer; + rsa_pri_key->publicExponent.data = NULL; + rsa_pri_key->publicExponent.len = 0; + rsa_pri_key->modulus.type = siBuffer; + rsa_pri_key->modulus.data = NULL; + rsa_pri_key->modulus.len = 0; + rsa_pri_key->privateExponent.type = siBuffer; + rsa_pri_key->privateExponent.data = NULL; + rsa_pri_key->privateExponent.len = 0; + rsa_pri_key->prime1.type = siBuffer; + rsa_pri_key->prime1.data = NULL; + rsa_pri_key->prime1.len = 0; + rsa_pri_key->prime2.type = siBuffer; + rsa_pri_key->prime2.data = NULL; + rsa_pri_key->prime2.len = 0; + rsa_pri_key->exponent1.type = siBuffer; + rsa_pri_key->exponent1.data = NULL; + rsa_pri_key->exponent1.len = 0; + rsa_pri_key->exponent2.type = siBuffer; + rsa_pri_key->exponent2.data = NULL; + rsa_pri_key->exponent2.len = 0; + rsa_pri_key->coefficient.type = siBuffer; + rsa_pri_key->coefficient.data = NULL; + rsa_pri_key->coefficient.len = 0; + return; +} + +/* Generate an RSA key pair of size 'num_bits' using public exponent 'earr' + + 'n', 'p', 'q', 'd' must be freed by the caller +*/ + +TPM_RESULT TPM_RSAGenerateKeyPair(unsigned char **n, /* public key - modulus */ + unsigned char **p, /* private key prime */ + unsigned char **q, /* private key prime */ + unsigned char **d, /* private key (private exponent) */ + int num_bits, /* key size in bits */ + const unsigned char *earr, /* public exponent as an array */ + uint32_t e_size) +{ + TPM_RESULT rc = 0; + SECItem publicExponent = { 0, 0, 0}; + RSAPrivateKey *rsaPrivateKey = NULL; /* freed @1 */ + unsigned long e; /* public exponent */ + + printf(" TPM_RSAGenerateKeyPair:\n"); + /* initialize in case of error */ + *n = NULL; + *p = NULL; + *q = NULL; + *d = NULL; + /* check that num_bits is a multiple of 16. If not, the primes p and q will not be a multiple + of 8 and will not fit well in a byte */ + if (rc == 0) { + if ((num_bits % 16) != 0) { + printf("TPM_RSAGenerateKeyPair: Error, num_bits %d is not a multiple of 16\n", + num_bits); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* convert the e array to an unsigned long */ + if (rc == 0) { + rc = TPM_LoadLong(&e, earr, e_size); + } + /* validate the public exponent against a list of legal values. Some values (e.g. even numbers) + can hang the key generator. */ + if (rc == 0) { + rc = TPM_RSA_exponent_verify(e); + } + /* generate the key pair */ + if (rc == 0) { + printf(" TPM_RSAGenerateKeyPair: num_bits %d exponent %08lx\n", num_bits, e); + publicExponent.type = siBuffer; + publicExponent.data = (unsigned char *)earr; + publicExponent.len = e_size; + /* Generate and return a new RSA public and private key token */ + rsaPrivateKey = RSA_NewKey(num_bits, &publicExponent); /* freed @1 */ + if (rsaPrivateKey == NULL) { + printf("TPM_RSAGenerateKeyPair: Error (fatal) calling RSA_NewKey()\n"); + rc = TPM_FAIL; + } + } + /* Key parts can some times have leading zeros, and some crypto libraries truncate. However, + the TPM expects fixed lengths. These calls restore any removed padding */ + /* load n */ + if (rc == 0) { + rc = TPM_memcpyPad(n, /* freed by caller */ + rsaPrivateKey->modulus.data, + rsaPrivateKey->modulus.len, + num_bits/8); /* required length */ + } + /* load p */ + if (rc == 0) { + rc = TPM_memcpyPad(p, /* freed by caller */ + rsaPrivateKey->prime1.data, + rsaPrivateKey->prime1.len, + num_bits/16); /* required length */ + } + /* load q */ + if (rc == 0) { + rc = TPM_memcpyPad(q, /* freed by caller */ + rsaPrivateKey->prime2.data, + rsaPrivateKey->prime2.len, + num_bits/16); /* required length */ + } + /* load d */ + if (rc == 0) { + rc = TPM_memcpyPad(d, /* freed by caller */ + rsaPrivateKey->privateExponent.data, + rsaPrivateKey->privateExponent.len, + num_bits/8); /* required length */ + } + /* on error, free the components and set back to NULL so subsequent free is safe */ + if (rc != 0) { + free(*n); + free(*p); + free(*q); + free(*d); + *n = NULL; + *p = NULL; + *q = NULL; + *d = NULL; + } + if (rsaPrivateKey != NULL) { + PORT_FreeArena(rsaPrivateKey->arena, PR_TRUE); /* @1 */ + } + return rc; +} + +/* TPM_RSAGeneratePublicToken() generates an RSA key token from n and e + */ + +static TPM_RESULT TPM_RSAGeneratePublicToken(RSAPublicKey *rsaPublicKey, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + + /* simply assign the arrays to the key token */ + if (rc == 0) { + printf(" TPM_RSAGeneratePublicToken: nbytes %u ebytes %u\n", nbytes, ebytes); + rsaPublicKey->arena = NULL; + /* public modulus */ + rsaPublicKey->modulus.type = siBuffer; + rsaPublicKey->modulus.data = narr; + rsaPublicKey->modulus.len = nbytes; + /* public exponent */ + rsaPublicKey->publicExponent.type = siBuffer; + rsaPublicKey->publicExponent.data = earr; + rsaPublicKey->publicExponent.len = ebytes; + } + return rc; +} + +/* TPM_RSAGeneratePrivateToken() generates an RSA key token from n, e, d + */ + +static TPM_RESULT TPM_RSAGeneratePrivateToken(RSAPrivateKey *rsa_pri_key, /* freed by caller */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + + printf(" TPM_RSAGeneratePrivateToken:\n"); + if (rc == 0) { + rsa_pri_key->arena = NULL; + /* public exponent */ + rsa_pri_key->publicExponent.type = siBuffer; + rsa_pri_key->publicExponent.data = earr; + rsa_pri_key->publicExponent.len = ebytes; + /* public modulus */ + rsa_pri_key->modulus.type = siBuffer; + rsa_pri_key->modulus.data = narr; + rsa_pri_key->modulus.len = nbytes; + /* private exponent */ + rsa_pri_key->privateExponent.type = siBuffer; + rsa_pri_key->privateExponent.data = darr; + rsa_pri_key->privateExponent.len = dbytes; + /* given these key parameters (n,e,d), fill in the rest of the parameters */ + rv = RSA_PopulatePrivateKey(rsa_pri_key); /* freed by caller */ + if (rv != SECSuccess) { + printf("TPM_RSAGeneratePrivateToken: Error, RSA_PopulatePrivateKey rv %d\n", rv); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_RSAPrivateDecrypt() decrypts 'encrypt_data' using the private key 'n, e, d'. The OAEP + padding is removed and 'decrypt_data_length' bytes are moved to 'decrypt_data'. + + 'decrypt_data_length' is at most 'decrypt_data_size'. +*/ + +TPM_RESULT TPM_RSAPrivateDecrypt(unsigned char *decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + size_t decrypt_data_size, /* size of decrypt_data buffer */ + TPM_ENC_SCHEME encScheme, /* encryption scheme */ + unsigned char* encrypt_data, /* encrypted data */ + uint32_t encrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + RSAPrivateKey rsa_pri_key; + unsigned char *padded_data = NULL; /* freed @2 */ + int padded_data_size = 0; + + printf(" TPM_RSAPrivateDecrypt: Input data size %u\n", encrypt_data_size); + TPM_RSAPrivateKeyInit(&rsa_pri_key); /* freed @1 */ + /* the encrypted data size must equal the public key size */ + if (rc == 0) { + if (encrypt_data_size != nbytes) { + printf("TPM_RSAPrivateDecrypt: Error, Encrypted data size is %u not %u\n", + encrypt_data_size, nbytes); + rc = TPM_DECRYPT_ERROR; + } + } + /* construct the freebl private key object from n,e,d */ + if (rc == 0) { + rc = TPM_RSAGeneratePrivateToken(&rsa_pri_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + /* allocate intermediate buffer for the decrypted but still padded data */ + if (rc == 0) { + /* the size of the decrypted data is guaranteed to be less than this */ + padded_data_size = rsa_pri_key.modulus.len; + rc = TPM_Malloc(&padded_data, padded_data_size); /* freed @2 */ + } + if (rc == 0) { + /* decrypt with private key. Must decrypt first and then remove padding because the decrypt + call cannot specify an encoding parameter */ + rv = RSA_PrivateKeyOp(&rsa_pri_key, /* private key token */ + padded_data, /* to - the decrypted but padded data */ + encrypt_data); /* from - the encrypted data */ + if (rv != SECSuccess) { + printf("TPM_RSAPrivateDecrypt: Error in RSA_PrivateKeyOp(), rv %d\n", rv); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + printf(" TPM_RSAPrivateDecrypt: RSA_PrivateKeyOp() success\n"); + printf(" TPM_RSAPrivateDecrypt: Padded data size %u\n", padded_data_size); + TPM_PrintFour(" TPM_RSAPrivateDecrypt: Decrypt padded data", padded_data); + /* check and remove the padding based on the TPM encryption scheme */ + if (encScheme == TPM_ES_RSAESOAEP_SHA1_MGF1) { + /* recovered seed and pHash are not returned */ + unsigned char seed[TPM_DIGEST_SIZE]; + unsigned char pHash[TPM_DIGEST_SIZE]; + if (rc == 0) { + /* the padded data skips the first 0x00 byte, since it expects the + padded data to come from a truncated bignum */ + rc = TPM_RSA_padding_check_PKCS1_OAEP(decrypt_data, /* to */ + decrypt_data_length, /* to length */ + decrypt_data_size, /* to buffer size */ + padded_data + 1, /* from */ + padded_data_size - 1, /* from length */ + pHash, /* 20 bytes */ + seed); /* 20 bytes */ + } + } + else if (encScheme == TPM_ES_RSAESPKCSv15) { + rc = TPM_PKCS1_PaddingType2Check(decrypt_data, /* to */ + decrypt_data_length, /* to length */ + decrypt_data_size, /* to buffer size*/ + padded_data, /* from */ + padded_data_size); /* from length */ + } + else { + printf("TPM_RSAPrivateDecrypt: Error, unknown encryption scheme %04x\n", encScheme); + rc = TPM_INAPPROPRIATE_ENC; + } + } + if (rc == 0) { + printf(" TPM_RSAPrivateDecrypt: RSA_padding_check_PKCS1 recovered %d bytes\n", + *decrypt_data_length); + TPM_PrintFour(" TPM_RSAPrivateDecrypt: Decrypt data", decrypt_data); + } + PORT_FreeArena(rsa_pri_key.arena, PR_TRUE); /* @1 */ + free(padded_data); /* @2 */ + return rc; +} + +/* TPM_RSAPublicEncrypt() PKCS1 pads 'decrypt_data' to 'encrypt_data_size' and encrypts using the + public key 'n, e'. +*/ + +TPM_RESULT TPM_RSAPublicEncrypt(unsigned char *encrypt_data, /* encrypted data */ + size_t encrypt_data_size, /* size of encrypted data buffer */ + TPM_ENC_SCHEME encScheme, /* padding type */ + const unsigned char *decrypt_data, /* decrypted data */ + size_t decrypt_data_size, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + unsigned char *padded_data = NULL; /* freed @1 */ + + printf(" TPM_RSAPublicEncrypt: Input data size %lu\n", (unsigned long)decrypt_data_size); + /* intermediate buffer for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&padded_data, encrypt_data_size); /* freed @1 */ + } + /* pad the decrypted data */ + if (rc == 0) { + /* based on the TPM encryption scheme */ + if (encScheme == TPM_ES_RSAESOAEP_SHA1_MGF1) { + unsigned char seed[TPM_DIGEST_SIZE]; + if (rc == 0) { + rc = TPM_Random(seed, TPM_DIGEST_SIZE); + } + if (rc == 0) { + padded_data[0] = 0x00; + rc = TPM_RSA_padding_add_PKCS1_OAEP(padded_data +1, /* to */ + encrypt_data_size -1, /* to length */ + decrypt_data, /* from */ + decrypt_data_size, /* from length */ + pHashConst, /* 20 bytes */ + seed); /* 20 bytes */ + } + } + else if (encScheme == TPM_ES_RSAESPKCSv15) { + rc = TPM_PKCS1_PaddingType2Add(padded_data, /* to */ + encrypt_data_size, /* to length */ + decrypt_data, /* from */ + decrypt_data_size); /* from length */ + } + else { + printf("TPM_RSAPublicEncrypt: Error, unknown encryption scheme %04x\n", encScheme); + rc = TPM_INAPPROPRIATE_ENC; + } + } + /* raw public key operation on the already padded input data */ + if (rc == 0) { + rc = TPM_RSAPublicEncryptRaw(encrypt_data, /* output */ + encrypt_data_size, /* input, size of enc buffer */ + padded_data, /* input */ + encrypt_data_size, /* input, size of dec buffer */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + free(padded_data); /* @1 */ + return rc; +} + +/* TPM_RSAPublicEncryptRaw() does a raw public key operation without any padding. + +*/ + +TPM_RESULT TPM_RSAPublicEncryptRaw(unsigned char *encrypt_data, /* output */ + uint32_t encrypt_data_size, /* input, size of enc buffer */ + unsigned char *decrypt_data, /* input */ + uint32_t decrypt_data_size, /* input, size of dec buffer */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + RSAPublicKey rsa_pub_key; + + printf(" TPM_RSAPublicEncryptRaw:\n"); + /* the input data size must equal the public key size (already padded) */ + if (rc == 0) { + if (decrypt_data_size != nbytes) { + printf("TPM_RSAPublicEncryptRaw: Error, decrypt data size is %u not %u\n", + decrypt_data_size, nbytes); + rc = TPM_ENCRYPT_ERROR; + } + } + /* the output data size must equal the public key size */ + if (rc == 0) { + if (encrypt_data_size != nbytes) { + printf("TPM_RSAPublicEncryptRaw: Error, Output data size is %u not %u\n", + decrypt_data_size, nbytes); + rc = TPM_ENCRYPT_ERROR; + } + } + /* construct the freebl public key object */ + if (rc == 0) { + rc = TPM_RSAGeneratePublicToken(&rsa_pub_key, /* freebl public key token */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncryptRaw: Public modulus", narr); + TPM_PrintAll(" TPM_RSAPublicEncryptRaw: Public exponent", earr, ebytes); + TPM_PrintFour(" TPM_RSAPublicEncryptRaw: Decrypt data", decrypt_data); + /* raw public key operation, encrypt the decrypt_data */ + rv = RSA_PublicKeyOp(&rsa_pub_key, /* freebl public key token */ + encrypt_data, /* output - the encrypted data */ + decrypt_data); /* input - the clear text data */ + if (rv != SECSuccess) { + printf("TPM_RSAPublicEncrypt: Error in RSA_PublicKeyOp, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncryptRaw: Encrypt data", encrypt_data); +#if 0 /* NOTE: Uncomment as a debug aid for signature verification */ + TPM_PrintAll(" TPM_RSAPublicEncryptRaw: Encrypt data", + encrypt_data, encrypt_data_size); +#endif + } + return rc; +} + +/* TPM_RSASign() signs 'message' of size 'message_size' using the private key n,e,d and the + signature scheme 'sigScheme' as specified in PKCS #1 v2.0. + + 'signature_length' bytes are moved to 'signature'. 'signature_length' is at most + 'signature_size'. signature must point to bytes of memory equal to the public modulus size. +*/ + +TPM_RESULT TPM_RSASign(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + unsigned int signature_size, /* input, size of signature buffer */ + TPM_SIG_SCHEME sigScheme, /* input, type of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes, + unsigned char *darr, /* private exponent */ + uint32_t dbytes) +{ + TPM_RESULT rc = 0; + RSAPrivateKey rsa_pri_key; + + printf(" TPM_RSASign:\n"); + TPM_RSAPrivateKeyInit(&rsa_pri_key); /* freed @1 */ + /* construct the free private key object from n,e,d */ + if (rc == 0) { + rc = TPM_RSAGeneratePrivateToken(&rsa_pri_key, /* freed @1 */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + /* sanity check the size of the output signature buffer */ + if (rc == 0) { + if (signature_size < nbytes) { + printf("TPM_RSASign: Error (fatal), buffer %u too small for signature %u\n", + signature_size, nbytes); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + /* determine the signature scheme for the key */ + if (rc == 0) { + switch(sigScheme) { + case TPM_SS_NONE: + printf("TPM_RSASign: Error, sigScheme TPM_SS_NONE\n"); + rc = TPM_INVALID_KEYUSAGE; + break; + case TPM_SS_RSASSAPKCS1v15_SHA1: + case TPM_SS_RSASSAPKCS1v15_INFO: + rc = TPM_RSASignSHA1(signature, + signature_length, + message, + message_size, + &rsa_pri_key); + break; + case TPM_SS_RSASSAPKCS1v15_DER: + rc = TPM_RSASignDER(signature, + signature_length, + message, + message_size, + &rsa_pri_key); + break; + default: + printf("TPM_RSASign: Error, sigScheme %04hx unknown\n", sigScheme); + rc = TPM_INVALID_KEYUSAGE; + break; + } + } + PORT_FreeArena(rsa_pri_key.arena, PR_TRUE); /* @1 */ + return rc; +} + +/* TPM_RSASignSHA1() performs the following: + prepend a DER encoded algorithm ID (SHA1 and RSA) + prepend a type 1 pad + encrypt with the private key +*/ + +static TPM_RESULT TPM_RSASignSHA1(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + RSAPrivateKey *rsa_pri_key) /* signing private key */ +{ + TPM_RESULT rc = 0; + unsigned char *message_der; /* DER padded message, freed @1 */ + + printf(" TPM_RSASignSHA1: key size %d\n", rsa_pri_key->modulus.len); + message_der = NULL; /* freed @1 */ + /* sanity check, SHA1 messages must be 20 bytes */ + if (rc == 0) { + if (message_size != TPM_DIGEST_SIZE) { + printf("TPM_RSASignSHA1: Error, message size %lu not TPM_DIGEST_SIZE\n", + (unsigned long)message_size ); + rc = TPM_DECRYPT_ERROR; + } + } + /* allocate memory for the DER padded message */ + if (rc == 0) { + rc = TPM_Malloc(&message_der, sizeof(sha1Oid) + message_size); /* freed @1 */ + } + if (rc == 0) { + /* copy the OID */ + memcpy(message_der, sha1Oid, sizeof(sha1Oid)); + /* copy the message */ + memcpy(message_der + sizeof(sha1Oid), message, message_size); + /* sign the DER padded message */ + rc = TPM_RSASignDER(signature, /* output */ + signature_length, /* output, size of signature */ + message_der, /* input */ + sizeof(sha1Oid) + message_size, /* input */ + rsa_pri_key); /* signing private key */ + } + free(message_der); /* @1 */ + return rc; +} + +/* TPM_RSASignDER() performs the following: + + prepend a PKCS1 type 1 pad + encrypt with the private key + + The caller must ensure that the signature buffer is >= the key size. +*/ + +static TPM_RESULT TPM_RSASignDER(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + RSAPrivateKey *rsa_pri_key) /* signing private key */ +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + unsigned char *message_pad; /* PKCS1 type 1 padded message, freed @1 */ + + printf(" TPM_RSASignDER: key size %d\n", rsa_pri_key->modulus.len); + message_pad = NULL; /* freed @1 */ + /* the padded message size is the same as the key size */ + /* allocate memory for the padded message */ + if (rc == 0) { + rc = TPM_Malloc(&message_pad, rsa_pri_key->modulus.len); /* freed @1 */ + } + /* PKCS1 type 1 pad the message */ + if (rc == 0) { + printf(" TPM_RSASignDER: Applying PKCS1 type 1 padding, size from %lu to %u\n", + (unsigned long)message_size, rsa_pri_key->modulus.len); + TPM_PrintFour(" TPM_RSASignDER: Input message", message); + /* This call checks that the message will fit with the padding */ + rc = TPM_PKCS1_PaddingType1Add(message_pad, /* to */ + rsa_pri_key->modulus.len, /* to length */ + message, /* from */ + message_size); /* from length */ + } + /* raw sign with private key */ + if (rc == 0) { + printf(" TPM_RSASignDER: Encrypting with private key, message size %d\n", + rsa_pri_key->modulus.len); + TPM_PrintFour(" TPM_RSASignDER: Padded message", message_pad); + /* sign with private key */ + rv = RSA_PrivateKeyOp(rsa_pri_key, /* freebl key token */ + signature, /* to - the decrypted but padded data */ + message_pad); /* from - the encrypted data */ + if (rv != SECSuccess) { + printf("TPM_RSASignDER: Error in RSA_PrivateKeyOp(), rv %d\n", rv); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSASignDER: signature", signature); + *signature_length = rsa_pri_key->modulus.len; + } + free(message_pad); /* @1 */ + return rc; +} + +/* TPM_RSAVerifySHA1() performs the following: + decrypt the signature + verify and remove type 1 pad + verify and remove DER encoded algorithm ID + verify the signature on the message +*/ + +TPM_RESULT TPM_RSAVerifySHA1(unsigned char *signature, /* input */ + unsigned int signature_size, /* input, size of signature + buffer */ + const unsigned char *message, /* input */ + uint32_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + unsigned char *padded_data = NULL; /* decrypted signature, freed @1 */ + uint32_t padLength; + int irc; + + printf(" TPM_RSAVerifySHA1:\n"); + /* allocate memory for the padded result of the public key operation */ + if (rc == 0) { + rc = TPM_Malloc(&padded_data, nbytes); /* freed @1 */ + } + /* do a raw encrypt of the signature */ + if (rc == 0) { + rc = TPM_RSAPublicEncryptRaw(padded_data, /* output */ + nbytes, /* input, size of message buffer */ + signature, /* input */ + signature_size, /* input, size of signature buffer */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + /* check PKCS1 padding and OID */ + if (rc == 0) { + rc = TPM_PKCS1_PaddingType1Check(&padLength, /* length of the PKCS1 padd and OID */ + padded_data, /* input data */ + nbytes); /* input data length */ + } + /* check message length */ + if (rc == 0) { + if (message_size != (nbytes - padLength)) { + printf("TPM_RSAVerifySHA1: Error, " + "message size %u not equal to size %u after padding removed\n", + message_size, nbytes - padLength); + rc = TPM_BAD_SIGNATURE; + } + } + /* check message */ + if (rc == 0) { + irc = memcmp(message, padded_data + padLength, message_size); + if (irc != 0) { + printf("TPM_RSAVerifySHA1: Error, message mismatch\n"); + TPM_PrintFour(" TPM_RSAVerifySHA1: message", message); + TPM_PrintFour(" TPM_RSAVerifySHA1: message from signature", padded_data + padLength); + rc = TPM_BAD_SIGNATURE; + } + } + /* public encrypt is general, here we're doing a signature check, so adjust the error message */ + else { + rc = TPM_BAD_SIGNATURE; + } + free(padded_data); /* @1 */ + return rc; +} + +/* TPM_RSAGetPrivateKey calculates q (2nd prime factor) and d (private key) from n (public key), e + (public exponent), and p (1st prime factor) + + 'qarr', darr' must be freed by the caller. +*/ + +TPM_RESULT TPM_RSAGetPrivateKey(uint32_t *qbytes, unsigned char **qarr, + uint32_t *dbytes, unsigned char **darr, + uint32_t nbytes, unsigned char *narr, + uint32_t ebytes, unsigned char *earr, + uint32_t pbytes, unsigned char *parr) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + RSAPrivateKey rsa_pri_key; + + /* set to NULL so caller can free after failure */ + printf(" TPM_RSAGetPrivateKey:\n"); + TPM_RSAPrivateKeyInit(&rsa_pri_key); /* freed @1 */ + *qarr = NULL; + *darr = NULL; + /* check input parameters */ + if (rc == 0) { + if ((narr == NULL) || (nbytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing n\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* check input parameters */ + if (rc == 0) { + if ((earr == NULL) || (ebytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing e\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* check input parameters */ + if (rc == 0) { + if ((parr == NULL) || (pbytes == 0)) { + printf("TPM_RSAGetPrivateKey: Error, missing p\n"); + rc = TPM_BAD_PARAMETER; + } + } + /* populate the private key token with n, e, p */ + if (rc == 0) { + rsa_pri_key.publicExponent.type = siBuffer; + rsa_pri_key.publicExponent.data = earr; + rsa_pri_key.publicExponent.len = ebytes; + rsa_pri_key.modulus.type = siBuffer; + rsa_pri_key.modulus.data = narr; + rsa_pri_key.modulus.len = nbytes; + rsa_pri_key.prime1.type = siBuffer; + rsa_pri_key.prime1.data = parr; + rsa_pri_key.prime1.len = pbytes; + /* fill in the rest of the freebl key token parameters. */ + rv = RSA_PopulatePrivateKey(&rsa_pri_key); /* freed @1 */ + if (rv != SECSuccess) { + printf("TPM_RSAGetPrivateKey: Error in RSA_PopulatePrivateKey rv %d\n", rv); + rc = TPM_BAD_PARAMETER; + } + } + /* extract and pad q */ + if (rc == 0) { + rc = TPM_memcpyPad(qarr, /* freed by caller */ + rsa_pri_key.prime2.data, rsa_pri_key.prime2.len, + pbytes); /* pad to p prime */ + *qbytes = pbytes; + } + /* extract and pad d */ + if (rc == 0) { + rc = TPM_memcpyPad(darr, /* freed by caller */ + rsa_pri_key.privateExponent.data, rsa_pri_key.privateExponent.len, + nbytes); /* pad to public modulus */ + *dbytes = nbytes; + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAGetPrivateKey: Calculated q", *qarr); + TPM_PrintFour(" TPM_RSAGetPrivateKey: Calculated d", *darr); + printf(" TPM_RSAGetPrivateKey: length of n,p,q,d = %u / %u / %u / %u\n", + nbytes, pbytes, *qbytes, *dbytes); + } + PORT_FreeArena(rsa_pri_key.arena, PR_TRUE); /* @1 */ + return rc; +} + +/* + PKCS1 Padding Functions +*/ + +/* TPM_PKCS1_PaddingType1Add() adds PKCS1 type 1 padding. + + The output buffer is preallocated. +*/ + +static TPM_RESULT TPM_PKCS1_PaddingType1Add(unsigned char *output, /* to */ + uint32_t outputLength, + const unsigned char *input, /* from */ + uint32_t inputLength) +{ + TPM_RESULT rc = 0; + uint32_t psLength; + uint32_t index; + + /* sanity check the length, this should never fail */ + printf(" TPM_PKCS1_PaddingType1Add:\n"); + if (rc == 0) { + if ((inputLength + 11) > outputLength) { + printf("TPM_PKCS1_PaddingType1Add: Error, input %u too big for output %u\n", + inputLength, outputLength); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + index = 0; + /* psLength is the number of 0xff bytes, subtract 3 for the leading 00,01 and trailing 00 */ + psLength = outputLength - inputLength - 3; + + /* add the PKCS1 pad 01 || PS || 00 || T where PS is at least 8 0xff bytes */ + /* PKCS1 pads to k-1 bytes, implies a leading 0 */ + output[index] = 0x00; + index++; + + output[index] = 0x01; + index++; + + memset(output + index, 0xff, psLength); + index += psLength; + + output[index] = 0x00; + index++; + + /* add the input data */ + memcpy(output + index, input, inputLength); + index += inputLength; + } + return rc; +} + +/* TPM_PKCS1_PaddingType1Check() checks PKCS1 type 1 padding and the SHA1withRSA OID + and returns their length + + Type 1 is: 00 01 FF's 00 OID message +*/ + +static TPM_RESULT TPM_PKCS1_PaddingType1Check(uint32_t *padLength, + unsigned char *input, + uint32_t inputLength) +{ + TPM_RESULT rc = 0; + int irc; + + printf(" TPM_PKCS1_PaddingType1Check:\n"); + /* sanity check the length */ + if (rc == 0) { + if ((sizeof(sha1Oid) + 11) > inputLength) { + printf("TPM_PKCS1_PaddingType1Check: Error, " + "sizeof(sha1Oid) %lu + 11 > inputLength %u\n", + (unsigned long)sizeof(sha1Oid), inputLength); + rc = TPM_ENCRYPT_ERROR; + } + } + /* check byte 0 */ + if (rc == 0) { + *padLength = 0; + if (input[*padLength] != 0x00) { + printf("TPM_PKCS1_PaddingType1Check: Error, byte %u %02x not 0x00\n", + *padLength, input[*padLength]); + rc = TPM_ENCRYPT_ERROR; + } + (*padLength)++; + } + /* check byte 1 */ + if (rc == 0) { + if (input[*padLength] != 0x01) { + printf("TPM_PKCS1_PaddingType1Check: Error, byte %u %02x not 0x01\n", + *padLength, input[*padLength]); + rc = TPM_ENCRYPT_ERROR; + } + (*padLength)++; + } + /* check for at least 8 0xff bytes */ + for ( ; (rc == 0) && (*padLength < 10) ; (*padLength)++) { + if (input[*padLength] != 0xff) { + printf("TPM_PKCS1_PaddingType1Check: Error, byte %u %02x not 0xff\n", + *padLength, input[*padLength]); + rc = TPM_ENCRYPT_ERROR; + } + } + /* check for more 0xff bytes */ + for ( ; (rc == 0) && (*padLength < inputLength) ; (*padLength)++) { + if (input[*padLength] != 0xff) { + break; + } + } + /* check for 0x00 byte */ + if (rc == 0) { + if (input[*padLength] != 0x00) { + printf("TPM_PKCS1_PaddingType1Check: Error, byte %u %02x not 0x00\n", + *padLength, input[*padLength]); + rc = TPM_ENCRYPT_ERROR; + } + (*padLength)++; + } + /* check length for OID */ + if (rc == 0) { + if (*padLength + sizeof(sha1Oid) > inputLength) { + printf("TPM_PKCS1_PaddingType1Check: Error, " + "padLength %u + sizeof(sha1Oid) %lu > inputLength %u\n", + *padLength, (unsigned long)sizeof(sha1Oid), inputLength); + rc = TPM_ENCRYPT_ERROR; + } + } + /* check OID */ + if (rc == 0) { + irc = memcmp(input + *padLength, sha1Oid, sizeof(sha1Oid)); + if (irc != 0) { + printf("TPM_PKCS1_PaddingType1Check: Error, OID mismatch\n"); + TPM_PrintAll(" TPM_PKCS1_PaddingType1Check: OID", + input + *padLength, sizeof(sha1Oid)); + rc = TPM_ENCRYPT_ERROR; + } + *padLength += sizeof(sha1Oid); + } + return rc; +} + +/* TPM_PKCS1_PaddingType2Add() adds the PKCS1 type 2 padding + + The output buffer is preallocated. + + See PKCS1 9.1.2.1 Encoding operation + + This method cheats a bit by adding a leading 00 as well, which is needed for the RSA operation. + + M message to be encoded, an octet string of length at most emLen-10 + emLen intended length in octets of the encoded message + + Output: + EM encoded message, an octet string of length emLen; or "message too long" +*/ + +static TPM_RESULT TPM_PKCS1_PaddingType2Add(unsigned char *encodedMessage, /* to */ + uint32_t encodedMessageLength, /* to length */ + const unsigned char *message, /* from */ + uint32_t messageLength) /* from length */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_PKCS1_PaddingType2Add: Message length %u padded length %u\n", + messageLength, encodedMessageLength); + /* 1. If the length of the message M is greater than emLen - 10 octets, output "message too + long" and stop. */ + if (rc == 0) { + if ((messageLength + 11) > encodedMessageLength) { + printf("TPM_PKCS1_PaddingType2Add: Error, message length too big for padded length\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + /* 2. Generate an octet string PS of length emLen-||M||-2 consisting of pseudorandomly generated + nonzero octets. The length of PS will be at least 8 octets. */ + if (rc == 0) { + rc = TPM_RandomNonZero(encodedMessage + 2, encodedMessageLength - messageLength - 3); + } + /* 3. Concatenate PS, the message M, and other padding to form the encoded message EM as: */ + /* EM = 02 || PS || 00 || M */ + if (rc == 0) { + encodedMessage[0] = 0x00; + encodedMessage[1] = 0x02; + encodedMessage[encodedMessageLength - messageLength - 1] = 0x00; + memcpy(encodedMessage + encodedMessageLength - messageLength, message, messageLength); + } + return rc; +} + +/* TPM_PKCS1_Type2PaddingCheck checks the PKCS1 type 2 padding and recovers the message + + The output buffer is preallocated. +*/ + +static +TPM_RESULT TPM_PKCS1_PaddingType2Check(unsigned char *outputData, /* to */ + uint32_t *outputDataLength, /* to length */ + uint32_t outputDataSize, /* pre-allocated to length */ + unsigned char *inputData, /* from - padded data */ + uint32_t inputDataLength) /* from length */ +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PKCS1_PaddingType2Check:\n"); + /* check the leading bytes for 0x00, 0x02 */ + if (rc == 0) { + if ((inputData[0] != 0x00) || + (inputData[1] != 0x02)) { + printf("TPM_PKCS1_PaddingType2Check: Error, bad leading bytes %02x %02x\n", + inputData[0], inputData[1]); + rc = TPM_DECRYPT_ERROR; + } + } + /* skip the non-zero random PS */ + for (i = 2 ; (rc == 0) && (i < inputDataLength) ; i++) { + if (inputData[i] == 0x00) { + break; + } + } + /* check for the trailing 0x00 */ + if (rc == 0) { + if (i == inputDataLength) { + printf("TPM_PKCS1_PaddingType2Check: Error, missing trailing 0x00\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* check that PS was at least 8 bytes */ + if (rc == 0) { + if (i < 10) { + printf("TPM_PKCS1_PaddingType2Check: Error, bad PS length %lu\n", (unsigned long)i-2); + rc = TPM_DECRYPT_ERROR; + } + } + /* check that the output can accommodate the message */ + if (rc == 0) { + i++; /* index past the trailing 0x00 */ + *outputDataLength = inputDataLength - i; + if (*outputDataLength > outputDataSize) { + printf("TPM_PKCS1_PaddingType2Check: Error, " + "message %u greater than output data size %u\n", + *outputDataLength, outputDataSize); + rc = TPM_DECRYPT_ERROR; + } + } + /* copy the message */ + if (rc == 0) { + memcpy(outputData, inputData + inputDataLength - *outputDataLength, *outputDataLength); + } + return rc; +} + +/* + GNU MP wrappers do error logging and transformation of errors to TPM type errors +*/ + +/* TPM_BN_num_bytes() wraps the gnump function in a TPM error handler + + Returns number of bytes in the input +*/ + +TPM_RESULT TPM_BN_num_bytes(unsigned int *numBytes, TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + mpz_t *bn = (mpz_t *)bn_in; + + /* is the bignum zero */ + int result = mpz_cmp_ui(*bn, 0); + /* mpz_sizeinbase() always returns at least one. If the value is zero, there should really be 0 + bytes */ + if (result == 0) { + *numBytes = 0; + } + /* take the base 2 number and round up to the next byte */ + else { + *numBytes = (mpz_sizeinbase (*bn, 2) +7) / 8; + } + return rc; +} + +/* TPM_BN_is_one() wraps the gnump function in a TPM error handler + + Returns success if input is 1 +*/ + +TPM_RESULT TPM_BN_is_one(TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + mpz_t *bn = (mpz_t *)bn_in; + int irc; + + irc = mpz_cmp_ui(*bn, 1); + if (irc != 0) { + printf("TPM_BN_is_one: Error, result is not 1\n"); + rc = TPM_DAA_WRONG_W; + } + return rc; +} + + +/* TPM_BN_mod() wraps the gnump function in a TPM error handler + + r = a mod m +*/ + +TPM_RESULT TPM_BN_mod(TPM_BIGNUM rem_in, + const TPM_BIGNUM a_in, + const TPM_BIGNUM m_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rem_in; + mpz_t *aBignum = (mpz_t *)a_in; + mpz_t *mBignum = (mpz_t *)m_in; + + /* set r to a mod m */ + mpz_mod(*rBignum, *aBignum, *mBignum); + return rc; +} + +/* TPM_BN_mask_bits() wraps the gnump function in a TPM error handler + + erase all but the lowest n bits of bn + bn = bn mod 2^^n +*/ + +TPM_RESULT TPM_BN_mask_bits(TPM_BIGNUM bn_in, unsigned int n) +{ + TPM_RESULT rc = 0; + unsigned int numBytes; + mpz_t *bn = (mpz_t *)bn_in; + + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, bn_in); + } + if (rc == 0) { + /* if the BIGNUM is already fewer bits, no need to mask */ + if (numBytes > (n / 8)) { + /* divide and return remainder, divisor is 2^^n */ + mpz_fdiv_r_2exp(*bn, *bn, n); + } + } + return rc; +} + +/* TPM_BN_rshift() wraps the gnump function in a TPM error handler + + Shift a right by n bits (discard the lowest n bits) and label the result r +*/ + +TPM_RESULT TPM_BN_rshift(TPM_BIGNUM *rBignum_in, /* freed by caller */ + TPM_BIGNUM aBignum_in, + int n) +{ + TPM_RESULT rc = 0; + mpz_t **rBignum = (mpz_t **)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + + printf(" TPM_BN_rshift: n %d\n", n); + if (rc == 0) { + rc = TPM_BN_new(rBignum_in); + } + if (rc == 0) { + /* divide and return quotient, rounded down (floor) */ + mpz_fdiv_q_2exp(**rBignum, *aBignum, n); + } + return rc; +} + +/* TPM_BN_lshift() wraps the gnump function in a TPM error handler + + Shift a left by n bits and label the result r +*/ + +TPM_RESULT TPM_BN_lshift(TPM_BIGNUM *rBignum_in, /* freed by caller */ + TPM_BIGNUM aBignum_in, + int n) +{ + TPM_RESULT rc = 0; + mpz_t **rBignum = (mpz_t **)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + + printf(" TPM_BN_lshift: n %d\n", n); + if (rc == 0) { + rc = TPM_BN_new(rBignum_in); + } + if (rc == 0) { + /* multiply by 2^^n is is a left shift by n */ + mpz_mul_2exp(**rBignum, *aBignum, n); + } + return rc; +} + +/* TPM_BN_add() wraps the gnump function in a TPM error handler + + r = a + b +*/ + +TPM_RESULT TPM_BN_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + mpz_t *bBignum = (mpz_t *)bBignum_in; + + printf(" TPM_BN_add:\n"); + /* result = a + b */ + mpz_add(*rBignum, *aBignum, *bBignum); + return rc; +} + +/* TPM_BN_mul() wraps the gnump function in a TPM error handler + + r = a * b +*/ + +TPM_RESULT TPM_BN_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + mpz_t *bBignum = (mpz_t *)bBignum_in; + + printf(" TPM_BN_mul:\n"); + /* r = a * b */ + mpz_mul(*rBignum, *aBignum, *bBignum); + return rc; +} + +/* TPM_BN_mod_exp() wraps the gnump function in a TPM error handler + + computes a to the p-th power modulo m (r=a^p % n) +*/ + +TPM_RESULT TPM_BN_mod_exp(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM pBignum_in, + TPM_BIGNUM nBignum_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + mpz_t *pBignum = (mpz_t *)pBignum_in; + mpz_t *nBignum = (mpz_t *)nBignum_in; + + printf(" TPM_BN_mod_exp:\n"); + mpz_powm(*rBignum, *aBignum, *pBignum, *nBignum); + return rc; +} + +/* TPM_BN_Mod_add() wraps the gnump function in a TPM error handler + + adds a to b modulo m +*/ + +TPM_RESULT TPM_BN_mod_add(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + mpz_t *bBignum = (mpz_t *)bBignum_in; + mpz_t *mBignum = (mpz_t *)mBignum_in; + + printf(" TPM_BN_mod_add:\n"); + /* r = a + b */ + mpz_add(*rBignum, *aBignum, *bBignum); + /* set r to r mod m */ + mpz_mod(*rBignum, *rBignum, *mBignum); + return rc; +} + +/* TPM_BN_mod_mul() wraps the gnump function in a TPM error handler + + r = (a * b) mod m +*/ + +TPM_RESULT TPM_BN_mod_mul(TPM_BIGNUM rBignum_in, + TPM_BIGNUM aBignum_in, + TPM_BIGNUM bBignum_in, + TPM_BIGNUM mBignum_in) +{ + TPM_RESULT rc = 0; + mpz_t *rBignum = (mpz_t *)rBignum_in; + mpz_t *aBignum = (mpz_t *)aBignum_in; + mpz_t *bBignum = (mpz_t *)bBignum_in; + mpz_t *mBignum = (mpz_t *)mBignum_in; + + printf(" TPM_BN_mod_mul:\n"); + /* r = a * b */ + mpz_mul(*rBignum, *aBignum, *bBignum); + /* set r to r mod m */ + mpz_mod(*rBignum, *rBignum, *mBignum); + return rc; +} + +/* TPM_BN_new() wraps the gnump function in a TPM error handler + + Allocates a new bignum +*/ + +TPM_RESULT TPM_BN_new(TPM_BIGNUM *bn_in) /* freed by caller */ +{ + TPM_RESULT rc = 0; + mpz_t *bn; + + if (rc== 0) { + rc = TPM_Malloc(bn_in, sizeof(mpz_t)); /* freed by caller */ + } + if (rc== 0) { + bn = (mpz_t *)*bn_in; + mpz_init(*bn); + } + return rc; +} + +/* TPM_BN_free() wraps the gnump function + + Frees the bignum +*/ + +void TPM_BN_free(TPM_BIGNUM bn_in) +{ + mpz_t *bn = (mpz_t *)bn_in; + if (bn != NULL) { + mpz_clear(*bn); + free(bn_in); + } + return; +} + +/* TPM_bn2bin wraps the function in gnump a TPM error handler. + + Converts a bignum to char array + + 'bin' must already be checked for sufficient size. +*/ + +TPM_RESULT TPM_bn2bin(unsigned char *bin, + TPM_BIGNUM bn_in) +{ + TPM_RESULT rc = 0; + mpz_t *bn = (mpz_t *)bn_in; + + mpz_export(bin, /* output */ + NULL, /* countp */ + 1, /* order, MSB first */ + 1, /* size, char */ + 0, /* endian, native (unused) */ + 0, /* nails, don't discard */ + *bn); /* input */ + return rc; +} + +/* TPM_memcpyPad allocates a buffer 'bin_out' and loads it from 'bin_in'. + + If padBytes is non-zero, 'bin_out' is padded with leading zeros if necessary, so that 'bytes' + will equal 'padBytes'. This is used when TPM data structures expect a fixed length while + the crypto library truncates leading zeros. + + '*bin_out' must be freed by the caller +*/ + +static TPM_RESULT TPM_memcpyPad(unsigned char **bin_out, + unsigned char *bin_in, + uint32_t bin_in_length, + uint32_t padBytes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_memcpyPad: padBytes %u\n", padBytes); + if (rc == 0) { + /* padBytes 0 says that no padding is required */ + if (padBytes == 0) { + padBytes = bin_in_length; /* setting equal yields no padding */ + } + /* The required output should never be less than the supplied input. Sanity check and + return a fatal error. */ + if (padBytes < bin_in_length) { + printf("TPM_memcpyPad: Error (fatal), " + "padBytes %u less than %u\n", padBytes, bin_in_length); + rc = TPM_FAIL; + } + if (padBytes != bin_in_length) { + printf(" TPM_memcpyPad: padBytes %u bytes %u\n", padBytes, bin_in_length); + } + } + /* allocate memory for the padded output */ + if (rc == 0) { + rc = TPM_Malloc(bin_out, padBytes); + } + if (rc == 0) { + memset(*bin_out, 0, padBytes - bin_in_length); /* leading 0 padding */ + memcpy((*bin_out) + padBytes - bin_in_length, /* start copy after padding */ + bin_in, bin_in_length); + } + return rc; +} + +/* TPM_bin2bn() wraps the gnump function in a TPM error handler + + Converts a char array to bignum + + bn must be freed by the caller. +*/ + +TPM_RESULT TPM_bin2bn(TPM_BIGNUM *bn_in, const unsigned char *bin, unsigned int bytes) +{ + TPM_RESULT rc = 0; + + TPM_BN_new(bn_in); + mpz_t *bn = (mpz_t *)*bn_in; + mpz_import(*bn, /* output */ + bytes, /* count */ + 1, /* order, MSB first */ + 1, /* size, char */ + 0, /* endian, native (unused) */ + 0, /* nail, don't discard */ + bin); /* input */ + return rc; +} + +/* + Hash Functions +*/ + +/* TPM_SHA1InitCmd() initializes a platform dependent TPM_SHA1Context structure. + + The structure must be freed using TPM_SHA1FinalCmd() +*/ + +TPM_RESULT TPM_SHA1InitCmd(void **context) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SHA1InitCmd:\n"); + if (rc == 0) { + /* create a new freebl SHA1 context */ + *context = SHA1_NewContext(); + if (*context == NULL) { + printf("TPM_SHA1InitCmd: Error allocating a new context\n"); + rc = TPM_SIZE; + } + } + /* reset the SHA-1 context, preparing it for a fresh round of hashing */ + if (rc== 0) { + SHA1_Begin(*context); + } + return rc; +} + +/* TPM_SHA1UpdateCmd() adds 'data' of 'length' to the SHA-1 context + */ + +TPM_RESULT TPM_SHA1UpdateCmd(void *context, const unsigned char *data, uint32_t length) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SHA1Update: length %u\n", length); + if (context != NULL) { + SHA1_Update(context, data, length); + } + else { + printf("TPM_SHA1Update: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + return rc; +} + +/* TPM_SHA1FinalCmd() extracts the SHA-1 digest 'md' from the context + */ + +TPM_RESULT TPM_SHA1FinalCmd(unsigned char *md, void *context) +{ + TPM_RESULT rc = 0; + unsigned int digestLen; + + printf(" TPM_SHA1FinalCmd:\n"); + if (rc== 0) { + if (context == NULL) { + printf("TPM_SHA1FinalCmd: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + } + if (rc== 0) { + SHA1_End(context, md, &digestLen, TPM_DIGEST_SIZE); + /* Sanity check. For SHA1 it should always be 20 bytes. */ + if (digestLen != TPM_DIGEST_SIZE) { + printf("TPM_SHA1Final: Error (fatal), SHA1_End returned %u bytes\n", digestLen); + rc = TPM_FAIL; + } + } + return rc; +} + +/* TPM_SHA1Delete() zeros and frees the SHA1 context */ + +void TPM_SHA1Delete(void **context) +{ + if (*context != NULL) { + printf(" TPM_SHA1Delete:\n"); + /* zero because the SHA1 context might have data left from an HMAC */ + SHA1_DestroyContext(*context, PR_TRUE); + *context = NULL; + } + return; +} + +#if defined (__x86_64__) || \ + defined(__amd64__) || \ + defined(__ia64__) || \ + defined(__powerpc64__) || \ + defined(__s390x__) || \ + (defined(__sparc__) && defined(__arch64__)) || \ + defined(__arm64__) + +#define IS_64 +typedef PRUint64 SHA_HW_t; + +#elif defined (__i386__) || \ + defined (__powerpc__) || \ + defined (__s390__) || \ + defined(__sparc__) || \ + defined(__arm__) + +typedef PRUint32 SHA_HW_t; +#undef IS_64 + +#else +#error "Cannot determine 32 or 64 bit platform" +#endif + +/* The structure returned by the SHA1_Flatten() command and passed to SHA1_Resurrect() + */ + +typedef struct SHA1SaveContextStrtd { + union { + PRUint32 w[16]; /* input buffer */ + PRUint8 b[64]; + } u; + PRUint64 size; /* count of hashed bytes. */ + SHA_HW_t H[22]; /* 5 state variables, 16 tmp values, 1 + extra */ +} SHA1SaveContextStr; + + +/* TPM_Sha1Context_Load() is non-portable code to deserialize the FreeBL SHA1 context. + + If the contextPresent prepended by TPM_Sha1Context_Store() is FALSE, context remains NULL. If + TRUE, context is allocated and loaded. +*/ + +TPM_RESULT TPM_Sha1Context_Load(void **context, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_BOOL contextPresent; /* is there a context to be loaded */ + uint32_t flattenSize; /* from the freebl library */ + SHA1Context *tmpContext = NULL; /* temp to get flatten size, freed @1 */ + uint32_t tmp32; /* temp to recreate 64-bit size */ + SHA1SaveContextStr restoreContext; + size_t i; + + printf(" TPM_Sha1Context_Load: FreeBL\n"); + /* TPM_Sha1Context_Store() stored a flag to indicate whether a context was stored */ + if (rc== 0) { + rc = TPM_LoadBool(&contextPresent, stream, stream_size); + printf(" TPM_Sha1Context_Load: contextPresent %u\n", contextPresent); + } + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if ((rc== 0) && contextPresent) { + rc = TPM_CheckTag(TPM_TAG_SHA1CONTEXT_FREEBL_V1, stream, stream_size); + } + /* check that context is NULL to detect memory leak */ + if ((rc== 0) && contextPresent) { + if (*context != NULL) { + printf("TPM_Sha1Context_Load: Error (fatal), *context %p should be NULL\n", *context ); + rc = TPM_FAIL; + } + } + /* create a temporary context just to get the freebl library size */ + if ((rc== 0) && contextPresent) { + rc = TPM_SHA1InitCmd((void **)&tmpContext); /* freed @1 */ + } + /* get the size of the FreeBL library SHA1 context */ + if ((rc== 0) && contextPresent) { + flattenSize = SHA1_FlattenSize(tmpContext); + /* sanity check that the freebl library and TPM structure here are in sync */ + if (flattenSize != sizeof(SHA1SaveContextStr)) { + printf("TPM_Sha1Context_Load: Error, " + "SHA1 context size %u from SHA1_FlattenSize not equal %lu from struture\n", + flattenSize, (unsigned long)sizeof(SHA1SaveContextStr)); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* + deserialization code to fill in restoreContext + */ + /* b[0..63] <- u.b[0..63] (bytes only, no bytswapping) */ + if ((rc== 0) && contextPresent) { + rc = TPM_Loadn(restoreContext.u.b, 64, stream, stream_size); + } + /* count <- size (this is 64 bits on all platforms) */ + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&tmp32, stream, stream_size); + restoreContext.size = (uint64_t)tmp32 << 32; /* big endian */ + } + if ((rc== 0) && contextPresent) { + rc = TPM_Load32(&tmp32, stream, stream_size); + restoreContext.size += (uint64_t)tmp32 & 0xffffffff; /* big endian */ + } + for (i = 0 ; (rc == 0) && contextPresent && (i < 5) ; i++) { + rc = TPM_Load32(&tmp32, stream, stream_size); + restoreContext.H[i] = tmp32; /* H can be 32 or 64 bits */ + } + /* load the context */ + if ((rc== 0) && contextPresent) { + /* the size test above ensures that the cast here is safe */ + *context = SHA1_Resurrect((unsigned char *)&restoreContext, NULL); + if (*context == NULL) { + printf("TPM_Sha1Context_Load: Error, could not SHA1_Resurrect\n"); + rc = TPM_SIZE; + } + } + TPM_SHA1Delete((void *)&tmpContext); /* @1 */ + return rc; +} + +/* TPM_Sha1Context_Store() is non-portable code to serialize the FreeBL SHA1 context. context is + not altered. + + It prepends a contextPresent flag to the stream, FALSE if context is NULL, TRUE if not. +*/ + +TPM_RESULT TPM_Sha1Context_Store(TPM_STORE_BUFFER *sbuffer, + void *context) +{ + TPM_RESULT rc = 0; + SECStatus rv = SECSuccess; + size_t i; + unsigned int flattenSize; + SHA1SaveContextStr saveContext; + TPM_BOOL contextPresent; /* is there a context to be stored */ + + printf(" TPM_Sha1Context_Store: FreeBL\n"); + /* store contextPresent */ + if (rc == 0) { + if (context != NULL) { + printf(" TPM_Sha1Context_Store: Storing context\n"); + contextPresent = TRUE; + } + else { + printf(" TPM_Sha1Context_Store: No context to store\n"); + contextPresent = FALSE; + } + printf(" TPM_Sha1Context_Store: contextPresent %u \n", contextPresent); + rc = TPM_Sbuffer_Append(sbuffer, &contextPresent, sizeof(TPM_BOOL)); + } + /* overall format tag */ + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_SHA1CONTEXT_FREEBL_V1); + } + if ((rc== 0) && contextPresent) { + /* get the size of the FreeBL SHA1 context */ + flattenSize = SHA1_FlattenSize(context); /* it will not be NULL here */ + /* sanity check that the freebl library and TPM structure here are in sync */ + if (flattenSize != sizeof(SHA1SaveContextStr)) { + printf("TPM_Sha1Context_Store: Error (fatal), " + "SHA1 context size %u from SHA1_FlattenSize not equal %lu from struture\n", + flattenSize, (unsigned long)sizeof(SHA1SaveContextStr)); + rc = TPM_FAIL; + } + } + /* store into the structure from the library */ + if ((rc== 0) && contextPresent) { + /* the size test above ensures that the cast here is safe */ + rv = SHA1_Flatten(context, (unsigned char *)&saveContext); + if (rv != SECSuccess) { + printf("TPM_Sha1Context_Store: Error (fatal), SHA1_Flatten rv %d\n", rv); + rc = TPM_FAIL; + } + } + /* + append the FreeBL SHA1 context to the stream + */ + /* b[0..63] <- u.b[0..63] (bytes only, no byte swapping) */ + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append(sbuffer, saveContext.u.b, 64); + } + /* count <- size (this is 64 bits on all platforms) */ + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, saveContext.size >> 32); /* big endian */ + } + if ((rc== 0) && contextPresent) { + rc = TPM_Sbuffer_Append32(sbuffer, saveContext.size & 0xffffffff); + } + /* SHA_HW_t - NSS uses 64 bits on 64 bit platforms for performance reasons only. The lower 32 + bits are critical, so you can always serialize/deserialize just the lower 32 bits. */ + /* The remainder of the H array is scratch memory and does not need to be preserved or + transmitted. */ + for (i = 0 ; (rc == 0) && contextPresent && (i < 5) ; i++) { + rc = TPM_Sbuffer_Append32(sbuffer, saveContext.H[i] & 0xffffffff); + } + return rc; +} + +/* + TPM_SYMMETRIC_KEY_DATA +*/ + +#ifdef TPM_AES + +/* TPM_SymmetricKeyData_New() allocates memory for and initializes a TPM_SYMMETRIC_KEY_DATA token. + */ + +TPM_RESULT TPM_SymmetricKeyData_New(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKeyData_New:\n"); + if (rc == 0) { + rc = TPM_Malloc(tpm_symmetric_key_data, sizeof(TPM_SYMMETRIC_KEY_DATA)); + } + if (rc == 0) { + TPM_SymmetricKeyData_Init(*tpm_symmetric_key_data); + } + return rc; +} + +/* TPM_SymmetricKeyData_Free() initializes the key token to wipe secrets. It then frees the + TPM_SYMMETRIC_KEY_DATA token and sets it to NULL. +*/ + +void TPM_SymmetricKeyData_Free(TPM_SYMMETRIC_KEY_TOKEN *tpm_symmetric_key_data) +{ + printf(" TPM_SymmetricKeyData_Free:\n"); + if (*tpm_symmetric_key_data != NULL) { + TPM_SymmetricKeyData_Init(*tpm_symmetric_key_data); + free(*tpm_symmetric_key_data); + *tpm_symmetric_key_data = NULL; + } + return; +} + +/* TPM_SymmetricKeyData_Init() is AES non-portable code to initialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +void TPM_SymmetricKeyData_Init(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Init:\n"); + tpm_symmetric_key_data->tag = TPM_TAG_KEY; + tpm_symmetric_key_data->valid = FALSE; + tpm_symmetric_key_data->fill = 0; + /* zero to wipe secrets */ + memset(tpm_symmetric_key_data->userKey, 0, sizeof(tpm_symmetric_key_data->userKey)); + return; +} + +/* TPM_SymmetricKeyData_Load() is AES non-portable code to deserialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the above TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Load(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_KEY, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_symmetric_key_data->valid), stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_symmetric_key_data->fill), stream, stream_size); + } + /* The AES key is a simple array. */ + if (rc == 0) { + rc = TPM_Loadn(tpm_symmetric_key_data->userKey, sizeof(tpm_symmetric_key_data->userKey), + stream, stream_size); + } + return rc; +} + +/* TPM_SymmetricKeyData_Store() is AES non-portable code to serialize the TPM_SYMMETRIC_KEY_DATA + + It depends on the above TPM_SYMMETRIC_KEY_DATA declaration. +*/ + +TPM_RESULT TPM_SymmetricKeyData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key_data->tag); + } + /* store valid */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->valid), sizeof(TPM_BOOL)); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_symmetric_key_data->fill), sizeof(TPM_BOOL)); + } + /* store AES key */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + tpm_symmetric_key_data->userKey, + sizeof(tpm_symmetric_key_data->userKey)); + } + return rc; +} + +/* TPM_SymmetricKeyData_GenerateKey() is AES non-portable code to generate a random symmetric key + + tpm_symmetric_key_data should be initialized before and after use +*/ + +TPM_RESULT TPM_SymmetricKeyData_GenerateKey(TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_token) +{ + TPM_RESULT rc = 0; + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_GenerateKey:\n"); + /* generate a random key */ + if (rc == 0) { + rc = TPM_Random(tpm_symmetric_key_data->userKey, sizeof(tpm_symmetric_key_data->userKey)); + } + if (rc == 0) { + tpm_symmetric_key_data->valid = TRUE; + } + return rc; +} + +/* TPM_SymmetricKeyData_Encrypt() is AES non-portable code to CBC encrypt 'decrypt_data' to + 'encrypt_data' + + The stream is padded as per PKCS#7 / RFC2630 + + 'encrypt_data' must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Encrypt(unsigned char **encrypt_data, /* output, caller frees */ + uint32_t *encrypt_length, /* output */ + const unsigned char *decrypt_data, /* input */ + uint32_t decrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_token) /* input */ +{ + TPM_RESULT rc = 0; + SECStatus rv; + AESContext *cx; + uint32_t pad_length; + uint32_t output_length; /* dummy */ + unsigned char *decrypt_data_pad; + unsigned char ivec[TPM_AES_BLOCK_SIZE]; /* initial chaining vector */ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Encrypt: Length %u\n", decrypt_length); + decrypt_data_pad = NULL; /* freed @1 */ + cx = NULL; /* freed @2 */ + + /* sanity check that the AES key has previously been generated */ + if (rc == 0) { + if (!tpm_symmetric_key_data->valid) { + printf("TPM_SymmetricKeyData_Encrypt: Error (fatal), AES key not valid\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + /* calculate the PKCS#7 / RFC2630 pad length and padded data length */ + pad_length = TPM_AES_BLOCK_SIZE - (decrypt_length % TPM_AES_BLOCK_SIZE); + *encrypt_length = decrypt_length + pad_length; + printf(" TPM_SymmetricKeyData_Encrypt: Padded length %u pad length %u\n", + *encrypt_length, pad_length); + /* allocate memory for the encrypted response */ + rc = TPM_Malloc(encrypt_data, *encrypt_length); + } + /* allocate memory for the padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&decrypt_data_pad, *encrypt_length); + } + if (rc == 0) { + /* set the IV */ + memset(ivec, 0, sizeof(ivec)); + /* create a new AES context */ + cx = AES_CreateContext(tpm_symmetric_key_data->userKey, + ivec, /* CBC initialization vector */ + NSS_AES_CBC, /* CBC mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE, /* key length */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (cx == NULL) { + printf("TPM_SymmetricKeyData_Encrypt: Error creating AES context\n"); + rc = TPM_SIZE; + } + } + /* pad the decrypted clear text data */ + if (rc == 0) { + /* unpadded original data */ + memcpy(decrypt_data_pad, decrypt_data, decrypt_length); + /* last gets pad = pad length */ + memset(decrypt_data_pad + decrypt_length, pad_length, pad_length); + /* encrypt the padded input to the output */ + TPM_PrintFour(" TPM_SymmetricKeyData_Encrypt: Input", decrypt_data_pad); + /* perform the AES encryption */ + rv = AES_Encrypt(cx, + *encrypt_data, &output_length, *encrypt_length, /* output */ + decrypt_data_pad, *encrypt_length); /* input */ + + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_Encrypt: Error, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Encrypt: Output", *encrypt_data); + } + free(decrypt_data_pad); /* @1 */ + if (cx != NULL) { + /* due to a FreeBL bug, must zero the context before destroying it */ + unsigned char dummy_key[TPM_AES_BLOCK_SIZE]; + unsigned char dummy_ivec[TPM_AES_BLOCK_SIZE]; + memset(dummy_key, 0x00, TPM_AES_BLOCK_SIZE); + memset(dummy_ivec, 0x00, TPM_AES_BLOCK_SIZE); + rv = AES_InitContext(cx, /* AES context */ + dummy_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + dummy_ivec, /* ivec */ + NSS_AES_CBC, /* CBC mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + AES_DestroyContext(cx, PR_TRUE); /* @2 */ + } + return rc; +} + +/* TPM_SymmetricKeyData_Decrypt() is AES non-portable code to CBC decrypt 'encrypt_data' to + 'decrypt_data' + + The stream must be padded as per PKCS#7 / RFC2630 + + decrypt_data must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_Decrypt(unsigned char **decrypt_data, /* output, caller frees */ + uint32_t *decrypt_length, /* output */ + const unsigned char *encrypt_data, /* input */ + uint32_t encrypt_length, /* input */ + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_token) /* input */ +{ + TPM_RESULT rc = 0; + SECStatus rv; + AESContext *cx; + uint32_t pad_length; + uint32_t output_length; /* dummy */ + uint32_t i; + unsigned char *pad_data; + unsigned char ivec[TPM_AES_BLOCK_SIZE]; /* initial chaining vector */ + TPM_SYMMETRIC_KEY_DATA *tpm_symmetric_key_data = + (TPM_SYMMETRIC_KEY_DATA *)tpm_symmetric_key_token; + + printf(" TPM_SymmetricKeyData_Decrypt: Length %u\n", encrypt_length); + cx = NULL; /* freed @1 */ + + /* sanity check encrypted length */ + if (rc == 0) { + if (encrypt_length < TPM_AES_BLOCK_SIZE) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* sanity check that the AES key has previously been generated */ + if (rc == 0) { + if (!tpm_symmetric_key_data->valid) { + printf("TPM_SymmetricKeyData_Decrypt: Error (fatal), AES key not valid\n"); + rc = TPM_FAIL; + } + } + /* allocate memory for the PKCS#7 / RFC2630 padded decrypted data */ + if (rc == 0) { + rc = TPM_Malloc(decrypt_data, encrypt_length); + } + if (rc == 0) { + /* set the IV */ + memset(ivec, 0, sizeof(ivec)); + /* create a new AES context */ + cx = AES_CreateContext(tpm_symmetric_key_data->userKey, + ivec, /* CBC initialization vector */ + NSS_AES_CBC, /* CBC mode */ + FALSE, /* decrypt */ + TPM_AES_BLOCK_SIZE, /* key length */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (cx == NULL) { + printf("TPM_SymmetricKeyData_Decrypt: Error creating AES context\n"); + rc = TPM_SIZE; + } + } + /* decrypt the input to the PKCS#7 / RFC2630 padded output */ + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Decrypt: Input", encrypt_data); + /* perform the AES decryption */ + rv = AES_Decrypt(cx, + *decrypt_data, &output_length, encrypt_length, /* output */ + encrypt_data, encrypt_length); /* input */ + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_Decrypt: Error, rv %d\n", rv); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_Decrypt: Output", *decrypt_data); + } + /* get the pad length */ + if (rc == 0) { + /* get the pad length from the last byte */ + pad_length = (uint32_t)*(*decrypt_data + encrypt_length - 1); + /* sanity check the pad length */ + printf(" TPM_SymmetricKeyData_Decrypt: Pad length %u\n", pad_length); + if ((pad_length == 0) || + (pad_length > TPM_AES_BLOCK_SIZE)) { + printf("TPM_SymmetricKeyData_Decrypt: Error, illegal pad length\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* get the unpadded length */ + *decrypt_length = encrypt_length - pad_length; + /* pad starting point */ + pad_data = *decrypt_data + *decrypt_length; + /* sanity check the pad */ + for (i = 0 ; i < pad_length ; i++, pad_data++) { + if (*pad_data != pad_length) { + printf("TPM_SymmetricKeyData_Decrypt: Error, bad pad %02x at index %u\n", + *pad_data, i); + rc = TPM_DECRYPT_ERROR; + } + } + } + if (cx != NULL) { + /* due to a FreeBL bug, must zero the context before destroying it */ + unsigned char dummy_key[TPM_AES_BLOCK_SIZE]; + unsigned char dummy_ivec[TPM_AES_BLOCK_SIZE]; + memset(dummy_key, 0x00, TPM_AES_BLOCK_SIZE); + memset(dummy_ivec, 0x00, TPM_AES_BLOCK_SIZE); + rv = AES_InitContext(cx, /* AES context */ + dummy_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + dummy_ivec, /* ivec */ + NSS_AES_CBC, /* CBC mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + AES_DestroyContext(cx, PR_TRUE); /* @1 */ + } + return rc; +} + +/* TPM_SymmetricKeyData_CtrCrypt() does an encrypt or decrypt (they are the same XOR operation with + a CTR mode pad) of 'data_in' to 'data_out'. + + TPM_SymmetricKeyData_CtrCrypt() is a TPM variant of the standard CTR encrypt function that + increments only the low 4 bytes of the counter. + + NOTE: This function looks general, but is currently hard coded to AES128. + + 'symmetric key' is the raw key, not converted to a non-portable form + 'ctr_in' is the initial CTR value before possible truncation +*/ + +TPM_RESULT TPM_SymmetricKeyData_CtrCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + const unsigned char *symmetric_key, /* input */ + uint32_t symmetric_key_size, /* input */ + const unsigned char *ctr_in, /* input */ + uint32_t ctr_in_size) /* input */ +{ + TPM_RESULT rc = 0; + SECStatus rv; + AESContext *cx = NULL; + unsigned char ctr[TPM_AES_BLOCK_SIZE]; + unsigned char pad_buffer[TPM_AES_BLOCK_SIZE]; /* the XOR pad */ + uint32_t output_length; /* dummy */ + uint32_t cint; /* counter as a 32-bit integer */ + + printf(" TPM_SymmetricKeyData_CtrCrypt: data_size %u\n", data_size); + symmetric_key_size = symmetric_key_size; + /* check the input CTR size, it can be truncated, but cannot be smaller than the AES key */ + if (rc == 0) { + if (ctr_in_size < sizeof(ctr)) { + printf(" TPM_SymmetricKeyData_CtrCrypt: Error (fatal)" + ", CTR size %u too small for AES key\n", ctr_in_size); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* make a truncated copy of CTR, since this function alters the value */ + memcpy(ctr, ctr_in, sizeof(ctr)); + TPM_PrintFour(" TPM_SymmetricKeyData_CtrCrypt: CTR", ctr); + } + /* create a new AES context */ + if (rc == 0) { + cx = AES_CreateContext(symmetric_key, /* AES key */ + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE, /* key length */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (cx == NULL) { + printf("TPM_SymmetricKeyData_CtrCrypt: Error creating AES context\n"); + rc = TPM_SIZE; + } + } + while (data_size != 0) { + printf(" TPM_SymmetricKeyData_CtrCrypt : data_size remaining %u\n", data_size); + /* initialize the context each time through the loop */ + if (rc == 0) { + rv = AES_InitContext(cx, /* AES context */ + symmetric_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_CtrCrypt: Error, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + /* get an XOR pad array by encrypting the CTR with the AES key */ + if (rc == 0) { + rv = AES_Encrypt(cx, + pad_buffer, &output_length, TPM_AES_BLOCK_SIZE, /* output */ + ctr, TPM_AES_BLOCK_SIZE); /* input */ + + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_CtrCrypt: Error, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + /* partial or full last data block */ + if (data_size <= TPM_AES_BLOCK_SIZE) { + TPM_XOR(data_out, data_in, pad_buffer, data_size); + data_size = 0; + } + /* full block, not the last block */ + else { + TPM_XOR(data_out, data_in, pad_buffer, TPM_AES_BLOCK_SIZE); + data_in += TPM_AES_BLOCK_SIZE; + data_out += TPM_AES_BLOCK_SIZE; + data_size -= TPM_AES_BLOCK_SIZE; + } + /* if not the last block, increment CTR, only the low 4 bytes */ + if (data_size != 0) { + /* CTR is a big endian array, so the low 4 bytes are used */ + cint = LOAD32(ctr, TPM_AES_BLOCK_SIZE-4); /* byte array to uint32_t */ + cint++; /* increment */ + STORE32(ctr, TPM_AES_BLOCK_SIZE-4, cint); /* uint32_t to byte array */ + } + } + } + if (cx != NULL) { + /* due to a FreeBL bug, must zero the context before destroying it */ + unsigned char dummy_key[TPM_AES_BLOCK_SIZE]; + memset(dummy_key, 0x00, TPM_AES_BLOCK_SIZE); + rv = AES_InitContext(cx, /* AES context */ + dummy_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + AES_DestroyContext(cx, PR_TRUE); /* @2 */ + } + return rc; +} + +/* TPM_SymmetricKeyData_OfbCrypt() does an encrypt or decrypt (they are the same XOR operation with + a OFB mode pad) of 'data_in' to 'data_out' + + NOTE: This function looks general, but is currently hard coded to AES128. + + 'symmetric key' is the raw key, not converted to a non-portable form + 'ivec_in' is the initial IV value before possible truncation +*/ + +TPM_RESULT TPM_SymmetricKeyData_OfbCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + const unsigned char *symmetric_key, /* in */ + uint32_t symmetric_key_size, /* in */ + unsigned char *ivec_in, /* input */ + uint32_t ivec_in_size) /* input */ +{ + TPM_RESULT rc = 0; + SECStatus rv; + AESContext *cx = NULL; + unsigned char ivec_loop[TPM_AES_BLOCK_SIZE]; /* ivec input to loop */ + unsigned char pad_buffer[TPM_AES_BLOCK_SIZE]; /* the XOR pad */ + uint32_t output_length; /* dummy */ + + printf(" TPM_SymmetricKeyData_OfbCrypt: data_size %u\n", data_size); + symmetric_key_size = symmetric_key_size; + /* check the input OFB size, it can be truncated, but cannot be smaller than the AES key */ + if (rc == 0) { + if (ivec_in_size < TPM_AES_BLOCK_SIZE) { + printf(" TPM_SymmetricKeyData_OfbCrypt: Error (fatal)," + "IV size %u too small for AES key\n", ivec_in_size); + rc = TPM_FAIL; /* should never occur */ + } + } + /* first time through, the ivec_loop will be the input ivec */ + if (rc == 0) { + memcpy(ivec_loop, ivec_in, sizeof(ivec_loop)); + TPM_PrintFour(" TPM_SymmetricKeyData_OfbCrypt: IV", ivec_loop); + } + /* create a new AES context */ + if (rc == 0) { + cx = AES_CreateContext(symmetric_key, + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE, /* key length */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (cx == NULL) { + printf("TPM_SymmetricKeyData_OfbCrypt: Error creating AES context\n"); + rc = TPM_SIZE; + } + } + while (data_size != 0) { + printf(" TPM_SymmetricKeyData_OfbCrypt: data_size remaining %u\n", data_size); + /* initialize the context each time through the loop */ + if (rc == 0) { + rv = AES_InitContext(cx, /* AES context */ + symmetric_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_OfbCrypt: Error, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + /* get an XOR pad array by encrypting the IV with the AES key */ + if (rc == 0) { + TPM_PrintFour(" TPM_SymmetricKeyData_OfbCrypt: IV", ivec_loop); + rv = AES_Encrypt(cx, + pad_buffer, &output_length, TPM_AES_BLOCK_SIZE, /* output */ + ivec_loop, TPM_AES_BLOCK_SIZE); /* input */ + + if (rv != SECSuccess) { + printf("TPM_SymmetricKeyData_OfbCrypt: Error, rv %d\n", rv); + rc = TPM_ENCRYPT_ERROR; + } + } + if (rc == 0) { + /* partial or full last data block */ + if (data_size <= TPM_AES_BLOCK_SIZE) { + TPM_XOR(data_out, data_in, pad_buffer, data_size); + data_size = 0; + } + /* full block, not the last block */ + else { + TPM_XOR(data_out, data_in, pad_buffer, TPM_AES_BLOCK_SIZE); + data_in += TPM_AES_BLOCK_SIZE; + data_out += TPM_AES_BLOCK_SIZE; + data_size -= TPM_AES_BLOCK_SIZE; + } + /* if not the last block, wrap the pad_buffer back to ivec_loop (output feed back) */ + memcpy(ivec_loop, pad_buffer, TPM_AES_BLOCK_SIZE); + } + } + if (cx != NULL) { + /* due to a FreeBL bug, must zero the context before destroying it */ + unsigned char dummy_key[TPM_AES_BLOCK_SIZE]; + memset(dummy_key, 0x00, TPM_AES_BLOCK_SIZE); + rv = AES_InitContext(cx, /* AES context */ + dummy_key, /* AES key */ + TPM_AES_BLOCK_SIZE, /* key length */ + NULL, /* ivec not used in NSS_AES */ + NSS_AES, /* mode */ + TRUE, /* encrypt */ + TPM_AES_BLOCK_SIZE); /* AES block length */ + AES_DestroyContext(cx, PR_TRUE); /* @2 */ + } + return rc; +} + +#endif /* TPM_AES */ diff --git a/src/tpm_cryptoh.c b/src/tpm_cryptoh.c new file mode 100644 index 00000000..f6f84385 --- /dev/null +++ b/src/tpm_cryptoh.c @@ -0,0 +1,5362 @@ +/********************************************************************************/ +/* */ +/* High Level Platform Independent Cryptography */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_cryptoh.c 4540 2011-04-07 18:51:34Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_admin.h" +#include "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_memory.h" +#include "tpm_migration.h" +#include "tpm_nonce.h" +#include "tpm_key.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_store.h" +#include "tpm_ver.h" + +#include "tpm_cryptoh.h" + +/* local prototypes */ + +static TPM_RESULT TPM_SHA1_valist(TPM_DIGEST md, + uint32_t length0, unsigned char *buffer0, + va_list ap); +static TPM_RESULT TPM_HMAC_Generatevalist(TPM_HMAC hmac, + const TPM_SECRET key, + va_list ap); + +static TPM_RESULT TPM_SHA1CompleteCommon(TPM_DIGEST hashValue, + void **sha1_context, + TPM_SIZED_BUFFER *hashData); + +/* + TPM_SIGN_INFO +*/ + +/* TPM_SignInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SignInfo_Init(TPM_SIGN_INFO *tpm_sign_info) +{ + printf(" TPM_SignInfo_Init:\n"); + memset(tpm_sign_info->fixed, 0, TPM_SIGN_INFO_FIXED_SIZE); + TPM_Nonce_Init(tpm_sign_info->replay); + TPM_SizedBuffer_Init(&(tpm_sign_info->data)); + return; +} + +/* TPM_SignInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_SignInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SIGN_INFO *tpm_sign_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SignInfo_Store:\n"); + /* store the tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_SIGNINFO); + } + /* store the fixed */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_sign_info->fixed, TPM_SIGN_INFO_FIXED_SIZE); + } + /* store the replay */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_sign_info->replay); + } + /* store the dataLen and data */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_sign_info->data)); + } + if (rc == 0) { + const unsigned char *buffer; + uint32_t length; + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + TPM_PrintAll(" TPM_SignInfo_Store: Buffer", buffer, length); + } + return rc; +} + +/* TPM_SignInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the sign_info + sets pointers to NULL + calls TPM_SignInfo_Init to set members back to default values + The sign_info itself is not freed +*/ + +void TPM_SignInfo_Delete(TPM_SIGN_INFO *tpm_sign_info) +{ + printf(" TPM_SignInfo_Delete:\n"); + if (tpm_sign_info != NULL) { + TPM_SizedBuffer_Delete(&(tpm_sign_info->data)); + TPM_SignInfo_Init(tpm_sign_info); + } + return; +} + +/* + TPM_CERTIFY_INFO +*/ + +/* TPM_CertifyInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CertifyInfo_Init(TPM_CERTIFY_INFO *tpm_certify_info) +{ + printf(" TPM_CertifyInfo_Init:\n"); + TPM_StructVer_Init(&(tpm_certify_info->version)); + tpm_certify_info->keyUsage = TPM_KEY_UNINITIALIZED; + tpm_certify_info->keyFlags = 0; + tpm_certify_info->authDataUsage = TPM_AUTH_ALWAYS; + TPM_KeyParms_Init(&(tpm_certify_info->algorithmParms)); + TPM_Digest_Init(tpm_certify_info->pubkeyDigest); + TPM_Nonce_Init(tpm_certify_info->data); + tpm_certify_info->parentPCRStatus = TRUE; + TPM_SizedBuffer_Init(&(tpm_certify_info->pcrInfo)); + tpm_certify_info->tpm_pcr_info = NULL; + return; +} + +/* TPM_CertifyInfo_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CertifyInfo_Init() + After use, call TPM_CertifyInfo_Delete() to free memory + + NOTE: Never called. +*/ + +TPM_RESULT TPM_CertifyInfo_Load(TPM_CERTIFY_INFO *tpm_certify_info, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo_Load:\n"); + /* load version */ + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_certify_info->version), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_certify_info->version)); + } + /* load keyUsage */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_certify_info->keyUsage), stream, stream_size); + } + /* load keyFlags */ + if (rc == 0) { + rc = TPM_KeyFlags_Load(&(tpm_certify_info->keyFlags), stream, stream_size); + } + /* load authDataUsage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info->authDataUsage), stream, stream_size); + } + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_certify_info->algorithmParms), stream, stream_size); + } + /* load pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_certify_info->pubkeyDigest, stream, stream_size); + } + /* load data */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_certify_info->data, stream, stream_size); + } + /* load parentPCRStatus */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_certify_info->parentPCRStatus), stream, stream_size); + } + /* load pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_certify_info->pcrInfo), stream, stream_size); + } + /* set TPM_PCR_INFO tpm_pcr_info cache from pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfo_CreateFromBuffer(&(tpm_certify_info->tpm_pcr_info), + &(tpm_certify_info->pcrInfo)); + } + return rc; +} + +/* TPM_CertifyInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CertifyInfo_Store(TPM_STORE_BUFFER *sbuffer, + TPM_CERTIFY_INFO *tpm_certify_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo_Store:\n"); + /* store version */ + if (rc == 0) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_certify_info->version)); + } + /* store keyUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_certify_info->keyUsage); + } + /* store keyFlags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_certify_info->keyFlags); + } + /* store authDataUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info->authDataUsage), + sizeof(TPM_AUTH_DATA_USAGE)); + } + /* store algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_certify_info->algorithmParms)); + } + /* store pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_certify_info->pubkeyDigest); + } + /* store data */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_certify_info->data); + } + /* store parentPCRStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info->parentPCRStatus), + sizeof(TPM_BOOL)); + } + /* copy cache to pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_certify_info->pcrInfo), + tpm_certify_info->tpm_pcr_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfo_Store); + } + /* copy pcrInfo to sbuffer */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info->pcrInfo)); + } + return rc; +} + +/* TPM_CertifyInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CertifyInfo_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CertifyInfo_Delete(TPM_CERTIFY_INFO *tpm_certify_info) +{ + printf(" TPM_CertifyInfo_Delete:\n"); + if (tpm_certify_info != NULL) { + TPM_KeyParms_Delete(&(tpm_certify_info->algorithmParms)); + /* pcrInfo */ + TPM_SizedBuffer_Delete(&(tpm_certify_info->pcrInfo)); + /* pcr cache */ + TPM_PCRInfo_Delete(tpm_certify_info->tpm_pcr_info); + free(tpm_certify_info->tpm_pcr_info); + TPM_CertifyInfo_Init(tpm_certify_info); + } + return; +} + +/* TPM_CertifyInfo_Set() fills in tpm_certify_info with the information from the key pointed to be + tpm_key +*/ + +TPM_RESULT TPM_CertifyInfo_Set(TPM_CERTIFY_INFO *tpm_certify_info, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo_Set:\n"); + if (rc == 0) { + tpm_certify_info->keyUsage = tpm_key->keyUsage; + tpm_certify_info->keyFlags = tpm_key->keyFlags; + tpm_certify_info->authDataUsage = tpm_key->authDataUsage; + rc = TPM_KeyParms_Copy(&(tpm_certify_info->algorithmParms), + &(tpm_key->algorithmParms)); + } + /* pubkeyDigest SHALL be a digest of the value TPM_KEY -> pubKey -> key in a TPM_KEY + representation of the key to be certified */ + if (rc == 0) { + rc = TPM_SHA1(tpm_certify_info->pubkeyDigest, + tpm_key->pubKey.size, tpm_key->pubKey.buffer, + 0, NULL); + } + return rc; +} + +/* + TPM_CERTIFY_INFO2 +*/ + +/* TPM_CertifyInfo2_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CertifyInfo2_Init(TPM_CERTIFY_INFO2 *tpm_certify_info2) +{ + printf(" TPM_CertifyInfo2_Init:\n"); + tpm_certify_info2->fill = 0x00; + tpm_certify_info2->payloadType = TPM_PT_ASYM; + tpm_certify_info2->keyUsage = TPM_KEY_UNINITIALIZED; + tpm_certify_info2->keyFlags = 0; + tpm_certify_info2->authDataUsage = TPM_AUTH_ALWAYS; + TPM_KeyParms_Init(&(tpm_certify_info2->algorithmParms)); + TPM_Digest_Init(tpm_certify_info2->pubkeyDigest); + TPM_Nonce_Init(tpm_certify_info2->data); + tpm_certify_info2->parentPCRStatus = TRUE; + TPM_SizedBuffer_Init(&(tpm_certify_info2->pcrInfo)); + TPM_SizedBuffer_Init(&(tpm_certify_info2->migrationAuthority)); + tpm_certify_info2->tpm_pcr_info_short = NULL; + return; +} + +/* TPM_CertifyInfo2_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CertifyInfo2_Init() + After use, call TPM_CertifyInfo2_Delete() to free memory +*/ + +TPM_RESULT TPM_CertifyInfo2_Load(TPM_CERTIFY_INFO2 *tpm_certify_info2, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo2_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CERTIFY_INFO2, stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info2->fill), stream, stream_size); + } + /* check fill immediately to ease debugging */ + if (rc == 0) { + if (tpm_certify_info2->fill != 0x00) { + printf("TPM_CertifyInfo2_Load: Error checking fill %02x\n", tpm_certify_info2->fill); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load payloadType */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info2->payloadType), stream, stream_size); + } + /* load keyUsage */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_certify_info2->keyUsage), stream, stream_size); + } + /* load keyFlags */ + if (rc == 0) { + rc = TPM_KeyFlags_Load(&(tpm_certify_info2->keyFlags), stream, stream_size); + } + /* load authDataUsage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_certify_info2->authDataUsage), stream, stream_size); + } + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_certify_info2->algorithmParms), stream, stream_size); + } + /* load pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_certify_info2->pubkeyDigest, stream, stream_size); + } + /* load data */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_certify_info2->data, stream, stream_size); + } + /* load parentPCRStatus */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_certify_info2->parentPCRStatus), stream, stream_size); + } + /* load pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_certify_info2->pcrInfo), stream, stream_size); + } + /* set TPM_PCR_INFO2 tpm_pcr_info cache from pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfoShort_CreateFromBuffer(&(tpm_certify_info2->tpm_pcr_info_short), + &(tpm_certify_info2->pcrInfo)); + } + /* load migrationAuthority */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_certify_info2->migrationAuthority), stream, stream_size); + } + /* check migrationAuthority immediately to ease debugging */ + if (rc == 0) { + if ((tpm_certify_info2->migrationAuthority.buffer != NULL) && + (tpm_certify_info2->migrationAuthority.size != TPM_DIGEST_SIZE)) { + printf("TPM_CertifyInfo2_Load: Error checking migrationAuthority %p, %u\n", + tpm_certify_info2->migrationAuthority.buffer, + tpm_certify_info2->migrationAuthority.size); + rc = TPM_INVALID_STRUCTURE; + } + } + return rc; +} + +/* TPM_CertifyInfo2_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CertifyInfo2_Store(TPM_STORE_BUFFER *sbuffer, + TPM_CERTIFY_INFO2 *tpm_certify_info2) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CertifyInfo2_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CERTIFY_INFO2); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->fill), sizeof(BYTE)); + } + /* store payloadType */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->payloadType), + sizeof(TPM_PAYLOAD_TYPE)); + } + /* store keyUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_certify_info2->keyUsage); + } + /* store keyFlags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_certify_info2->keyFlags); + } + /* store authDataUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->authDataUsage), + sizeof(TPM_AUTH_DATA_USAGE)); + } + /* store algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_certify_info2->algorithmParms)); + } + /* store pubkeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_certify_info2->pubkeyDigest); + } + /* store data */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_certify_info2->data); + } + /* store parentPCRStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_certify_info2->parentPCRStatus), + sizeof(TPM_BOOL)); + } + /* copy cache to pcrInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_certify_info2->pcrInfo), + tpm_certify_info2->tpm_pcr_info_short, + (TPM_STORE_FUNCTION_T)TPM_PCRInfoShort_Store); + } + /* copy pcrInfo to sbuffer */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info2->pcrInfo)); + } + /* store migrationAuthority */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_certify_info2->migrationAuthority)); + } + return rc; +} + +/* TPM_CertifyInfo2_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CertifyInfo2_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CertifyInfo2_Delete(TPM_CERTIFY_INFO2 *tpm_certify_info2) +{ + printf(" TPM_CertifyInfo2_Delete:\n"); + if (tpm_certify_info2 != NULL) { + TPM_KeyParms_Delete(&(tpm_certify_info2->algorithmParms)); + /* pcrInfo */ + TPM_SizedBuffer_Delete(&(tpm_certify_info2->pcrInfo)); + /* pcr cache */ + TPM_PCRInfoShort_Delete(tpm_certify_info2->tpm_pcr_info_short); + free(tpm_certify_info2->tpm_pcr_info_short); + TPM_SizedBuffer_Delete(&(tpm_certify_info2->migrationAuthority)); + TPM_CertifyInfo2_Init(tpm_certify_info2); + } + return; +} + +/* TPM_CertifyInfo2_Set() fills in tpm_certify_info2 with the information from the key pointed to by + tpm_key. + +*/ + +TPM_RESULT TPM_CertifyInfo2_Set(TPM_CERTIFY_INFO2 *tpm_certify_info2, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_CertifyInfo_Set:\n"); + /* get the TPM_STORE_ASYMKEY object */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + tpm_certify_info2->payloadType = tpm_store_asymkey->payload; + tpm_certify_info2->keyUsage = tpm_key->keyUsage; + tpm_certify_info2->keyFlags = tpm_key->keyFlags; + tpm_certify_info2->authDataUsage = tpm_key->authDataUsage; + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + rc = TPM_KeyParms_Copy(&(tpm_certify_info2->algorithmParms), + &(tpm_key->algorithmParms)); + } + /* pubkeyDigest SHALL be a digest of the value TPM_KEY -> pubKey -> key in a TPM_KEY + representation of the key to be certified */ + if (rc == 0) { + rc = TPM_SHA1(tpm_certify_info2->pubkeyDigest, + tpm_key->pubKey.size, tpm_key->pubKey.buffer, + 0, NULL); + } + return rc; +} + +/* + TPM_SYMMETRIC_KEY +*/ + +/* TPM_SymmetricKey_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SymmetricKey_Init(TPM_SYMMETRIC_KEY *tpm_symmetric_key) +{ + printf(" TPM_SymmetricKey_Init:\n"); + tpm_symmetric_key->algId = 0; + tpm_symmetric_key->encScheme = TPM_ES_NONE; + tpm_symmetric_key->size = 0; + tpm_symmetric_key->data = NULL; + return; +} + +/* TPM_SymmetricKey_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_SymmetricKey_Init() + After use, call TPM_SymmetricKey_Delete() to free memory +*/ + +TPM_RESULT TPM_SymmetricKey_Load(TPM_SYMMETRIC_KEY *tpm_symmetric_key, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKey_Load:\n"); + /* load algId */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_symmetric_key->algId), stream, stream_size); + } + /* load encScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_symmetric_key->encScheme), stream, stream_size); + } + /* load size */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_symmetric_key->size), stream, stream_size); + } + /* allocate memory for the data */ + if ((rc == 0) && (tpm_symmetric_key->size > 0)) { + rc = TPM_Malloc(&(tpm_symmetric_key->data), tpm_symmetric_key->size); + } + /* load data */ + if ((rc == 0) && (tpm_symmetric_key->size > 0)) { + rc = TPM_Loadn(tpm_symmetric_key->data, tpm_symmetric_key->size, stream, stream_size); + } + return rc; +} + +/* TPM_SymmetricKey_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_SymmetricKey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY *tpm_symmetric_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKey_Store:\n"); + /* store algId */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_symmetric_key->algId); + } + /* store encScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key->encScheme); + } + /* NOTE: Cannot use TPM_SizedBuffer_Store since the first parameter is a uint16_t */ + /* store size */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_symmetric_key->size); + } + /* store data */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_symmetric_key->data, tpm_symmetric_key->size); + } + return rc; +} + +/* TPM_SymmetricKey_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_SymmetricKey_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_SymmetricKey_Delete(TPM_SYMMETRIC_KEY *tpm_symmetric_key) +{ + printf(" TPM_SymmetricKey_Delete:\n"); + if (tpm_symmetric_key != NULL) { + free(tpm_symmetric_key->data); + TPM_SymmetricKey_Init(tpm_symmetric_key); + } + return; +} + +/* TPM_SymmetricKeyData_EncryptSbuffer() encrypts 'sbuffer' to 'encrypt_data' + + Padding is included, so the output may be larger than the input. + + 'encrypt_data' must be free by the caller +*/ + +TPM_RESULT TPM_SymmetricKeyData_EncryptSbuffer(TPM_SIZED_BUFFER *encrypt_data, + TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_data) +{ + TPM_RESULT rc = 0; + const unsigned char *decrypt_data; /* serialization buffer */ + uint32_t decrypt_data_size; /* serialization size */ + + printf(" TPM_SymmetricKeyData_EncryptSbuffer:\n"); + if (rc == 0) { + /* get the serialization results */ + TPM_Sbuffer_Get(sbuffer, &decrypt_data, &decrypt_data_size); + /* platform dependent symmetric key encrypt */ + rc = TPM_SymmetricKeyData_Encrypt(&(encrypt_data->buffer), /* output, caller frees */ + &(encrypt_data->size), /* output */ + decrypt_data, /* input */ + decrypt_data_size, /* input */ + tpm_symmetric_key_data); + } + return rc; +} + +/* TPM_SymmetricKeyData_StreamCrypt() encrypts or decrypts 'data_in' to 'data_out ' + + It assumes that the size of data_out and data_in are equal, and that a stream cipher mode is + used. For the supported stream ciphers, encrypt and decrypt are equivalent, so no direction flag + is required. + + AES 128 with CTR or OFB modes are supported. For CTR mode, pad is the initial count. For OFB + mode, pad is the IV. +*/ + +TPM_RESULT TPM_SymmetricKeyData_StreamCrypt(unsigned char *data_out, /* output */ + const unsigned char *data_in, /* input */ + uint32_t data_size, /* input */ + TPM_ALGORITHM_ID algId, /* algorithm */ + TPM_ENC_SCHEME encScheme, /* mode */ + const unsigned char *symmetric_key, /* input */ + uint32_t symmetric_key_size, /* input */ + unsigned char *pad_in, /* input */ + uint32_t pad_in_size) /* input */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_SymmetricKeyData_StreamCrypt:\n"); + switch (algId) { + case TPM_ALG_AES128: + switch (encScheme) { + case TPM_ES_SYM_CTR: + rc = TPM_SymmetricKeyData_CtrCrypt(data_out, + data_in, + data_size, + symmetric_key, + symmetric_key_size, + pad_in, + pad_in_size); + break; + case TPM_ES_SYM_OFB: + rc = TPM_SymmetricKeyData_OfbCrypt(data_out, + data_in, + data_size, + symmetric_key, + symmetric_key_size, + pad_in, + pad_in_size); + break; + default: + printf("TPM_SymmetricKeyData_StreamCrypt: Error, bad AES128 encScheme %04x\n", + encScheme); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + break; + default: + printf("TPM_SymmetricKeyData_StreamCrypt: Error, bad algID %08x\n", algId); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + return rc; +} + +/* These functions perform high-level, platform independent functions. + They call the lower level, platform dependent crypto functions in + tpm_crypto.c +*/ + +/* TPM_SHA1Sbuffer() calculates the SHA-1 digest of a TPM_STORE_BUFFER. + + This is commonly used when calculating a digest on a serialized structure. Structures are + serialized to a TPM_STORE_BUFFER. + + The TPM_STORE_BUFFER is not deleted. +*/ + +TPM_RESULT TPM_SHA1Sbuffer(TPM_DIGEST tpm_digest, + TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_SHA1Sbuffer:\n"); + if (rc == 0) { + /* get the components of the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + TPM_PrintFour(" TPM_SHA1Sbuffer: input", buffer); + /* hash the serialized buffer to tpm_digest */ + rc = TPM_SHA1(tpm_digest, + length, buffer, + 0, NULL); + } + return rc; +} + +/* TPM_SHA1_GenerateStructure() generates a SHA-1 digest of a structure. It serializes the + structure and hashes the result. + + tpmStructure is the structure to be serialized + storeFunction is the serialization function for the structure +*/ + +TPM_RESULT TPM_SHA1_GenerateStructure(TPM_DIGEST tpm_digest, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + + printf(" TPM_SHA1_GenerateStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* Serialize the structure */ + if (rc == 0) { + rc = storeFunction(&sbuffer, tpmStructure); + } + /* hash the serialized buffer to tpm_hmac */ + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_SHA1_CheckStructure() generates a SHA-1 digest of a structure. It serializes the structure + and hashes the result. It compares the result to 'expected_digest' and returns 'error' on + mismatch. + + tpmStructure is the structure to be serialized + storeFunction is the serialization function for the structure +*/ + + + +TPM_RESULT TPM_SHA1_CheckStructure(TPM_DIGEST expected_digest, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction, + TPM_RESULT error) +{ + TPM_RESULT rc = 0; + TPM_DIGEST actual_digest; + + printf(" TPM_SHA1_CheckStructure:\n"); + /* hash the serialized buffer to tpm_digest */ + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(actual_digest, tpmStructure, storeFunction); + } + /* check the digests */ + if (rc == 0) { + rc = TPM_Digest_Compare(actual_digest, expected_digest); + if (rc != 0) { + rc = error; + } + } + return rc; +} + +/* TPM_SHA1() can be called directly to hash a list of streams. + + The ... arguments to be hashed are a list of the form + size_t length, unsigned char *buffer + terminated by a 0 length + */ + +TPM_RESULT TPM_SHA1(TPM_DIGEST md, ...) +{ + TPM_RESULT rc = 0; + va_list ap; + + printf(" TPM_SHA1:\n"); + va_start(ap, md); + rc = TPM_SHA1_valist(md, 0, NULL, ap); + va_end(ap); + return rc; +} + +/* TPM_SHA1_Check() digests the list of streams and compares the result to 'digest_expect' + */ + +TPM_RESULT TPM_SHA1_Check(TPM_DIGEST digest_expect, ...) +{ + TPM_RESULT rc = 0; + TPM_DIGEST digest_actual; + va_list ap; + + printf(" TPM_SHA1_Check:\n"); + if (rc == 0) { + va_start(ap, digest_expect); + rc = TPM_SHA1_valist(digest_actual, 0, NULL, ap); + va_end(ap); + } + if (rc == 0) { + rc = TPM_Digest_Compare(digest_expect, digest_actual); + } + return rc; +} + +/* TPM_SHA1_valist() is the internal function, called with the va_list already created. + + It is called from TPM_SHA1() to do a simple hash. Typically length0==0 and buffer0==NULL. + + It can also be called from the HMAC function to hash the variable number of input parameters. In + that case, the va_list for the text is already formed. length0 and buffer0 are used to input the + padded key. +*/ + +static TPM_RESULT TPM_SHA1_valist(TPM_DIGEST md, + uint32_t length0, unsigned char *buffer0, + va_list ap) +{ + TPM_RESULT rc = 0; + uint32_t length; + unsigned char *buffer; + void *context = NULL; /* platform dependent context */ + TPM_BOOL done = FALSE; + + printf(" TPM_SHA1_valist:\n"); + if (rc == 0) { + rc = TPM_SHA1InitCmd(&context); + } + if (rc == 0) { + if (length0 !=0) { /* optional first text block */ + printf(" TPM_SHA1_valist: Digesting %u bytes\n", length0); + rc = TPM_SHA1UpdateCmd(context, buffer0, length0); /* hash the buffer */ + } + } + while ((rc == 0) && !done) { + length = va_arg(ap, uint32_t); /* first vararg is the length */ + if (length != 0) { /* loop until a zero length argument terminates */ + buffer = va_arg(ap, unsigned char *); /* second vararg is the array */ + printf(" TPM_SHA1_valist: Digesting %u bytes\n", length); + rc = TPM_SHA1UpdateCmd(context, buffer, length); /* hash the buffer */ + } + else { + done = TRUE; + } + } + if (rc == 0) { + rc = TPM_SHA1FinalCmd(md, context); + } + if (rc == 0) { + TPM_PrintFour(" TPM_SHA1_valist: Digest", md); + } + /* call TPM_SHA1Delete even if there was an error */ + TPM_SHA1Delete(&context); + return rc; +} + +/* TPM_HMAC_GenerateSbuffer() calculates the HMAC digest of a TPM_STORE_BUFFER. + + This is commonly used when calculating an HMAC on a serialized structure. Structures are + serialized to a TPM_STORE_BUFFER. + + The TPM_STORE_BUFFER is not deleted. +*/ + +TPM_RESULT TPM_HMAC_GenerateSbuffer(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_HMAC_GenerateSbuffer:\n"); + if (rc == 0) { + /* get the components of the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* HMAC the serialized buffer to tpm_hmac */ + rc = TPM_HMAC_Generate(tpm_hmac, + hmac_key, + length, buffer, + 0, NULL); + } + return rc; +} + +/* TPM_HMAC_GenerateStructure() generates an HMAC of a structure. It serializes the structure and + HMAC's the result. + + hmacKey is the HMAC key + tpmStructure is the structure to be serialized + storeFunction is the serialization function for the structure +*/ + +TPM_RESULT TPM_HMAC_GenerateStructure(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + + printf(" TPM_HMAC_GenerateStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* Serialize the structure */ + if (rc == 0) { + rc = storeFunction(&sbuffer, tpmStructure); + } + /* hash the serialized buffer to tpm_hmac */ + if (rc == 0) { + rc = TPM_HMAC_GenerateSbuffer(tpm_hmac, hmac_key, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_HMAC_Generate() can be called directly to HMAC a list of streams. + + The ... arguments are a message list of the form + size_t length, unsigned char *buffer + terminated by a 0 length +*/ + +TPM_RESULT TPM_HMAC_Generate(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + ...) +{ + TPM_RESULT rc = 0; + va_list ap; + + printf(" TPM_HMAC_Generate:\n"); + va_start(ap, hmac_key); + rc = TPM_HMAC_Generatevalist(tpm_hmac, hmac_key, ap); + va_end(ap); + return rc; +} + +/* TPM_HMAC_Generatevalist() is the internal function, called with the va_list already created. + + It is called from TPM_HMAC_Generate() and TPM_HMAC_Check() with the va_list for the text already + formed. +*/ + +#define TPM_HMAC_BLOCK_SIZE 64 + +static TPM_RESULT TPM_HMAC_Generatevalist(TPM_HMAC tpm_hmac, + const TPM_SECRET key, + va_list ap) +{ + TPM_RESULT rc = 0; + unsigned char ipad[TPM_HMAC_BLOCK_SIZE]; + unsigned char opad[TPM_HMAC_BLOCK_SIZE]; + size_t i; + TPM_DIGEST inner_hash; + + printf(" TPM_HMAC_Generatevalist:\n"); + /* calculate key XOR ipad and key XOR opad */ + if (rc == 0) { + /* first part, key XOR pad */ + for (i = 0 ; i < TPM_AUTHDATA_SIZE ; i++) { + ipad[i] = key[i] ^ 0x36; /* magic numbers from RFC 2104 */ + opad[i] = key[i] ^ 0x5c; + } + /* second part, 0x00 XOR pad */ + memset(ipad + TPM_AUTHDATA_SIZE, 0x36, TPM_HMAC_BLOCK_SIZE - TPM_AUTHDATA_SIZE); + memset(opad + TPM_AUTHDATA_SIZE, 0x5c, TPM_HMAC_BLOCK_SIZE - TPM_AUTHDATA_SIZE); + /* calculate the inner hash, hash the key XOR ipad and the text */ + rc = TPM_SHA1_valist(inner_hash, + TPM_HMAC_BLOCK_SIZE, ipad, ap); + } + /* hash the key XOR opad and the previous hash */ + if (rc == 0) { + rc = TPM_SHA1(tpm_hmac, + TPM_HMAC_BLOCK_SIZE, opad, + TPM_DIGEST_SIZE, inner_hash, + 0, NULL); + } + if (rc == 0) { + TPM_PrintFour(" TPM_HMAC_Generatevalist: HMAC", tpm_hmac); + } + return rc; +} + +/* TPM_HMAC_CheckSbuffer() checks the HMAC of a TPM_STORE_BUFFER. + + This is commonly used when checking an HMAC on a serialized structure. Structures are serialized + to a TPM_STORE_BUFFER. + + The TPM_STORE_BUFFER is not deleted. +*/ + +TPM_RESULT TPM_HMAC_CheckSbuffer(TPM_BOOL *valid, /* result */ + TPM_HMAC expect, /* expected */ + const TPM_SECRET hmac_key, /* key */ + TPM_STORE_BUFFER *sbuffer) /* data stream */ +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_HMAC_CheckSbuffer:\n"); + if (rc == 0) { + /* get the components of the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* HMAC the serialized buffer to tpm_hmac */ + rc = TPM_HMAC_Check(valid, + expect, + hmac_key, + length, buffer, + 0, NULL); + } + return rc; +} + +/* TPM_HMAC_Check() can be called directly to check the HMAC of a list of streams. + + The ... arguments are a list of the form + size_t length, unsigned char *buffer + terminated by a 0 length + +*/ + +TPM_RESULT TPM_HMAC_Check(TPM_BOOL *valid, + TPM_HMAC expect, + const TPM_SECRET key, + ...) +{ + TPM_RESULT rc = 0; + va_list ap; + TPM_HMAC actual; + int result; + + printf(" TPM_HMAC_Check:\n"); + va_start(ap, key); + if (rc == 0) { + rc = TPM_HMAC_Generatevalist(actual, key, ap); + } + if (rc == 0) { + TPM_PrintFour(" TPM_HMAC_Check: Calculated", actual); + TPM_PrintFour(" TPM_HMAC_Check: Received ", expect); + result = memcmp(expect, actual, TPM_DIGEST_SIZE); + if (result == 0) { + *valid = TRUE; + } + else { + *valid = FALSE; + } + } + va_end(ap); + return rc; +} + +/* TPM_HMAC_CheckStructure() is a generic function that checks the integrity HMAC of a structure. + + hmacKey is the HMAC key + tpmStructure is the structure to be serialized + expect is the expected HMAC, a member of the structure + storeFunction is the serialization function for the structure + error is the failure return code + + The function saves a copy of the expected HMAC, and then NULL's the structure member. It + serializes the structure, generates an HMAC, and compares it to the expected value. + + As a side effect, the structure member is zeroed. +*/ + +TPM_RESULT TPM_HMAC_CheckStructure(const TPM_SECRET hmac_key, + void *tpmStructure, + TPM_HMAC expect, + TPM_STORE_FUNCTION_T storeFunction, + TPM_RESULT error) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + TPM_HMAC saveExpect; + TPM_BOOL valid; + + printf(" TPM_HMAC_CheckStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + if (rc == 0) { + TPM_Digest_Copy(saveExpect, expect); /* save the expected value */ + TPM_Digest_Init(expect); /* set value in structure to NULL */ + rc = storeFunction(&sbuffer, + tpmStructure); + } + /* verify the HMAC of the serialized structure */ + if (rc == 0) { + rc = TPM_HMAC_CheckSbuffer(&valid, /* result */ + saveExpect, /* expected */ + hmac_key, /* key */ + &sbuffer); /* data stream */ + } + if (rc == 0) { + if (!valid) { + printf("TPM_HMAC_CheckStructure: Error checking HMAC\n"); + rc = error; + } + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_XOR XOR's 'in1' and 'in2' of 'length', putting the result in 'out' + +*/ + +void TPM_XOR(unsigned char *out, + const unsigned char *in1, + const unsigned char *in2, + size_t length) +{ + size_t i; + + for (i = 0 ; i < length ; i++) { + out[i] = in1[i] ^ in2[i]; + } + return; +} + +/* TPM_MGF1() generates an MGF1 'array' of length 'arrayLen' from 'seed' of length 'seedlen' + + The openSSL DLL doesn't export MGF1 in Windows or Linux 1.0.0, so this version is created from + scratch. + + Algorithm and comments (not the code) from: + + PKCS #1: RSA Cryptography Specifications Version 2.1 B.2.1 MGF1 + + Prototype designed to be compatible with openSSL + + MGF1 is a Mask Generation Function based on a hash function. + + MGF1 (mgfSeed, maskLen) + + Options: + + Hash hash function (hLen denotes the length in octets of the hash + function output) + + Input: + + mgfSeed seed from which mask is generated, an octet string + maskLen intended length in octets of the mask, at most 2^32(hLen) + + Output: + mask mask, an octet string of length l; or "mask too long" + + Error: "mask too long' +*/ + +TPM_RESULT TPM_MGF1(unsigned char *mask, + uint32_t maskLen, + const unsigned char *mgfSeed, + uint32_t mgfSeedlen) +{ + TPM_RESULT rc = 0; + unsigned char counter[4]; /* 4 octets */ + uint32_t count; /* counter as an integral type */ + uint32_t outLen; + TPM_DIGEST lastDigest; + + printf(" TPM_MGF1: Output length %u\n", maskLen); + if (rc == 0) { + /* this is possible with arrayLen on a 64 bit architecture, comment to quiet beam */ + if ((maskLen / TPM_DIGEST_SIZE) > 0xffffffff) { /*constant condition*/ + printf(" TPM_MGF1: Error (fatal), Output length too large for 32 bit counter\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* 1.If l > 2^32(hLen), output "mask too long" and stop. */ + /* NOTE Checked by caller */ + /* 2. Let T be the empty octet string. */ + /* 3. For counter from 0 to [masklen/hLen] - 1, do the following: */ + for (count = 0, outLen = 0 ; (rc == 0) && (outLen < maskLen) ; count++) { + /* a. Convert counter to an octet string C of length 4 octets - see Section 4.1 */ + /* C = I2OSP(counter, 4) NOTE Basically big endian */ + uint32_t count_n = htonl(count); + memcpy(counter, &count_n, 4); + /* b.Concatenate the hash of the seed mgfSeed and C to the octet string T: */ + /* T = T || Hash (mgfSeed || C) */ + /* If the entire digest is needed for the mask */ + if ((outLen + TPM_DIGEST_SIZE) < maskLen) { + rc = TPM_SHA1(mask + outLen, + mgfSeedlen, mgfSeed, + 4, counter, + 0, NULL); + outLen += TPM_DIGEST_SIZE; + } + /* if the mask is not modulo TPM_DIGEST_SIZE, only part of the final digest is needed */ + else { + /* hash to a temporary digest variable */ + rc = TPM_SHA1(lastDigest, + mgfSeedlen, mgfSeed, + 4, counter, + 0, NULL); + /* copy what's needed */ + memcpy(mask + outLen, lastDigest, maskLen - outLen); + outLen = maskLen; /* outLen = outLen + maskLen - outLen */ + } + } + /* 4.Output the leading l octets of T as the octet string mask. */ + return rc; +} + +/* TPM_MGF1_GenerateArray() generates an array of length arrayLen using the varargs as the seed. + + Since the seed is a known length, it is passed in rather that extracted from the varargs. If the + seed length turns out to be wrong once the varargs are parsed, TPM_FAIL is returned. + + 'array' must be freed by the caller. +*/ + +TPM_RESULT TPM_MGF1_GenerateArray(unsigned char **array, + uint32_t arrayLen, + uint32_t seedLen, + ...) +{ + TPM_RESULT rc = 0; + va_list ap; + unsigned char *seed; /* constructed MGF1 seed */ + size_t vaLength; /* next seed segment length */ + unsigned char *vaBuffer; /* next seed segment buffer */ + uint32_t seedLeft; /* remaining seed bytes required */ + unsigned char *seedBuffer; /* running pointer to the seed array */ + TPM_BOOL done = FALSE; /* done when a vaLength == 0 is reached */ + + printf(" TPM_MGF1_GenerateArray: arrayLen %u seedLen %u\n", arrayLen, seedLen); + seed = NULL; /* freed @1 */ + *array = NULL; /* freed by caller */ + va_start(ap, seedLen); + /* allocate temporary memory for the seed */ + if (rc == 0) { + rc = TPM_Malloc(&seed, seedLen); + seedBuffer = seed; + seedLeft = seedLen; + } + /* construct the seed */ + while ((rc == 0) && !done) { + vaLength = (size_t)va_arg(ap, uint32_t); /* first vararg is the length */ + if (vaLength != 0) { /* loop until a zero length argument terminates */ + if (rc == 0) { + printf(" TPM_MGF1_GenerateArray: Appending %lu bytes\n", (unsigned long)vaLength); + if (vaLength > seedLeft) { + printf("TPM_MGF1_GenerateArray: Error (fatal), seedLen too small\n"); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + if (rc == 0) { + vaBuffer = va_arg(ap, unsigned char *); /* second vararg is the array */ + memcpy(seedBuffer, vaBuffer, vaLength); + seedBuffer += vaLength; + seedLeft-= vaLength; + } + } + else { + done = TRUE; + if (seedLeft != 0) { + printf("TPM_MGF1_GenerateArray: Error (fatal), seedLen too large by %u\n", + seedLeft); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + } + /* allocate memory for the array */ + if (rc == 0) { + rc = TPM_Malloc(array, arrayLen); + } + /* generate the MGF1 array */ + if (rc == 0) { + TPM_MGF1(*array, + arrayLen, + seed, + seedLen); + TPM_PrintFour(" TPM_MGF1_GenerateArray: MGF1", *array); + } + va_end(ap); + free(seed); /* @1 */ + return rc; +} + +/* TPM_bn2binMalloc() allocates a buffer 'bin' and loads it from 'bn'. + 'bytes' is set to the allocated size of 'bin'. + + If padBytes is non-zero, 'bin' is padded with leading zeros if necessary, so that 'bytes' will + equal 'padBytes'. This is used when TPM data structures expect a fixed length while the crypto + library 'bn to bin' function might truncates leading zeros. + + '*bin' must be freed by the caller +*/ + +TPM_RESULT TPM_bn2binMalloc(unsigned char **bin, /* freed by caller */ + unsigned int *bytes, + TPM_BIGNUM bn, + uint32_t padBytes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_bn2binMalloc: padBytes %u\n", padBytes); + /* number of bytes required in the bin array */ + if (rc == 0) { + rc = TPM_BN_num_bytes(bytes, bn); + } + /* calculate the array size to malloc */ + if (rc == 0) { + /* padBytes 0 says that no padding is required */ + if (padBytes == 0) { + padBytes = *bytes; /* setting equal yields no padding */ + } + /* if the array with padding is still less than the number of bytes required by the bignum, + this function fails */ + if (padBytes < *bytes) { + printf("TPM_bn2binMalloc: Error, " + "padBytes %u less than BN bytes %u\n", padBytes, *bytes); + rc = TPM_SIZE; + } + /* log if padding is occurring */ + if (padBytes != *bytes) { + printf(" TPM_bn2binMalloc: padBytes %u bytes %u\n", padBytes, *bytes); + } + } + /* allocate for the padded array */ + if (rc == 0) { + rc = TPM_Malloc(bin, padBytes); + *bytes = padBytes; + } + /* call the bignum to bin conversion */ + if (rc == 0) { + rc = TPM_bn2binArray(*bin, padBytes, bn); + } + return rc; +} + +/* TPM_bn2binArray() loads the array 'bin' of size 'bytes' from 'bn' + + The data from 'bn' is right justified and zero padded. +*/ + +TPM_RESULT TPM_bn2binArray(unsigned char *bin, + unsigned int bytes, + TPM_BIGNUM bn) +{ + TPM_RESULT rc = 0; + unsigned int numBytes; + + printf(" TPM_bn2binArray: size %u\n", bytes); + if (rc == 0) { + /* zero pad */ + memset(bin, 0, bytes); + /* bytes required for the bignum */ + rc = TPM_BN_num_bytes(&numBytes, bn); + } + /* if the array is less than the number of bytes required by the bignum, this function fails */ + if (rc == 0) { + printf(" TPM_bn2binArray: numBytes in bignum %u\n", numBytes); + if (numBytes > bytes) { + printf("TPM_bn2binArray: Error, " + "BN bytes %u greater than array bytes %u\n", numBytes, bytes); + rc = TPM_SIZE; + } + } + if (rc == 0) { + /* if there are bytes in the bignum (it is not zero) */ + if (numBytes > 0) { + rc = TPM_bn2bin(bin + bytes - numBytes, /* store right justified */ + bn); + } + } + return rc; +} + +/* TPM_2bin2bn() converts two byte arrays to a positive BIGNUM. + + The two byte arrays are concatenated. The concatenation is used to create the BIGNUM. + + bignum must be freed by the caller. +*/ + +TPM_RESULT TPM_2bin2bn(TPM_BIGNUM *bignum_in, /* freed by caller */ + const unsigned char *bin0, uint32_t size0, + const unsigned char *bin1, uint32_t size1) +{ + TPM_RESULT rc = 0; /* TPM return code */ + TPM_STORE_BUFFER sBuffer; /* used of >1 element or first element is negative */ + const unsigned char *buffer; + uint32_t size; + + printf(" TPM_bin2bn:\n"); + TPM_Sbuffer_Init(&sBuffer); /* freed @1 */ + /* append the first element */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(&sBuffer, bin0, size0); + } + /* append the next element */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(&sBuffer, bin1, size1); + } + /* create the BIGNUM from the array */ + if (rc == 0) { + TPM_Sbuffer_Get(&sBuffer, &buffer, &size); + /* create the BIGNUM */ + rc = TPM_bin2bn(bignum_in, buffer, size); /* freed by caller */ + } + TPM_Sbuffer_Delete(&sBuffer); /* @1 */ + return rc; +} + +/* TPM_RSAPrivateDecryptMalloc() allocates a buffer 'decrypt_data' of size 'decrypt_data_size' + and then calls TPM_RSAPrivateDecryptH(). +*/ + +TPM_RESULT TPM_RSAPrivateDecryptMalloc(unsigned char **decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + unsigned char *encrypt_data, + uint32_t encrypt_data_size, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + /* allocate space for the decrypted blob */ + printf(" TPM_RSAPrivateDecryptMalloc: Return max data size %u bytes\n", + tpm_key->pubKey.size); + if (rc == 0) { + rc = TPM_Malloc(decrypt_data, tpm_key->pubKey.size); + } + if (rc == 0) { + rc = TPM_RSAPrivateDecryptH(*decrypt_data, + decrypt_data_length, + tpm_key->pubKey.size, + encrypt_data, + encrypt_data_size, + tpm_key); + } + return rc; +} + +/* TPM_RSAPrivateDecryptH() decrypts 'encrypt_data' using the private key in + 'tpm_key' and 'decrypt_data_length' bytes are moved to 'decrypt_data'. + + 'decrypt_data_length' is at most 'decrypt_data_size'. +*/ + +TPM_RESULT TPM_RSAPrivateDecryptH(unsigned char *decrypt_data, /* decrypted data */ + uint32_t *decrypt_data_length, /* length of data put into + decrypt_data */ + uint32_t decrypt_data_size, /* size of decrypt_data buffer */ + unsigned char *encrypt_data, + uint32_t encrypt_data_size, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + unsigned char *darr; /* private exponent */ + uint32_t dbytes; + + printf(" TPM_RSAPrivateDecryptH: Data size %u bytes\n", encrypt_data_size); + TPM_PrintFour(" TPM_RSAPrivateDecryptH: Encrypt data", encrypt_data); + if (rc == 0) { + if (tpm_key == NULL) { + printf("TPM_RSAPrivateDecryptH: Error, NULL key\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* extract the public key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + /* extract the private key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPrivateKey(&dbytes, &darr, tpm_key); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + /* check the key size vs the data size */ + if (rc == 0) { + if (encrypt_data_size > nbytes) { + printf("TPM_RSAPrivateDecryptH: Error, data size too long for key size %u bytes\n", + nbytes); + rc = TPM_BAD_DATASIZE; + } + } + if (rc == 0) { + /* debug printing */ + printf(" TPM_RSAPrivateDecryptH: Public key length %u\n", nbytes); + printf(" TPM_RSAPrivateDecryptH: Private key length %u\n", dbytes); + TPM_PrintFour(" TPM_RSAPrivateDecryptH: Public key", narr); + printf(" TPM_RSAPrivateDecryptH: Exponent %02x %02x %02x\n", earr[0], earr[1], earr[2]); + TPM_PrintFour(" TPM_RSAPrivateDecryptH: Private key", darr); + /* decrypt with private key */ + rc = TPM_RSAPrivateDecrypt(decrypt_data, /* decrypted data */ + decrypt_data_length, /* length of data put into decrypt_data */ + decrypt_data_size, /* size of decrypt_data buffer */ + tpm_key->algorithmParms.encScheme, /* encryption scheme */ + encrypt_data, /* encrypted data */ + encrypt_data_size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPrivateDecryptH: Decrypt data", decrypt_data); + } + return rc; +} + +/* TPM_RSAPublicEncryptSbuffer_Key() encrypts 'sbuffer' using the public key in 'tpm_key' and + puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncryptSbuffer_Key(TPM_SIZED_BUFFER *enc_data, + TPM_STORE_BUFFER *sbuffer, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + const unsigned char *decrypt_data; /* serialization buffer */ + uint32_t decrypt_data_size; /* serialization size */ + + printf(" TPM_RSAPublicEncryptSbuffer_Key:\n"); + /* get the serialization results */ + TPM_Sbuffer_Get(sbuffer, &decrypt_data, &decrypt_data_size); + /* encrypt the serialization buffer with the public key, and place + the result in the enc_data buffer */ + rc = TPM_RSAPublicEncrypt_Key(enc_data, + decrypt_data, + decrypt_data_size, + tpm_key); + return rc; +} + +/* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key in 'tpm_key' and + puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncrypt_Key(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + printf(" TPM_RSAPublicEncrypt_Key: Data size %lu bytes\n", (unsigned long)decrypt_data_size); + if (rc == 0) { + if (tpm_key == NULL) { + printf("TPM_RSAPublicEncrypt_Key: Error, NULL key\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + /* extract the public key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + if (rc == 0) { + rc = TPM_RSAPublicEncrypt_Common(enc_data, + decrypt_data, + decrypt_data_size, + tpm_key->algorithmParms.encScheme, /* encryption scheme */ + narr, + nbytes, + earr, + ebytes); + } + return rc; +} + +/* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key in 'tpm_pubkey' and + puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncrypt_Pubkey(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + printf(" TPM_RSAPublicEncrypt_Pubkey: Data size %lu bytes\n", (unsigned long)decrypt_data_size); + if (rc == 0) { + if (tpm_pubkey == NULL) { + printf("TPM_RSAPublicEncrypt_Pubkey: Error, NULL key\n"); + rc = TPM_ENCRYPT_ERROR; + } + } + /* extract the public key from TPM_PUBKEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetPublicKey(&nbytes, &narr, tpm_pubkey); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetExponent(&ebytes, &earr, tpm_pubkey); + } + if (rc == 0) { + rc = TPM_RSAPublicEncrypt_Common(enc_data, + decrypt_data, + decrypt_data_size, + tpm_pubkey->algorithmParms.encScheme, + narr, + nbytes, + earr, + ebytes); + } + return rc; +} + +/* TPM_RSAPublicEncrypt_Key() encrypts 'buffer' of 'length' using the public key modulus and + exponent, and puts the results in 'encData' +*/ + +TPM_RESULT TPM_RSAPublicEncrypt_Common(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_ENC_SCHEME encScheme, + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) + +{ + TPM_RESULT rc = 0; + unsigned char *encrypt_data = NULL; + + printf(" TPM_RSAPublicEncrypt_Common: Data size %lu bytes\n", (unsigned long)decrypt_data_size); + TPM_PrintFour(" TPM_RSAPublicEncrypt_Common: Decrypt data", decrypt_data); + /* check the key size vs the data size */ + if (rc == 0) { + if (decrypt_data_size > nbytes) { + printf("TPM_RSAPublicEncrypt_Common: Error, data size too long for key size %u bytes\n", + nbytes); + rc = TPM_BAD_DATASIZE; + } + } + /* allocate an array for the encrypted data */ + if (rc == 0) { + rc = TPM_Malloc(&encrypt_data, nbytes); + } + /* pad and encrypt the data */ + if (rc == 0) { + TPM_PrintFour(" TPM_RSAPublicEncrypt_Common: Public key", narr); + printf(" TPM_RSAPublicEncrypt_Common: Exponent %02x %02x %02x\n", + earr[0], earr[1], earr[2]); + rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ + nbytes, /* encrypted data size */ + encScheme, /* encryption scheme */ + decrypt_data, /* decrypted data */ + decrypt_data_size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + /* copy the result to the sized buffer */ + if (rc == 0) { + printf(" TPM_RSAPublicEncrypt_Common: Encrypt data size %u\n", nbytes); + TPM_PrintFour(" TPM_RSAPublicEncrypt_Common: Encrypt data", encrypt_data); + rc = TPM_SizedBuffer_Set(enc_data, nbytes, encrypt_data); + } + free(encrypt_data); /* @1 */ + return rc; +} + +/* + Signing Functions + + These commands show the TPM command and the allowed signature schemes: + + SHA DER INFO + TPM_GetAuditDigestSigned y n y + TPM_CertifyKey y n y + TPM_CertifyKey2 y n y + TPM_CertifySelfTest y n y + TPM_Quote y n y + TPM_Quote2 y n y + TPM_Sign y y y + TPM_MakeIdentity y n y + TPM_GetCapabilitySigned y n y +*/ + +/* TPM_RSASignToSizedBuffer() signs 'message' using the private key in 'tpm_key' and places the + result in 'signature' + + 'signature' should be initialized and deleted by the caller +*/ + +TPM_RESULT TPM_RSASignToSizedBuffer(TPM_SIZED_BUFFER *signature, + const unsigned char *message, /* input */ + size_t message_size, /* input */ + TPM_KEY *tpm_key) /* input, signing key */ +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *rsa_key_parms; + unsigned int signature_length; + + printf(" TPM_RSASignToSizedBuffer: Message size %lu bytes\n", (unsigned long)message_size); + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&rsa_key_parms, + &(tpm_key->algorithmParms)); + } + /* allocating space for the signature */ + if (rc == 0) { + rc = TPM_SizedBuffer_Allocate(signature, (rsa_key_parms->keyLength)/CHAR_BIT); + } + /* sign */ + if (rc == 0) { + rc = TPM_RSASignH(signature->buffer, /* output signature */ + &signature_length, /* output, size of signature */ + signature->size, /* input, size of signature buffer */ + message, /* message */ + message_size, /* message size */ + tpm_key); /* input, signing key */ + } + /* sanity check on signature */ + if (rc == 0) { + if (signature_length != signature->size) { + printf("TPM_RSASignToSizedBuffer: Error (fatal) signature_length %u sigSize %u\n", + signature_length, signature->size); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + return rc; +} + + +/* TPM_RSASignH() signs 'message' using the private key in 'tpm_key'. 'signature_length' bytes are + moved to 'signature'. + + 'signature_length' is at most 'signature_size'. +*/ + +TPM_RESULT TPM_RSASignH(unsigned char *signature, /* output */ + unsigned int *signature_length, /* output, size of signature */ + unsigned int signature_size, /* input, size of signature buffer */ + const unsigned char *message, /* input */ + size_t message_size, /* input */ + TPM_KEY *tpm_key) /* input, signing key */ +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + unsigned char *darr; /* private exponent */ + uint32_t dbytes; + + printf(" TPM_RSASignH: Message size %lu bytes\n", (unsigned long)message_size); + TPM_PrintFour(" TPM_RSASignH: Message", message); + /* extract the public key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + /* extract the private key from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetPrivateKey(&dbytes, &darr, tpm_key); + } + /* extract the exponent from TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + if (rc == 0) { + /* debug printing */ + TPM_PrintFour(" TPM_RSASignH: Public key", narr); + printf(" TPM_RSASignH: Exponent %02x %02x %02x\n", earr[0], earr[1], earr[2]); + TPM_PrintFour(" TPM_RSASignH: Private key", darr); + /* sign with private key */ + rc = TPM_RSASign(signature, /* output */ + signature_length, /* output, size of signature */ + signature_size, /* input, size of signature buffer */ + tpm_key->algorithmParms.sigScheme, /* input, type of signature */ + message, /* input */ + message_size, /* input */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes, + darr, /* private exponent */ + dbytes); + } + if (rc == 0) { + TPM_PrintFour(" TPM_RSASignH: Signature", signature); + } + return rc; +} + +/* TPM_RSAVerifyH() verifies 'message' using the TPM format public key in 'tpm_pubkey' +*/ + +TPM_RESULT TPM_RSAVerifyH(TPM_SIZED_BUFFER *signature, /* input */ + const unsigned char *message, /* input */ + uint32_t message_size, /* input */ + TPM_PUBKEY *tpm_pubkey) /* input, verify key */ +{ + TPM_RESULT rc = 0; + unsigned char *narr; /* public modulus */ + uint32_t nbytes; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + printf(" TPM_RSAVerifyH: Message size %u bytes\n", message_size); + /* extract the public key from TPM_PUBKEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetPublicKey(&nbytes, &narr, tpm_pubkey); + } + /* extract the exponent from TPM_PUBKEY */ + if (rc == 0) { + rc = TPM_Pubkey_GetExponent(&ebytes, &earr, tpm_pubkey); + } + if (rc == 0) { + /* debug printing */ + TPM_PrintFour(" TPM_RSAVerifyH: Public key", narr); + TPM_PrintAll(" TPM_RSAVerifyH: Public exponent", earr, ebytes); + /* verify with public key */ + rc = TPM_RSAVerify(signature->buffer, /* input signature buffer */ + signature->size, /* input, size of signature buffer */ + tpm_pubkey->algorithmParms.sigScheme, /* input, type of signature */ + message, /* message */ + message_size, /* message size */ + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + return rc; +} + +/* TPM_RSAVerify() verifies the 'signature' of size 'signature_size' on the 'message' of size + 'message_size' using the public key n,e and the signature scheme 'sigScheme' as specified in PKCS + #1 v2.0. +*/ + +TPM_RESULT TPM_RSAVerify(unsigned char *signature, /* input */ + unsigned int signature_size, /* input, size of signature buffer */ + TPM_SIG_SCHEME sigScheme, /* input, type of signature */ + const unsigned char *message, /* input */ + uint32_t message_size, /* input */ + unsigned char *narr, /* public modulus */ + uint32_t nbytes, + unsigned char *earr, /* public exponent */ + uint32_t ebytes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAVerify:\n"); + /* determine the signature scheme for the key */ + if (rc == 0) { + switch(sigScheme) { + case TPM_SS_NONE: + printf("TPM_RSAVerify: Error, sigScheme TPM_SS_NONE\n"); + rc = TPM_INVALID_KEYUSAGE; + break; + case TPM_SS_RSASSAPKCS1v15_SHA1: + case TPM_SS_RSASSAPKCS1v15_INFO: + rc = TPM_RSAVerifySHA1(signature, + signature_size, + message, + message_size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + break; + case TPM_SS_RSASSAPKCS1v15_DER: + printf("TPM_RSAVerify: Error, sigScheme %04hx unsupported\n", sigScheme); + rc = TPM_INVALID_KEYUSAGE; + break; + default: + printf("TPM_RSAVerify: Error, sigScheme %04hx unknown\n", sigScheme); + rc = TPM_INVALID_KEYUSAGE; + break; + } + } + return rc; +} + +/* + OAEP Padding +*/ + +/* TPM_RSA_padding_add_PKCS1_OAEP() is a variation of the the openSSL function + + int RSA_padding_add_PKCS1_OAEP(unsigned char *to, int tlen, + unsigned char *f, int fl, unsigned char *p, int pl); + + It is used for TPM migration. The "encoding parameter" pl is replaced by pHash and the generated + random seed is replaced by a seed parameter. + + This function was independently written from the PKCS1 specification "9.1.1.1 Encoding + Operation", intended to be unencumbered by any license. + + + | seed | pHash | PS | 01 | Message | + + SHA1 SHA1 flen + + | <- emLen -> | + | db + | maskDb + | dbMask | + | seedMask + | maskSeed +*/ + +TPM_RESULT TPM_RSA_padding_add_PKCS1_OAEP(unsigned char *em, uint32_t emLen, + const unsigned char *from, uint32_t fLen, + const unsigned char *pHash, /* input 20 bytes */ + const unsigned char *seed) /* input 20 bytes */ +{ + TPM_RESULT rc = 0; + unsigned char *dbMask; + unsigned char *db; + unsigned char *maskedDb; + unsigned char *seedMask; + unsigned char *maskedSeed; + + printf(" TPM_RSA_padding_add_PKCS1_OAEP: fLen %d emLen %d\n", fLen, emLen); + TPM_PrintFour(" TPM_RSA_padding_add_PKCS1_OAEP: from", from); + TPM_PrintFour(" TPM_RSA_padding_add_PKCS1_OAEP: pHash", pHash); + TPM_PrintFour(" TPM_RSA_padding_add_PKCS1_OAEP: seed", seed); + + dbMask = NULL; /* freed @1 */ + + /* 1. If the length of P is greater than the input limitation for */ + /* the hash function (2^61-1 octets for SHA-1) then output "parameter */ + /* string too long" and stop. */ + /* NOTE Not done, pHash is input directly */ + /* 2. If ||M|| > emLen-2hLen-1 then output "message too long" and stop. */ + if (rc == 0) { + if (emLen < ((2 * TPM_DIGEST_SIZE) + 1 + fLen)) { + printf("TPM_RSA_padding_add_PKCS1_OAEP: Error, " + "message length %u too large for encoded length %u\n", fLen, emLen); + rc = TPM_ENCRYPT_ERROR; + } + } + /* 3. Generate an octet string PS consisting of emLen-||M||-2hLen-1 zero octets. The length of + PS may be 0. */ + /* NOTE Created directly in DB (step 5) */ + + /* 4. Let pHash = Hash(P), an octet string of length hLen. */ + /* NOTE pHash is input directly */ + + /* 5. Concatenate pHash, PS, the message M, and other padding to form a data block DB as: DB = + pHash || PS || 01 || M */ + if (rc == 0) { + /* NOTE Since db is eventually maskedDb, part of em, create directly in em */ + db = em + TPM_DIGEST_SIZE; + memcpy(db, pHash, TPM_DIGEST_SIZE); /* pHash */ + memset(db + TPM_DIGEST_SIZE, 0, /* PS */ + emLen - fLen - (2 * TPM_DIGEST_SIZE) - 1); + /* PSlen = emlen - flen - (2 * TPM_DIGEST_SIZE) - 1 + 0x01 index = TPM_DIGEST_SIZE + PSlen + = TPM_DIGEST_SIZE + emlen - flen - (2 * TPM_DIGEST_SIZE) - 1 + = emlen - fLen - TPM_DIGEST_SIZE - 1 */ + db[emLen - fLen - TPM_DIGEST_SIZE - 1] = 0x01; + memcpy(db + emLen - fLen - TPM_DIGEST_SIZE, from, fLen); /* M */ + + /* 6. Generate a random octet string seed of length hLen. */ + /* NOTE seed is input directly */ + + /* 7. Let dbMask = MGF(seed, emLen-hLen). */ + rc = TPM_Malloc(&dbMask, emLen - TPM_DIGEST_SIZE); + } + if (rc == 0) { + rc = TPM_MGF1(dbMask, emLen - TPM_DIGEST_SIZE, seed, TPM_DIGEST_SIZE); + } + if (rc == 0) { + /* 8. Let maskedDB = DB \xor dbMask. */ + /* NOTE Since maskedDB is eventually em, XOR directly to em */ + maskedDb = em + TPM_DIGEST_SIZE; + TPM_XOR(maskedDb, db, dbMask, emLen - TPM_DIGEST_SIZE); + + /* 9. Let seedMask = MGF(maskedDB, hLen). */ + /* NOTE Since seedMask is eventually em, create directly to em */ + seedMask = em; + rc = TPM_MGF1(seedMask, TPM_DIGEST_SIZE, maskedDb, emLen - TPM_DIGEST_SIZE); + } + if (rc == 0) { + /* 10. Let maskedSeed = seed \xor seedMask. */ + /* NOTE Since maskedSeed is eventually em, create directly to em */ + maskedSeed = em; + TPM_XOR(maskedSeed, seed, seedMask, TPM_DIGEST_SIZE); + + /* 11. Let EM = maskedSeed || maskedDB. */ + /* NOTE Created directly in em */ + + /* 12. Output EM. */ + TPM_PrintFour(" TPM_RSA_padding_add_PKCS1_OAEP: em", em); + } + free(dbMask); /* @1 */ + return rc; +} + +/* TPM_RSA_padding_check_PKCS1_OAEP() is a variation of the openSSL function + + int RSA_padding_check_PKCS1_OAEP(unsigned char *to, int tlen, + unsigned char *f, int fl, int rsa_len, unsigned char *p, int pl); + + It is used for TPM key migration. In addition to the message 'to' and message length 'tlen', the + seed and 'pHash are returned. + + This function was independently written from the PKCS1 specification "9.1.1.2 Decoding + Operation", intended to be unencumbered by the any license. + + | seed | pHash | PS | 01 | Message | + SHA1 SHA1 + | <- emLen -> | + + | maskedSeed + | seedMask + | maskedDB + | db + | <- dbMask -> | + +*/ + +TPM_RESULT TPM_RSA_padding_check_PKCS1_OAEP(unsigned char *to, uint32_t *tLen, uint32_t tSize, + const unsigned char *em, uint32_t emLen, + unsigned char *pHash, /* output 20 bytes */ + unsigned char *seed) /* output 20 bytes */ +{ + TPM_RESULT rc = 0; + const unsigned char *maskedSeed; + const unsigned char *maskedDB; + uint32_t dbLen; + unsigned char *dbMask; + unsigned char *seedMask; + unsigned char *db; + size_t i; + + printf(" TPM_RSA_padding_check_PKCS1_OAEP: emLen %d tSize %d\n", emLen, tSize); + TPM_PrintFour(" TPM_RSA_padding_check_PKCS1_OAEP: em", em); + + dbMask = NULL; /* freed @1 */ + + /* 1. If the length of P is greater than the input limitation for the hash function (2^61-1 + octets for SHA-1) then output "parameter string too long" and stop. */ + /* NOTE There is no P input. pHash is calculated for the output, but no comparison is + performed. */ + + /* 2. If ||EM|| < 2hLen+1, then output "decoding error" and stop. */ + if (rc == 0) { + if (emLen < (2 * TPM_DIGEST_SIZE) + 1) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, encoded length %u too small\n", emLen); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + /* 3. Let maskedSeed be the first hLen octets of EM and let maskedDB be the remaining ||EM|| + - hLen octets. */ + maskedSeed = em; + maskedDB = em + TPM_DIGEST_SIZE; + dbLen = emLen - TPM_DIGEST_SIZE; + /* 4. Let seedMask = MGF(maskedDB, hLen). */ + /* NOTE Created directly in seed */ + seedMask = seed; + rc = TPM_MGF1(seedMask, TPM_DIGEST_SIZE, maskedDB, dbLen); + } + if (rc == 0) { + /* 5. Let seed = maskedSeed \xor seedMask. */ + TPM_XOR(seed, maskedSeed, seedMask, TPM_DIGEST_SIZE); + /* 6. Let dbMask = MGF(seed, ||EM|| - hLen). */ + rc = TPM_Malloc(&dbMask, dbLen); + } + if (rc == 0) { + rc = TPM_MGF1(dbMask, dbLen, seed, TPM_DIGEST_SIZE); + } + if (rc == 0) { + /* 7. Let DB = maskedDB \xor dbMask. */ + /* NOTE XOR back to dbMask, since dbMask no longer needed */ + db = dbMask; + TPM_XOR(db, maskedDB, dbMask, dbLen); + /* 8. Let pHash = Hash(P), an octet string of length hLen. */ + /* NOTE pHash is input directly */ + /* 9. Separate DB into an octet string pHash' consisting of the first hLen octets of DB, + ... */ + memcpy(pHash, db, TPM_DIGEST_SIZE); + /* ... a (possibly empty) octet string PS consisting of consecutive zero octets following + pHash', and a message M as: DB = pHash' || PS || 01 || M */ + for (i = TPM_DIGEST_SIZE; i < dbLen; i++) { + if (db[i] != 0x00) { + break; /* skip the PS segment */ + } + } + /* If there is no 01 octet to separate PS from M, output "decoding error" and stop. */ + if (i == dbLen) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, missing 0x01\n"); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + if (db[i] != 0x01) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, missing 0x01\n"); + rc = TPM_DECRYPT_ERROR; + } + } + /* 10. If pHash' does not equal pHash, output "decoding error" and stop. */ + /* NOTE No pHash input to compare */ + /* 11. Output M. */ + if (rc == 0) { + i++; /* skip the 0x01 to the beginning of the message M */ + *tLen = dbLen - i; + if (*tLen > tSize) { + printf("TPM_RSA_padding_check_PKCS1_OAEP: Error, tSize %u too small for message %u\n", + tSize, *tLen); + rc = TPM_DECRYPT_ERROR; + } + } + if (rc == 0) { + memcpy(to, db + i, *tLen); + printf(" TPM_RSA_padding_check_PKCS1_OAEP: tLen %d \n", *tLen); + TPM_PrintFour(" TPM_RSA_padding_check_PKCS1_OAEP: to", to); + TPM_PrintFour(" TPM_RSA_padding_check_PKCS1_OAEP: pHash", pHash); + TPM_PrintFour(" TPM_RSA_padding_check_PKCS1_OAEP: seed", seed); + } + free(dbMask); /* @1 */ + return rc; +} + +/* TPM_RSA_exponent_verify() validates the public exponent against a list of legal values. Some + values (e.g. even numbers) will have the key generator. +*/ + +TPM_RESULT TPM_RSA_exponent_verify(unsigned long exponent) +{ + TPM_RESULT rc = 0; + size_t i; + int found; + + static const unsigned long legalExponent[] = { 3,5,7,17,257,65537 }; + + for (i = 0, found = FALSE ; + !found && (i < (sizeof(legalExponent) / sizeof (unsigned long))) ; + i++) { + + if (exponent == legalExponent[i]) { + found = TRUE; + } + } + if (!found) { + printf("TPM_RSA_exponent_verify: Error, public exponent %lu is illegal\n", exponent ); + rc = TPM_BAD_KEY_PROPERTY; + } + return rc; +} + +/* SHA1 and HMAC test driver + + Returns TPM_FAILEDSELFTEST on error +*/ + +TPM_RESULT TPM_CryptoTest(void) +{ + TPM_RESULT rc = 0; + int not_equal; + TPM_BOOL valid; + + /* SHA1 */ + unsigned char buffer1[] = "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + unsigned char expect1[] = {0x84,0x98,0x3E,0x44,0x1C, + 0x3B,0xD2,0x6E,0xBA,0xAE, + 0x4A,0xA1,0xF9,0x51,0x29, + 0xE5,0xE5,0x46,0x70,0xF1}; + TPM_DIGEST actual; + uint32_t actual_size; + + /* HMAC */ + unsigned char key2[] = {0xaa,0xaa,0xaa,0xaa,0xaa, 0xaa,0xaa,0xaa,0xaa,0xaa, + 0xaa,0xaa,0xaa,0xaa,0xaa, 0xaa,0xaa,0xaa,0xaa,0xaa}; + unsigned char expect2[] = {0x12,0x5d,0x73,0x42,0xb9,0xac,0x11,0xcd,0x91,0xa3, + 0x9a,0xf4,0x8a,0xa1,0x7b,0x4f,0x63,0xf1,0x75,0xd3}; + /* data 0xdd repeated 50 times */ + unsigned char data2[50]; + + /* oaep tests */ + const unsigned char oaep_pad_str[] = { 'T', 'C', 'P', 'A' }; + unsigned char pHash_in[TPM_DIGEST_SIZE]; + unsigned char pHash_out[TPM_DIGEST_SIZE]; + unsigned char seed_in[TPM_DIGEST_SIZE] = {0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, + 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff, + 0xf0,0xf1,0xf2,0xf3}; + unsigned char seed_out[TPM_DIGEST_SIZE]; + unsigned char oaep_in[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07}; + unsigned char oaep_pad[256]; + unsigned char oaep_out[8]; + uint32_t oeap_length; + + /* symmetric key with pad */ + TPM_SYMMETRIC_KEY_TOKEN tpm_symmetric_key_data = NULL; /* opaque structure, freed @7 */ + unsigned char clrStream[64]; /* expected */ + unsigned char *encStream; /* encrypted */ + uint32_t encSize; + unsigned char *decStream; /* actual */ + uint32_t decSize; + + /* symmetric key ctr and ofb mode */ + TPM_SECRET symKey; + TPM_NONCE pad; /* CTR or IV */ + TPM_ENCAUTH symClear; + TPM_ENCAUTH symEnc; + TPM_ENCAUTH symDec; + + /* RSA encrypt and decrypt, sign and verify */ + unsigned char *n; /* public key - modulus */ + unsigned char *p; /* private key prime */ + unsigned char *q; /* private key prime */ + unsigned char *d; /* private key (private exponent) */ + unsigned char encrypt_data[2048/8]; /* encrypted data */ + + printf(" TPM_CryptoTest:\n"); + encStream = NULL; /* freed @1 */ + decStream = NULL; /* freed @2 */ + n = NULL; /* freed @3 */ + p = NULL; /* freed @4 */ + q = NULL; /* freed @5 */ + d = NULL; /* freed @6 */ + + if (rc == 0) { + printf(" TPM_CryptoTest: Test 1 - SHA1 one part\n"); + rc = TPM_SHA1(actual, + sizeof(buffer1) - 1, buffer1, + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 1\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 2 - SHA1 two parts\n"); + rc = TPM_SHA1(actual, + 16, buffer1, /* first 16 */ + sizeof(buffer1) - 17, buffer1 + 16, /* rest */ + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 2\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 3 - HMAC generate - one part\n"); + memset(data2, 0xdd, 50); + rc = TPM_HMAC_Generate(actual, + key2, + 50, data2, + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect2, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 3\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 4 - HMAC generate - two parts\n"); + memset(data2, 0xdd, 50); + rc = TPM_HMAC_Generate(actual, + key2, + 20, data2, + 30, data2 + 20, + 0, NULL); + } + if (rc == 0) { + not_equal = memcmp(expect2, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 3\n"); + TPM_PrintFour("\texpect", expect2); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 4 - HMAC check - two parts\n"); + memset(data2, 0xdd, 50); + rc = TPM_HMAC_Check(&valid, + expect2, + key2, + 20, data2, + 30, data2 + 20, + 0, NULL); + } + if (rc == 0) { + if (!valid) { + printf("TPM_CryptoTest: Error in test 4\n"); + TPM_PrintFour("\texpect", expect1); + TPM_PrintFour("\tactual", actual); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 5 - OAEP add and check\n"); + rc = TPM_SHA1(pHash_in, + sizeof(oaep_pad_str), oaep_pad_str, + 0, NULL); + } + if (rc == 0) { + rc = TPM_RSA_padding_add_PKCS1_OAEP(oaep_pad, sizeof(oaep_pad), + oaep_in, sizeof(oaep_in), + pHash_in, seed_in); + } + if (rc == 0) { + rc = TPM_RSA_padding_check_PKCS1_OAEP(oaep_out, &oeap_length, sizeof(oaep_out), + oaep_pad, sizeof(oaep_pad), + pHash_out, + seed_out); + } + if (rc == 0) { + if (oeap_length != sizeof(oaep_out)) { + printf("TPM_CryptoTest: Error in test 5, expect length %lu, actual length %u\n", + (unsigned long)sizeof(oaep_out), oeap_length); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(oaep_in, oaep_out, sizeof(oaep_out)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 5 oaep\n"); + TPM_PrintFour("\tin ", oaep_in); + TPM_PrintFour("\tout", oaep_out); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(pHash_in, pHash_out, sizeof(pHash_in)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 5 pHash\n"); + TPM_PrintFour("\tpHash_in ", pHash_in); + TPM_PrintFour("\tpHash_out", pHash_out); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(seed_in, seed_out, sizeof(seed_in)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 5 seed\n"); + TPM_PrintFour("\tseed_in ", seed_in); + TPM_PrintFour("\tseed_out", seed_out); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 6 - Symmetric key with PKCS pad test\n"); + /* allocate memory for the key token */ + rc = TPM_SymmetricKeyData_New(&tpm_symmetric_key_data); /* freed @7 */ + } + /* generate a key */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_GenerateKey(tpm_symmetric_key_data); + } + /* generate clear text */ + if (rc == 0) { + rc = TPM_Random(clrStream, sizeof(clrStream)); + } + /* symmetric encrypt */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Encrypt(&encStream, /* output, freed @1 */ + &encSize, /* output */ + clrStream, /* input */ + sizeof(clrStream), /* input */ + tpm_symmetric_key_data); /* key */ + } + /* symmetric decrypt */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Decrypt(&decStream, /* output, freed by caller */ + &decSize, /* output */ + encStream, /* input */ + encSize, /* input */ + tpm_symmetric_key_data); /* key */ + } + /* symmetric compare */ + if (rc == 0) { + if (sizeof(clrStream) != decSize) { + printf("TPM_CryptoTest: Error in test 6, in %lu, out %u\n", + (unsigned long)sizeof(clrStream), decSize); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(clrStream, decStream, sizeof(clrStream)); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 6\n"); + TPM_PrintFour("\tclear stream in", clrStream); + TPM_PrintFour("\tdecrypted stream", decStream); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 7 - Symmetric key with CTR mode\n"); + /* generate a key */ + rc = TPM_Random(symKey, TPM_SECRET_SIZE); + } + /* generate CTR */ + if (rc == 0) { + rc = TPM_Random(pad, TPM_NONCE_SIZE); + } + /* generate clear text */ + if (rc == 0) { + rc = TPM_Random(symClear, TPM_AUTHDATA_SIZE); + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_CtrCrypt(symEnc, /* output */ + symClear, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_CtrCrypt(symDec, /* output */ + symEnc, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + /* symmetric compare */ + if (rc == 0) { + rc = TPM_Secret_Compare(symDec, symClear); + if (rc != 0) { + printf("TPM_CryptoTest: Error in test 8\n"); + TPM_PrintFour("\tclear stream in", symClear); + TPM_PrintFour("\tdecrypted stream", symDec); + } + } + if (rc == 0) { + printf(" TPM_CryptoTest: Test 8 - Symmetric key with OFB mode\n"); + /* generate a key */ + rc = TPM_Random(symKey, TPM_SECRET_SIZE); + } + /* generate IV */ + if (rc == 0) { + rc = TPM_Random(pad, TPM_NONCE_SIZE); + } + /* generate clear text */ + if (rc == 0) { + rc = TPM_Random(symClear, TPM_AUTHDATA_SIZE); + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_OfbCrypt(symEnc, /* output */ + symClear, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + if (rc == 0) { + rc = TPM_SymmetricKeyData_OfbCrypt(symDec, /* output */ + symEnc, /* input */ + TPM_AUTHDATA_SIZE, /* input */ + symKey, /* in */ + TPM_SECRET_SIZE, /* in */ + pad, /* input */ + TPM_NONCE_SIZE); /* input */ + } + /* symmetric compare */ + if (rc == 0) { + rc = TPM_Secret_Compare(symDec, symClear); + if (rc != 0) { + printf("TPM_CryptoTest: Error in test 8\n"); + TPM_PrintFour("\tclear stream in", symClear); + TPM_PrintFour("\tdecrypted stream", symDec); + } + } + /* RSA OAEP encrypt and decrypt */ + if (rc == 0) { + printf(" TPM_CryptoTest: Test 9 - RSA encrypt with OAEP padding\n"); + /* generate a key */ + rc = TPM_RSAGenerateKeyPair(&n, /* public key - modulus */ + &p, /* private key prime */ + &q, /* private key prime */ + &d, /* private key (private exponent) */ + 2048, /* key size in bits */ + tpm_default_rsa_exponent, /* public exponent as an array */ + 3); + } + /* encrypt */ + if (rc == 0) { + rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ + sizeof(encrypt_data), /* size of encrypted data buffer */ + TPM_ES_RSAESOAEP_SHA1_MGF1, /* TPM_ENC_SCHEME */ + expect1, /* decrypted data */ + sizeof(expect1), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3); + } + if (rc == 0) { + rc = TPM_RSAPrivateDecrypt(actual, /* decrypted data */ + &actual_size, /* length of data put into + decrypt_data */ + TPM_DIGEST_SIZE, /* size of decrypt_data buffer */ + TPM_ES_RSAESOAEP_SHA1_MGF1, /* TPM_ENC_SCHEME */ + encrypt_data, /* encrypted data */ + sizeof(encrypt_data), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3, + d, /* private exponent */ + 2048/8); + } + if (rc == 0) { + if (actual_size != TPM_DIGEST_SIZE) { + printf("TPM_CryptoTest: Error in test 9, expect length %u, actual length %u\n", + TPM_DIGEST_SIZE, actual_size); + rc = TPM_FAILEDSELFTEST; + } + } + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 9\n"); + TPM_PrintFour("\tin ", expect1); + TPM_PrintFour("\tout", actual); + rc = TPM_FAILEDSELFTEST; + } + } + /* RSA PKCS1 pad, encrypt and decrypt */ + if (rc == 0) { + printf(" TPM_CryptoTest: Test 10 - RSA encrypt with PKCS padding\n"); + /* encrypt */ + rc = TPM_RSAPublicEncrypt(encrypt_data, /* encrypted data */ + sizeof(encrypt_data), /* size of encrypted data buffer */ + TPM_ES_RSAESPKCSv15, /* TPM_ENC_SCHEME */ + expect1, /* decrypted data */ + sizeof(expect1), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3); + } + /* decrypt */ + if (rc == 0) { + rc = TPM_RSAPrivateDecrypt(actual, /* decrypted data */ + &actual_size, /* length of data put into + decrypt_data */ + TPM_DIGEST_SIZE, /* size of decrypt_data buffer */ + TPM_ES_RSAESPKCSv15, /* TPM_ENC_SCHEME */ + encrypt_data, /* encrypted data */ + sizeof(encrypt_data), + n, /* public modulus */ + 2048/8, + tpm_default_rsa_exponent, /* public exponent */ + 3, + d, /* private exponent */ + 2048/8); + } + /* check length after padding removed */ + if (rc == 0) { + if (actual_size != TPM_DIGEST_SIZE) { + printf("TPM_CryptoTest: Error in test 10, expect length %u, actual length %u\n", + TPM_DIGEST_SIZE, actual_size); + rc = TPM_FAILEDSELFTEST; + } + } + /* check data */ + if (rc == 0) { + not_equal = memcmp(expect1, actual, TPM_DIGEST_SIZE); + if (not_equal) { + printf("TPM_CryptoTest: Error in test 10\n"); + TPM_PrintFour("\tin ", expect1); + TPM_PrintFour("\tout", actual); + rc = TPM_FAILEDSELFTEST; + } + } + /* run library specific self tests as required */ + if (rc == 0) { + rc = TPM_Crypto_TestSpecific(); + } + if (rc != 0) { + rc = TPM_FAILEDSELFTEST; + } + free(encStream); /* @1 */ + free(decStream); /* @2 */ + free(n); /* @3 */ + free(p); /* @4 */ + free(q); /* @5 */ + free(d); /* @6 */ + TPM_SymmetricKeyData_Free(&tpm_symmetric_key_data); /* @7 */ + return rc; +} + +/* 13.5 TPM_Sign rev 111 + + The Sign command signs data and returns the resulting digital signature. + + The TPM does not allow TPM_Sign with a TPM_KEY_IDENTITY (AIK) because TPM_Sign can sign arbitrary + data and could be used to fake a quote. (This could have been relaxed to allow TPM_Sign with an + AIK if the signature scheme is _INFO For an _INFO key, the metadata prevents TPM_Sign from faking + a quote.) + + The TPM MUST support all values of areaToSignSize that are legal for the defined signature scheme + and key size. The maximum value of areaToSignSize is determined by the defined signature scheme + and key size. + + In the case of PKCS1v15_SHA1 the areaToSignSize MUST be TPM_DIGEST (the hash size of a sha1 + operation - see 8.5.1 TPM_SS_RSASSAPKCS1v15_SHA1). In the case of PKCS1v15_DER the maximum size + of areaToSign is k - 11 octets, where k is limited by the key size (see 8.5.2 + TPM_SS_RSASSAPKCS1v15_DER). +*/ + +TPM_RESULT TPM_Process_Sign(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform + digital signatures. */ + TPM_SIZED_BUFFER areaToSign; /* The value to sign */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle authorization + */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization handle */ + TPM_AUTHDATA privAuth; /* The authorization digest that authorizes the use of + keyHandle. HMAC key: key.usageAuth */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus ; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_RSA_KEY_PARMS *rsa_key_parms; /* for key */ + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *keyUsageAuth; + TPM_SIGN_INFO tpm_sign_info; + const unsigned char *S1_data; /* data to be signed */ + uint32_t S1_size; + TPM_DIGEST infoDigest; /* TPM_SIGN_INFO structure digest */ + TPM_STORE_BUFFER sbuffer; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_Sign: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&areaToSign); /* freed @1 */ + TPM_SignInfo_Init(&tpm_sign_info); /* freed @2 */ + TPM_Sbuffer_Init(&sbuffer); /* freed @3 */ + TPM_SizedBuffer_Init(&sig); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sign: keyHandle %08x\n", keyHandle); + /* get areaToSignSize and areaToSign parameters */ + returnCode = TPM_SizedBuffer_Load(&areaToSign, &command, ¶mSize); /* freed @1 */ + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sign: Signing %u bytes\n", areaToSign.size); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Sign: Error, command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* check TPM_AUTH_DATA_USAGE authDataUsage */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (key->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_Sign: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + key, + keyUsageAuth, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM validates the AuthData to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. If the areaToSignSize is 0 the TPM returns TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if (areaToSign.size == 0) { + printf("TPM_Process_Sign: Error, areaToSignSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 3. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING or TPM_KEY_LEGACY, if not return + the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((key->keyUsage != TPM_KEY_SIGNING) && ((key->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_Sign: Error, keyUsage %04hx is invalid\n", key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. The TPM verifies that the signature scheme and key size can properly sign the areaToSign + parameter. NOTE Done in 5. - 7.*/ + /* get key -> TPM_RSA_KEY_PARMS */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&rsa_key_parms, + &(key->algorithmParms)); + } + if (returnCode == TPM_SUCCESS) { + /* 5. If signature scheme is TPM_SS_RSASSAPKCS1v15_SHA1 then */ + if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1\n"); + /* a. Validate that areaToSignSize is 20 return TPM_BAD_PARAMETER on error */ + if (returnCode == TPM_SUCCESS) { + if (areaToSign.size != TPM_DIGEST_SIZE) { + printf("TPM_Process_Sign: Error, areaToSignSize %d should be %u\n", + areaToSign.size, TPM_DIGEST_SIZE); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. Set S1 to areaToSign */ + if (returnCode == TPM_SUCCESS) { + S1_size = areaToSign.size; + S1_data = areaToSign.buffer; + } + } + /* 6. Else if signature scheme is TPM_SS_RSASSAPKCS1v15_DER then */ + else if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_DER) { + printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_DER\n"); + /* a. Validate that areaToSignSize is at least 11 bytes less than the key size, return + TPM_BAD_PARAMETER on error */ + if (returnCode == TPM_SUCCESS) { + if (areaToSign.size > (((rsa_key_parms->keyLength)/CHAR_BIT) - 11)) { + printf("TPM_Process_Sign: Error, areaToSignSize %d should be 11-%u\n", + areaToSign.size, ((rsa_key_parms->keyLength)/CHAR_BIT)); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. Set S1 to areaToSign */ + if (returnCode == TPM_SUCCESS) { + S1_size = areaToSign.size; + S1_data = areaToSign.buffer; + } + } + /* 7. else if signature scheme is TPM_SS_RSASSAPKCS1v15_INFO then */ + else if (key->algorithmParms.sigScheme == TPM_SS_RSASSAPKCS1v15_INFO) { + printf("TPM_Process_Sign: sigScheme is TPM_SS_RSASSAPKCS1v15_INFO\n"); + if (returnCode == TPM_SUCCESS) { + /* a. Create S2 a TPM_SIGN_INFO structure */ + /* NOTE: Done by TPM_SignInfo_Init() */ + /* b. Set S2 -> fixed to "SIGN" */ + memcpy(tpm_sign_info.fixed, "SIGN", TPM_SIGN_INFO_FIXED_SIZE); + /* c.i. If nonceOdd is not present due to an unauthorized command return + TPM_BAD_PARAMETER */ + if (tag == TPM_TAG_RQU_COMMAND) { + printf("TPM_Process_Sign: Error, TPM_SS_RSASSAPKCS1v15_INFO and no auth\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + /* c. Set S2 -> replay to nonceOdd */ + TPM_Nonce_Copy(tpm_sign_info.replay, nonceOdd); + /* d. Set S2 -> dataLen to areaToSignSize */ + /* e. Set S2 -> data to areaToSign */ + returnCode = TPM_SizedBuffer_Copy(&(tpm_sign_info.data), &areaToSign); + } + /* f. Set S1 to the SHA-1(S2) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(infoDigest, + &tpm_sign_info, + (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); + S1_size = TPM_DIGEST_SIZE; + S1_data = infoDigest; + } + } + /* 8. Else return TPM_INVALID_KEYUSAGE */ + else { + printf("TPM_Process_Sign: Error, sigScheme %04hx\n", key->algorithmParms.sigScheme); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 9. The TPM computes the signature, sig, using the key referenced by keyHandle using S1 as the + value to sign */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintAll("TPM_Process_Sign: Digest to sign", S1_data, S1_size); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + S1_data, /* message */ + S1_size, /* message size */ + key); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Sign: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 10. Return the computed signature in Sig */ + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&areaToSign); /* @1 */ + TPM_SignInfo_Delete(&tpm_sign_info); /* @2 */ + TPM_Sbuffer_Delete(&sbuffer); /* @3 */ + TPM_SizedBuffer_Delete(&sig); /* @4 */ + return rcf; +} + +/* 13.1 TPM_SHA1Start rev 96 + + This capability starts the process of calculating a SHA-1 digest. + + The exposure of the SHA-1 processing is a convenience to platforms in a mode that do not have + sufficient memory to perform SHA-1 themselves. As such the use of SHA-1 is restrictive on the + TPM. + + The TPM may not allow any other types of processing during the execution of a SHA-1 + session. There is only one SHA-1 session active on a TPM. The exclusivity of a SHA-1 + context is due to the relatively large volatile buffer it requires in order to hold the + intermediate results between the SHA-1 context commands. This buffer can be in + contradiction to other command needs. + + After the execution of SHA1Start, and prior to SHA1End, the receipt of any command other than + SHA1Update will cause the invalidation of the SHA-1 session. +*/ + +TPM_RESULT TPM_Process_SHA1Start(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters - none */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + uint32_t maxNumBytes = TPM_SHA1_MAXNUMBYTES; /* Maximum number of bytes that can be sent + to TPM_SHA1Update. Must be a multiple of + 64 bytes. */ + + printf("TPM_Process_SHA1Start: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1Start: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This capability prepares the TPM for a subsequent TPM_SHA1Update, TPM_SHA1Complete or + TPM_SHA1CompleteExtend command. The capability SHALL open a thread that calculates a SHA-1 + digest. + */ + if (returnCode == TPM_SUCCESS) { + if (transportInternal == NULL) { + tpm_state->transportHandle = 0; /* SHA-1 thread not within transport */ + } + else { + tpm_state->transportHandle = transportInternal->transHandle; /* SHA-1 thread within + transport */ + } + returnCode = TPM_SHA1InitCmd(&(tpm_state->sha1_context)); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1Start: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append maxNumBytes */ + returnCode = TPM_Sbuffer_Append32(response, maxNumBytes); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 13.2 TPM_SHA1Update rev 114 + + 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_Process_SHA1Update(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_SIZED_BUFFER hashData; /* Bytes to be hashed */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SHA1Update: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&hashData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* load hashData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&hashData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1Update: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This command SHALL incorporate complete blocks of data into the digest of an existing SHA-1 + thread. Only integral numbers of complete blocks (64 bytes each) can be processed. + */ + /* 1. If there is no existing SHA-1 thread, return TPM_SHA_THREAD */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->sha1_context == NULL) { + printf("TPM_Process_SHA1Update: Error, no existing SHA1 thread\n"); + returnCode = TPM_SHA_THREAD; + } + } + /* 2. If numBytes is not a multiple of 64 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SHA1Update: numBytes %u bytes\n", hashData.size); + if ((hashData.size % 64) != 0) { + printf("TPM_Process_SHA1Update: Error, numBytes not integral number of blocks\n"); + /* a. Return TPM_SHA_ERROR */ + returnCode = TPM_SHA_ERROR; + /* b. The TPM MAY terminate the SHA-1 thread */ + TPM_SHA1Delete(&(tpm_state->sha1_context)); + } + } + /* 3. If numBytes is greater than maxNumBytes returned by TPM_SHA1Start */ + if (returnCode == TPM_SUCCESS) { + if (hashData.size > TPM_SHA1_MAXNUMBYTES) { + /* a. Return TPM_SHA_ERROR */ + returnCode = TPM_SHA_ERROR; + /* b. The TPM MAY terminate the SHA-1 thread */ + TPM_SHA1Delete(&(tpm_state->sha1_context)); + } + } + /* 4. Incorporate hashData into the digest of the existing SHA-1 thread. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1UpdateCmd(tpm_state->sha1_context, hashData.buffer, hashData.size); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1Update: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&hashData); /* @1 */ + return rcf; +} + +/* 13.3 TPM_SHA1Complete rev 87 + + This capability terminates a pending SHA-1 calculation. +*/ + +TPM_RESULT TPM_Process_SHA1Complete(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_SIZED_BUFFER hashData; /* Final bytes to be hashed */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST hashValue; /* The output of the SHA-1 hash. */ + TPM_SizedBuffer_Init(&hashData); /* freed @1 */ + + printf("TPM_Process_SHA1Complete: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* load hashData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&hashData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1Complete: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This command SHALL incorporate a partial or complete block of data into the digest of an + existing SHA-1 thread, and terminate that thread. hashDataSize MAY have values in the range + of 0 through 64, inclusive. If the SHA-1 thread has received no bytes the TPM SHALL + calculate the SHA-1 of the empty buffer. + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1CompleteCommon(hashValue, + &(tpm_state->sha1_context), + &hashData); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1Complete: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append hashValue */ + returnCode = TPM_Digest_Store(response, hashValue); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&hashData); /* @1 */ + return rcf; +} + +/* 13.4 TPM_SHA1CompleteExtend rev 109 + + This capability terminates a pending SHA-1 calculation and EXTENDS the result into a Platform + Configuration Register using a SHA-1 hash process. + + This command is designed to complete a hash sequence and extend a PCR in memory-less + environments. + + This command SHALL incorporate a partial or complete block of data into the digest of an existing + SHA-1 thread, EXTEND the resultant digest into a PCR, and terminate the thread. hashDataSize MAY + have values in the range of 0 through 64, inclusive. +*/ + +TPM_RESULT TPM_Process_SHA1CompleteExtend(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_PCRINDEX pcrNum; /* Index of the PCR to be modified */ + TPM_SIZED_BUFFER hashData; /* Final bytes to be hashed */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST h1HashValue; /* The output of the SHA-1 hash. */ + TPM_PCRVALUE outDigest; /* The PCR value after execution of the command. */ + + printf("TPM_Process_SHA1CompleteExtend: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&hashData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pcrNum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&pcrNum, &command, ¶mSize); + } + /* get hashData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SHA1CompleteExtend: pcrNum %u\n", pcrNum); + returnCode = TPM_SizedBuffer_Load(&hashData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SHA1CompleteExtend: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. 1.Validate that pcrNum represents a legal PCR number. On error, return TPM_BADINDEX. */ + /* 2. Map V1 to TPM_STANY_DATA */ + /* 3. Map L1 to V1 -> localityModifier */ + /* 4. If the current locality, held in L1, is not selected in TPM_PERMANENT_DATA -> pcrAttrib + [PCRIndex]. pcrExtendLocal, return TPM_BAD_LOCALITY */ + /* NOTE Done in TPM_ExtendCommon() */ + /* 5. Create H1 the TPM_DIGEST of the SHA-1 session ensuring that hashData, if any, is */ + /* added to the SHA-1 session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1CompleteCommon(h1HashValue, + &(tpm_state->sha1_context), + &hashData); + } + /* 6. Perform the actions of TPM_Extend using H1 as the data and pcrNum as the PCR to extend */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ExtendCommon(outDigest, tpm_state, ordinal, pcrNum, h1HashValue); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SHA1CompleteExtend: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append hashValue */ + returnCode = TPM_Digest_Store(response, h1HashValue); + } + /* append outDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, outDigest); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&hashData); /* @1 */ + return rcf; +} + +/* TPM_SHA1CompleteCommon() is common code for TPM_Process_SHA1Complete() and + TPM_Process_SHA1CompleteExtend() +*/ + +TPM_RESULT TPM_SHA1CompleteCommon(TPM_DIGEST hashValue, /* output: digest */ + void **sha1_context, /* IO: SHA1 context */ + TPM_SIZED_BUFFER *hashData) /* final data to be hashed */ +{ + TPM_RESULT rc = 0; + + /* The TPM specification says that the last data chunk must be 0-64 bytes */ + printf("TPM_SHA1CompleteCommon: %u bytes\n", hashData->size); + if (rc == 0) { + if (hashData->size > 64) { + printf("TPM_SHA1CompleteCommon: Error, hashDataSize %u not 0-64\n", + hashData->size); + rc = TPM_SHA_ERROR; + } + } + /* cannot call SHA1Complete() before SHA1Start() */ + if (rc == 0) { + if (*sha1_context == NULL) { + printf("TPM_SHA1CompleteCommon: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + } + if ((rc == 0) && (hashData->size != 0)) { + rc = TPM_SHA1UpdateCmd(*sha1_context, hashData->buffer, hashData->size); + } + if (rc == 0) { + rc = TPM_SHA1FinalCmd(hashValue, *sha1_context); + } + /* the SHA1 thread should be terminated even if there is an error */ + TPM_SHA1Delete(sha1_context); + return rc; +} + +/* 13.6 TPM_GetRandom rev 87 + + GetRandom returns the next bytesRequested bytes from the random number generator to the caller. + + It is recommended that a TPM implement the RNG in a manner that would allow it to return RNG + bytes such that the frequency of bytesRequested being more than the number of bytes available is + an infrequent occurrence. +*/ + +TPM_RESULT TPM_Process_GetRandom(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + uint32_t bytesRequested; /* Number of bytes to return */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER randomBytes; /* The returned bytes */ + + printf("TPM_Process_GetRandom: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&randomBytes); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get bytesRequested parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&bytesRequested, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetRandom: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM determines if amount bytesRequested is available from the TPM. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetRandom: bytesRequested %u\n", bytesRequested); + if (bytesRequested > TPM_RANDOM_MAX) { + bytesRequested = TPM_RANDOM_MAX; + printf("TPM_Process_GetRandom: bytes available %u\n", bytesRequested); + } + } + /* 2. Set randomBytesSize to the number of bytes available from the RNG. This number MAY be less + than bytesRequested. */ + if ((returnCode == TPM_SUCCESS) && (bytesRequested > 0)) { + returnCode = TPM_SizedBuffer_Allocate(&randomBytes, bytesRequested); + } + /* 3. Set randomBytes to the next randomBytesSize bytes from the RNG */ + if ((returnCode == TPM_SUCCESS) && (bytesRequested > 0)) { + returnCode = TPM_Random(randomBytes.buffer, bytesRequested); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetRandom: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append randomBytes */ + returnCode = TPM_SizedBuffer_Store(response, &randomBytes); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&randomBytes); /* freed @1 */ + return rcf; +} + +/* 13.7 TPM_StirRandom rev 109 + + StirRandom adds entropy to the RNG state. +*/ + +TPM_RESULT TPM_Process_StirRandom(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_SIZED_BUFFER inData; /* Data to add entropy to RNG state, + Number of bytes of input */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_StirRandom: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inData); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_StirRandom: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If dataSize is not less than 256 bytes, the TPM MAY return TPM_BAD_PARAMETER. */ + /* The TPM updates the state of the current RNG using the appropriate mixing function. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StirRandomCmd(&inData); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_StirRandom: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inData); /* @1 */ + return rcf; +} + +/* 13.8 TPM_CertifyKey rev 107 + + The TPM_CertifyKey operation allows one key to certify the public portion of another key. A TPM + identity key may be used to certify non-migratable keys but is not permitted to certify migratory + keys or certified migration keys. As such, it allows the TPM to make the statement "this key is + held in a TPM-shielded location, and it will never be revealed." For this statement to have + veracity, the Challenger must trust the policies used by the entity that issued the identity and + the maintenance policy of the TPM manufacturer. + + Signing and legacy keys may be used to certify both migratable and non-migratable keys. Then the + usefulness of a certificate depends on the trust in the certifying key by the recipient of the + certificate. + + The key to be certified must be loaded before TPM_CertifyKey is called. + + The determination to use the TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 on the output is based on + which PCRs and what localities the certified key is restricted to. A key to be certified that + does not have locality restrictions and which uses no PCRs greater than PCR #15 will cause this + command to return and sign a TPM_CERTIFY_INFO structure, which provides compatibility with V1.1 + TPMs. + + When this command is run to certify all other keys (those that use PCR #16 or higher, as well as + those limited by locality in any way), it will return and sign a TPM_CERTIFY_INFO2 structure. + + TPM_CertifyKey does not support the case where (a) the certifying key requires a usage + authorization to be provided but (b) the key-to-be-certified does not. In such cases, + TPM_CertifyKey2 must be used. + + If a command tag (in the parameter array) specifies only one authorisation session, then the TPM + convention is that the first session listed is ignored (authDataUsage must be TPM_AUTH_NEVER for + this key) and the incoming session data is used for the second auth session in the list. In + TPM_CertifyKey, the first session is the certifying key and the second session is the + key-to-be-certified. In TPM_CertifyKey2, the first session is the key-to-be-certified and the + second session is the certifying key. +*/ + +TPM_RESULT TPM_Process_CertifyKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE certHandle; /* Handle of the key to be used to certify the key. */ + TPM_KEY_HANDLE keyHandle; /* Handle of the key to be certified. */ + TPM_NONCE antiReplay; /* 160 bits of externally supplied data (typically a nonce + provided to prevent replay-attacks) */ + TPM_AUTHHANDLE certAuthHandle; /* The authorization session handle used for certHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with certAuthHandle + */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA certAuth; /* The authorization session digest for inputs and + certHandle. HMAC key: certKey.auth. */ + TPM_AUTHHANDLE keyAuthHandle; /* The authorization session handle used for the key to be + signed. */ + TPM_NONCE keynonceOdd; /* Nonce generated by system associated with keyAuthHandle + */ + TPM_BOOL continueKeySession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA keyAuth; /* The authorization session digest for the inputs and key + to be signed. HMAC key: key.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *cert_auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *target_auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL certAuthHandleValid = FALSE; + TPM_BOOL keyAuthHandleValid = FALSE; + TPM_SECRET *certHmacKey; + TPM_SECRET *targetHmacKey; + TPM_BOOL certPCRStatus; + TPM_BOOL targetPCRStatus; + TPM_KEY *certKey = NULL; /* the key specified by certHandle */ + TPM_KEY *targetKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *certKeyUsageAuth; + TPM_SECRET *targetKeyUsageAuth; + TPM_BOOL pcrUsage; + TPM_LOCALITY_SELECTION localityAtRelease; + int v1Version; /* TPM 1.1 or TPM 1.2 */ + int certifyType = 0; /* TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 */ + TPM_DIGEST m1Digest; /* digest of certifyInfo */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CERTIFY_INFO certifyInfo; /* TPM_CERTIFY_INFO or TPM_CERTIFY_INFO2 structure + that provides information relative to keyhandle + NOTE This is c1 in the Actions. */ + TPM_CERTIFY_INFO2 certifyInfo2; + TPM_SIZED_BUFFER outData; /* The signature of certifyInfo */ + + printf("TPM_Process_CertifyKey: Ordinal Entry\n"); + TPM_CertifyInfo_Init(&certifyInfo); /* freed @1 */ + TPM_CertifyInfo2_Init(&certifyInfo2); /* freed @2 */ + TPM_SizedBuffer_Init(&outData); /* freed @3 */ + /* + get inputs + */ + /* get certHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&certHandle, &command, ¶mSize); + } + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: certHandle %08x\n", certHandle); + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag210(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&certAuthHandle, + &certAuthHandleValid, + nonceOdd, + &continueAuthSession, + certAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_CertifyKey: certAuthHandle %08x\n", certAuthHandle); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Get(&keyAuthHandle, + &keyAuthHandleValid, + keynonceOdd, + &continueKeySession, + keyAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + printf("TPM_Process_CertifyKey: keyAuthHandle %08x\n", keyAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CertifyKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + certAuthHandleValid = FALSE; + keyAuthHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the certHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&certKey, &certPCRStatus, tpm_state, certHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&targetKey, &targetPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* 1. The TPM validates that the key pointed to by certHandle has a signature scheme of + TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO */ + if (returnCode == TPM_SUCCESS) { + if ((certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_CertifyKey: Error, invalid certKey sigScheme %04hx\n", + certKey->algorithmParms.sigScheme); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* 2. Verify command and key AuthData values */ + /* a. If tag is TPM_TAG_RQU_AUTH2_COMMAND */ + /* i. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTHFAIL on error */ + /* ii. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTH2FAIL on error */ + /* b. else if tag is TPM_TAG_RQU_AUTH1_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + /* ii. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTHFAIL on error */ + /* c. else if tag is TPM_TAG_RQU_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + /* ii. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key + referenced by keyHandle, return TPM_AUTHFAIL on error. */ + + /* NOTE: Simplified the above logic as follows */ + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND, process the first set of authorization data */ + /* get certHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&certKeyUsageAuth, certKey); + } + /* get the first session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&cert_auth_session_data, + &certHmacKey, + tpm_state, + certAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + certKey, + certKeyUsageAuth, /* OIAP */ + certKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTHFAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *certHmacKey, /* HMAC key */ + inParamDigest, + cert_auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + certAuth); /* Authorization digest for input */ + } + /* If tag is not TPM_TAG_RQU_AUTH2_COMMAND */ + /* Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (certKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CertifyKey: Error, cert key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND or TPM_TAG_RQU_AUTH1_COMMAND process the second set of + authorization data */ + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&targetKeyUsageAuth, targetKey); + } + /* get the second session data */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&target_auth_session_data, + &targetHmacKey, + tpm_state, + keyAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + targetKey, + targetKeyUsageAuth, /* OIAP */ + targetKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTH2FAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Auth2data_Check(tpm_state, + *targetHmacKey, /* HMAC key */ + inParamDigest, + target_auth_session_data, /* authorization session */ + keynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueKeySession, + keyAuth); /* Authorization digest for input */ + } + /* Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced + by keyHandle, return TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (targetKey->authDataUsage == TPM_AUTH_ALWAYS) { + printf("TPM_Process_CertifyKey: Error, target key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 3. If keyHandle -> payload is not TPM_PT_ASYM, return TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (targetKey->tpm_store_asymkey->payload != TPM_PT_ASYM) { + printf("TPM_Process_CertifyKey: Error, target key invalid payload %02x\n", + targetKey->tpm_store_asymkey->payload); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. If the key pointed to by certHandle is an identity key (certHandle -> keyUsage is + TPM_KEY_IDENTITY) */ + if ((returnCode == TPM_SUCCESS) && (certKey->keyUsage == TPM_KEY_IDENTITY)) { + /* a. If keyHandle -> keyflags -> keyInfo -> migratable is TRUE return TPM_MIGRATEFAIL */ + if (targetKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_CertifyKey: Error, target key is migratable\n"); + returnCode = TPM_MIGRATEFAIL; + } + } + /* 5. Validate that certHandle -> keyUsage is TPM_KEY_SIGN, TPM_KEY_IDENTITY or TPM_KEY_LEGACY, + if not return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: certHandle -> keyUsage %04hx\n", certKey->keyUsage); + if ((certKey->keyUsage != TPM_KEY_SIGNING) && + ((certKey->keyUsage) != TPM_KEY_IDENTITY) && + ((certKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey: Error, certHandle -> keyUsage %04hx is invalid\n", + certKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. Validate that keyHandle -> keyUsage is TPM_KEY_SIGN, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, + TPM_KEY_BIND or TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: keyHandle -> keyUsage %04hx\n", targetKey->keyUsage); + if ((targetKey->keyUsage != TPM_KEY_SIGNING) && + ((targetKey->keyUsage) != TPM_KEY_STORAGE) && + ((targetKey->keyUsage) != TPM_KEY_IDENTITY) && + ((targetKey->keyUsage) != TPM_KEY_BIND) && + ((targetKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey: Error, keyHandle -> keyUsage %04hx is invalid\n", + targetKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 7. If keyHandle -> digestAtRelease requires the use of PCRs 16 or higher to calculate or if + keyHandle -> localityAtRelease is not 0x1F */ + /* get PCR usage 16 and higher */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetPCRUsage(&pcrUsage, targetKey, 2); + } + /* get localityAtRelease */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetLocalityAtRelease(&localityAtRelease, targetKey); + } + if (returnCode == TPM_SUCCESS) { + if (pcrUsage || (localityAtRelease != TPM_LOC_ALL)) { + /* a. Set V1 to 1.2 */ + v1Version = 2; /* locality or >2 PCR's */ + } + /* 8. Else */ + else { + /* a. Set V1 to 1.1 */ + v1Version = 1; /* no locality and <= 2 PCR's */ + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: V1 %d\n", v1Version); + /* 9. If keyHandle -> pcrInfoSize is not 0 */ + if (targetKey->pcrInfo.size != 0) { + printf("TPM_Process_CertifyKey: Setting PCR info from key\n"); + /* a. If keyHandle -> keyFlags has pcrIgnoredOnRead set to FALSE */ + /* i. Create a digestAtRelease according to the specified PCR registers and + compare to keyHandle -> digestAtRelease and if a mismatch return + TPM_WRONGPCRVAL */ + /* ii. If specified validate any locality requests on error TPM_BAD_LOCALITY */ + /* NOTE: Done by TPM_KeyHandleEntries_GetKey() */ + /* b. If V1 is 1.1 */ + if (v1Version == 1) { + certifyType = 1; + /* i. Create C1 a TPM_CERTIFY_INFO structure */ + /* NOTE: Done by TPM_CertifyInfo_Init() */ + /* ii. Fill in C1 with the information from the key pointed to by keyHandle */ + /* NOTE: Done in common _Set() code below */ + /* iii. The TPM MUST set c1 -> pcrInfoSize to 44. */ + /* iv. The TPM MUST set c1 -> pcrInfo to a TPM_PCR_INFO structure properly filled + out using the information from keyHandle. */ + /* This function actually creates the cache, which is serialized later */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfo_CreateFromKey(&(certifyInfo.tpm_pcr_info), + targetKey); + } + /* v. The TPM MUST set c1 -> digestAtCreation to 20 bytes of 0x00. */ + if (returnCode == TPM_SUCCESS) { + TPM_Digest_Init(certifyInfo.tpm_pcr_info->digestAtCreation); + } + } + /* c. Else */ + else { + certifyType = 2; + /* i. Create C1 a TPM_CERTIFY_INFO2 structure */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + /* ii. Fill in C1 with the information from the key pointed to by keyHandle */ + /* NOTE: Done in common _Set() code below */ + /* iii. Set C1 -> pcrInfoSize to the size of an appropriate TPM_PCR_INFO_SHORT + structure. */ + /* iv. Set C1 -> pcrInfo to a properly filled out TPM_PCR_INFO_SHORT structure, + using the information from keyHandle. */ + /* This function actually creates the cache, which is serialized later */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoShort_CreateFromKey(&(certifyInfo2.tpm_pcr_info_short), + targetKey); + } + /* v. Set C1 -> migrationAuthoritySize to 0 */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + } + } + /* 10. Else */ + else { + certifyType = 1; + /* a. Create C1 a TPM_CERTIFY_INFO structure */ + /* NOTE: Done by TPM_CertifyInfo_Init() */ + /* b. Fill in C1 with the information from the key pointed to be keyHandle */ + /* NOTE: Done in common _Set() code below */ + /* c. The TPM MUST set c1 -> pcrInfoSize to 0 */ + /* NOTE: Done by TPM_CertifyInfo_Init() */ + } + } + /* 11. Create TPM_DIGEST H1 which is the SHA-1 hash of keyHandle -> pubKey -> key. Note that + is the actual public modulus, and does not include any structure formatting. */ + /* 12. Set C1 -> pubKeyDigest to H1 */ + /* NOTE: Done by TPM_CertifyInfo_Set() or TPM_CertifyInfo2_Set() */ + /* 13. The TPM copies the antiReplay parameter to c1 -> data. */ + /* Set C1 -> parentPCRStatus to the value from keyHandle NOTE: Implied in specification */ + /* Fill in C1 with the information from the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: Setting certifyInfo from target key\n"); + if (certifyType == 1) { + TPM_Digest_Copy(certifyInfo.data, antiReplay); + certifyInfo.parentPCRStatus = targetPCRStatus; + returnCode = TPM_CertifyInfo_Set(&certifyInfo, targetKey); + } + else { + TPM_Digest_Copy(certifyInfo2.data, antiReplay); + certifyInfo2.parentPCRStatus = targetPCRStatus; + returnCode = TPM_CertifyInfo2_Set(&certifyInfo2, targetKey); + } + } + /* 14. The TPM sets certifyInfo to C1. */ + /* NOTE Created as certifyInfo or certifyInfo2 */ + /* 15. The TPM creates m1, a message digest formed by taking the SHA-1 of c1. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: Digesting certifyInfo\n"); + if (certifyType == 1) { + returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo, + (TPM_STORE_FUNCTION_T)TPM_CertifyInfo_Store); + } + else { + returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo2, + (TPM_STORE_FUNCTION_T)TPM_CertifyInfo2_Store); + } + } + /* a. The TPM then computes a signature using certHandle -> sigScheme. The resulting signed blob + is returned in outData. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey: Signing certifyInfo digest with certifying key\n"); + returnCode = TPM_RSASignToSizedBuffer(&outData, /* signature */ + m1Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + certKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CertifyKey: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* Return certifyInfo */ + if (certifyType == 1) { + returnCode = TPM_CertifyInfo_Store(response, &certifyInfo); + } + else { + returnCode = TPM_CertifyInfo2_Store(response, &certifyInfo2); + } + } + if (returnCode == TPM_SUCCESS) { + /* Return outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *certHmacKey, /* HMAC key */ + cert_auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *targetHmacKey, /* HMAC key */ + target_auth_session_data, + outParamDigest, + keynonceOdd, + continueKeySession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueKeySession) && + keyAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, keyAuthHandle); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + certAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, certAuthHandle); + } + /* + cleanup + */ + TPM_CertifyInfo_Delete(&certifyInfo); /* @1 */ + TPM_CertifyInfo2_Delete(&certifyInfo2); /* @2 */ + TPM_SizedBuffer_Delete(&outData); /* @3 */ + return rcf; +} + +/* 13.9 TPM_CertifyKey2 rev 107 + + This command is based on TPM_CertifyKey, but includes the ability to certify a Certifiable + Migration Key (CMK), which requires extra input parameters. + + TPM_CertifyKey2 always produces a TPM_CERTIFY_INFO2 structure. + + TPM_CertifyKey2 does not support the case where (a) the key-to-be-certified requires a usage + authorization to be provided but (b) the certifying key does not. + + If a command tag (in the parameter array) specifies only one authorisation session, then the TPM + convention is that the first session listed is ignored (authDataUsage must be + TPM_NO_READ_PUBKEY_AUTH or TPM_AUTH_NEVER for this key) and the incoming session data is used for + the second auth session in the list. In TPM_CertifyKey2, the first session is the key to be + certified and the second session is the certifying key. +*/ + +TPM_RESULT TPM_Process_CertifyKey2(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle of the key to be certified. */ + TPM_KEY_HANDLE certHandle; /* Handle of the key to be used to certify the key. */ + TPM_DIGEST migrationPubDigest; /* The digest of a TPM_MSA_COMPOSITE structure, + containing at least one public key of a Migration + Authority */ + TPM_NONCE antiReplay; /* 160 bits of externally supplied data (typically a nonce + provided to prevent replay-attacks) */ + TPM_AUTHHANDLE keyAuthHandle; /* The authorization session handle used for the key to be + signed. */ + TPM_NONCE keynonceOdd; /* Nonce generated by system associated with keyAuthHandle + */ + TPM_BOOL continueKeySession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA keyAuth; /* The authorization session digest for the inputs and key + to be signed. HMAC key: key.usageAuth. */ + TPM_AUTHHANDLE certAuthHandle; /* The authorization session handle used for certHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with certAuthHandle + */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA certAuth; /* Authorization HMAC key: certKey.auth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *cert_auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *target_auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL certAuthHandleValid = FALSE; + TPM_BOOL keyAuthHandleValid = FALSE; + TPM_SECRET *certHmacKey; + TPM_SECRET *targetHmacKey; + TPM_BOOL certPCRStatus; + TPM_BOOL targetPCRStatus; + TPM_KEY *certKey = NULL; /* the key specified by certHandle */ + TPM_KEY *targetKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *certKeyUsageAuth; + TPM_SECRET *targetKeyUsageAuth; + TPM_STORE_ASYMKEY *targetStoreAsymkey; + TPM_CMK_MIGAUTH m2CmkMigauth; + TPM_BOOL hmacValid; + TPM_DIGEST migrationAuthority; + TPM_DIGEST m1Digest; /* digest of certifyInfo */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CERTIFY_INFO2 certifyInfo2; /* TPM_CERTIFY_INFO2 relative to keyHandle */ + TPM_SIZED_BUFFER outData; /* The signed public key. */ + + printf("TPM_Process_CertifyKey2: Ordinal Entry\n"); + TPM_CertifyInfo2_Init(&certifyInfo2); /* freed @1 */ + TPM_SizedBuffer_Init(&outData); /* freed @2 */ + TPM_CmkMigauth_Init(&m2CmkMigauth); /* freed @3 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* get certHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: keyHandle %08x\n", keyHandle); + returnCode = TPM_Load32(&certHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: certHandle %08x\n", certHandle); + /* get the migrationPubDigest parameter */ + returnCode = TPM_Digest_Load(migrationPubDigest, &command, ¶mSize); + } + /* get the antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag210(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&keyAuthHandle, + &keyAuthHandleValid, + keynonceOdd, + &continueKeySession, + keyAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_CertifyKey2: keyAuthHandle %08x\n", keyAuthHandle); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Get(&certAuthHandle, + &certAuthHandleValid, + nonceOdd, + &continueAuthSession, + certAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + printf("TPM_Process_CertifyKey2: certAuthHandle %08x\n", certAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CertifyKey2: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + certAuthHandleValid = FALSE; + keyAuthHandleValid = FALSE; + } + /* + Processing + */ + /* get the keys corresponding to the certHandle and keyHandle parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&targetKey, &targetPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&certKey, &certPCRStatus, tpm_state, certHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the TPM_STORE_ASYMKEY cache for the target TPM_KEY */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetStoreAsymkey(&targetStoreAsymkey, targetKey); + } + /* 1. The TPM validates that the key pointed to by certHandle has a signature scheme of + TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO */ + if (returnCode == TPM_SUCCESS) { + if ((certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (certKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_CertifyKey2: Error, invalid certKey sigScheme %04hx\n", + certKey->algorithmParms.sigScheme); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* 2. Verify command and key AuthData values: */ + /* a. If tag is TPM_TAG_RQU_AUTH2_COMMAND */ + /* i. The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTHFAIL on error */ + /* ii. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTH2FAIL on error */ + /* b. else if tag is TPM_TAG_RQU_AUTH1_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key + referenced by keyHandle, return TPM_AUTHFAIL on error */ + /* ii. The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTHFAIL on error */ + /* c. else if tag is TPM_TAG_RQU_COMMAND */ + /* i. Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key + referenced by keyHandle, return TPM_AUTHFAIL on error */ + /* ii. Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + /* NOTE: Simplified the above logic as follows */ + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND, process the first set of authorization data */ + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&targetKeyUsageAuth, targetKey); + } + /* get the first session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&target_auth_session_data, + &targetHmacKey, + tpm_state, + keyAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + targetKey, + targetKeyUsageAuth, /* OIAP */ + targetKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* The TPM verifies the AuthData in keyAuthHandle provides authorization to use the key + pointed to by keyHandle, return TPM_AUTHFAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *targetHmacKey, /* HMAC key */ + inParamDigest, + target_auth_session_data, /* authorization session */ + keynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueKeySession, + keyAuth); /* Authorization digest for input */ + } + /* If tag is not TPM_TAG_RQU_AUTH2_COMMAND */ + /* Verify that authDataUsage is TPM_AUTH_NEVER or TPM_NO_READ_PUBKEY_AUTH for the key referenced + by keyHandle, return TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (targetKey->authDataUsage == TPM_AUTH_ALWAYS) { + printf("TPM_Process_CertifyKey2: Error, target key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* If tag is TPM_TAG_RQU_AUTH2_COMMAND or TPM_TAG_RQU_AUTH1_COMMAND process the second set of + authorization data */ + /* get certHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&certKeyUsageAuth, certKey); + } + /* get the second session data */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&cert_auth_session_data, + &certHmacKey, + tpm_state, + certAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + certKey, + certKeyUsageAuth, /* OIAP */ + certKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* The TPM verifies the AuthData in certAuthHandle provides authorization to use the key + pointed to by certHandle, return TPM_AUTH2FAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_Auth2data_Check(tpm_state, + *certHmacKey, /* HMAC key */ + inParamDigest, + cert_auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + certAuth); /* Authorization digest for input */ + } + /* If the command is TPM_TAG_RQU_COMMAND */ + /* Verify that authDataUsage is TPM_AUTH_NEVER for the key referenced by certHandle, return + TPM_AUTHFAIL on error. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (certKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CertifyKey2: Error, cert key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 3. If the key pointed to by certHandle is an identity key (certHandle -> keyUsage is + TPM_KEY_IDENTITY) */ + if ((returnCode == TPM_SUCCESS) && (certKey->keyUsage == TPM_KEY_IDENTITY)) { + /* a. If keyHandle -> keyFlags -> migratable is TRUE and + [keyHandle -> keyFlags-> migrateAuthority is FALSE or + (keyHandle -> payload != TPM_PT_MIGRATE_RESTRICTED and + keyHandle -> payload != TPM_PT_MIGRATE_EXTERNAL)] + return TPM_MIGRATEFAIL */ + if ((targetKey->keyFlags & TPM_MIGRATABLE) && + (!(targetKey->keyFlags & TPM_MIGRATEAUTHORITY) || + ((targetStoreAsymkey->payload != TPM_PT_MIGRATE_RESTRICTED) && + (targetStoreAsymkey->payload != TPM_PT_MIGRATE_EXTERNAL)))) { + printf("TPM_Process_CertifyKey2: Error, target key migrate fail\n"); + returnCode = TPM_MIGRATEFAIL; + } + } + /* 4. Validate that certHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or + TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: certHandle ->keyUsage %04hx\n", certKey->keyUsage); + if ((certKey->keyUsage != TPM_KEY_SIGNING) && + ((certKey->keyUsage) != TPM_KEY_IDENTITY) && + ((certKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey2: Error, keyUsage %04hx is invalid\n", + certKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, + TPM_KEY_BIND or TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: keyHandle -> keyUsage %04hx\n", targetKey->keyUsage); + if ((targetKey->keyUsage != TPM_KEY_SIGNING) && + ((targetKey->keyUsage) != TPM_KEY_STORAGE) && + ((targetKey->keyUsage) != TPM_KEY_IDENTITY) && + ((targetKey->keyUsage) != TPM_KEY_BIND) && + ((targetKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_CertifyKey2: Error, keyHandle -> keyUsage %04hx is invalid\n", + targetKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. The TPM SHALL create a c1 a TPM_CERTIFY_INFO2 structure from the key pointed to by + keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CertifyInfo2_Set(&certifyInfo2, targetKey); + } + /* 7. Create TPM_DIGEST H1 which is the SHA-1 hash of keyHandle -> pubKey -> key. Note that + is the actual public modulus, and does not include any structure formatting. */ + /* 8. Set C1 -> pubKeyDigest to H1 */ + /* NOTE: Done by TPM_CertifyInfo2_Set() */ + if (returnCode == TPM_SUCCESS) { + /* 9. Copy the antiReplay parameter to c1 -> data */ + TPM_Digest_Copy(certifyInfo2.data, antiReplay); + /* 10. Copy other keyHandle parameters into C1 */ + certifyInfo2.parentPCRStatus = targetPCRStatus; + /* 11. If keyHandle -> payload == TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_EXTERNAL */ + if ((targetStoreAsymkey->payload == TPM_PT_MIGRATE_RESTRICTED) || + (targetStoreAsymkey->payload == TPM_PT_MIGRATE_EXTERNAL)) { + printf("TPM_Process_CertifyKey2: " + "TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_RESTRICTED\n"); + /* a. create thisPubKey, a TPM_PUBKEY structure containing the public key, algorithm and + parameters corresponding to keyHandle */ + /* NOTE Not required. Digest is created directly below */ + /* b. Verify that the migration authorization is valid for this key */ + /* i. Create M2 a TPM_CMK_MIGAUTH structure */ + /* NOTE Done by TPM_CmkMigauth_Init() */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set M2 -> msaDigest to migrationPubDigest */ + TPM_Digest_Copy(m2CmkMigauth.msaDigest, migrationPubDigest ); + /* iii. Set M2 -> pubKeyDigest to SHA-1[thisPubKey] */ + returnCode = TPM_Key_GeneratePubkeyDigest(m2CmkMigauth.pubKeyDigest, targetKey); + } + /* iv. Verify that [keyHandle -> migrationAuth] == HMAC(M2) signed by using tpmProof as + the secret and return error TPM_MA_SOURCE on mismatch */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Check migrationAuth\n"); + returnCode = + TPM_CmkMigauth_CheckHMAC(&hmacValid, /* result */ + targetStoreAsymkey->migrationAuth, /* expect */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkMigauth); + } + if (returnCode == TPM_SUCCESS) { + if (!hmacValid) { + printf("TPM_Process_CertifyKey2: Error, Invalid migrationAuth\n"); + returnCode = TPM_MA_SOURCE; + } + } + /* c. Set C1 -> migrationAuthority = SHA-1(migrationPubDigest || keyHandle -> payload) + */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Set migrationAuthority\n"); + returnCode = TPM_SHA1(migrationAuthority, + TPM_DIGEST_SIZE, migrationPubDigest, + sizeof(TPM_PAYLOAD_TYPE), &(targetStoreAsymkey->payload), + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Set(&(certifyInfo2.migrationAuthority), + TPM_DIGEST_SIZE, migrationAuthority); + } + /* d. if keyHandle -> payload == TPM_PT_MIGRATE_RESTRICTED */ + /* i. Set C1 -> payloadType = TPM_PT_MIGRATE_RESTRICTED */ + /* e. if keyHandle -> payload == TPM_PT_MIGRATE_EXTERNAL */ + /* i. Set C1 -> payloadType = TPM_PT_MIGRATE_EXTERNAL */ + /* NOTE: Done by TPM_CertifyInfo2_Set() */ + } + /* 12. Else */ + else { + printf("TPM_Process_CertifyKey2: " + " Not TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_RESTRICTED\n"); + /* a. set C1 -> migrationAuthority = NULL */ + /* b. set C1 -> migrationAuthoritySize = 0 */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + /* c. Set C1 -> payloadType = TPM_PT_ASYM */ + certifyInfo2.payloadType = TPM_PT_ASYM; + } + } + if (returnCode == TPM_SUCCESS) { + /* 13. If keyHandle -> pcrInfoSize is not 0 */ + if (targetKey->pcrInfo.size != 0) { + printf("TPM_Process_CertifyKey2: Setting PCR info from key\n"); + /* a. The TPM MUST set c1 -> pcrInfoSize to match the pcrInfoSize from the keyHandle + key. */ + /* b. The TPM MUST set c1 -> pcrInfo to match the pcrInfo from the keyHandle key */ + /* This function actually creates the cache, which is serialized later */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoShort_CreateFromKey(&(certifyInfo2.tpm_pcr_info_short), + targetKey); + } + /* c. If keyHandle -> keyFlags has pcrIgnoredOnRead set to FALSE */ + /* i. Create a digestAtRelease according to the specified PCR registers and compare to + keyHandle -> digestAtRelease and if a mismatch return TPM_WRONGPCRVAL */ + /* ii. If specified validate any locality requests on error TPM_BAD_LOCALITY */ + /* NOTE: Done by TPM_KeyHandleEntries_GetKey() */ + } + /* 14. Else */ + /* a. The TPM MUST set c1 -> pcrInfoSize to 0 */ + /* NOTE: Done by TPM_CertifyInfo2_Init() */ + } + /* 15. The TPM creates m1, a message digest formed by taking the SHA-1 of c1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Digesting certifyInfo\n"); + returnCode = TPM_SHA1_GenerateStructure(m1Digest, &certifyInfo2, + (TPM_STORE_FUNCTION_T)TPM_CertifyInfo2_Store); + } + /* a. The TPM then computes a signature using certHandle -> sigScheme. The resulting signed blob + is returned in outData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifyKey2: Signing certifyInfo digest\n"); + returnCode = TPM_RSASignToSizedBuffer(&outData, /* signature */ + m1Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + certKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CertifyKey2: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* Return certifyInfo */ + returnCode = TPM_CertifyInfo2_Store(response, &certifyInfo2); + } + if (returnCode == TPM_SUCCESS) { + /* Return outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *targetHmacKey, /* HMAC key */ + target_auth_session_data, + outParamDigest, + keynonceOdd, + continueKeySession); + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *certHmacKey, /* HMAC key */ + cert_auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueKeySession) && + keyAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, keyAuthHandle); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + certAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, certAuthHandle); + } + /* + cleanup + */ + TPM_CertifyInfo2_Delete(&certifyInfo2); /* @1 */ + TPM_SizedBuffer_Delete(&outData); /* @2 */ + TPM_CmkMigauth_Delete(&m2CmkMigauth); /* @3 */ + return rcf; +} + +/* 28.3 TPM_CertifySelfTest rev 94 + + CertifySelfTest causes the TPM to perform a full self-test and return an authenticated value if + the test passes. + + If a caller itself requires proof, it is sufficient to use any signing key for which only the TPM + and the caller have AuthData. + + If a caller requires proof for a third party, the signing key must be one whose signature is + trusted by the third party. A TPM-identity key may be suitable. + + Information returned by TPM_CertifySelfTest MUST NOT aid identification of an individual TPM. +*/ + +TPM_RESULT TPM_Process_CertifySelfTest(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform + digital signatures. */ + TPM_NONCE antiReplay; /* AntiReplay nonce to prevent replay of messages */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the + inputs and use of keyHandle. HMAC key: key.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *sigKey; /* from keyHandle */ + TPM_BOOL sigKeyPCRStatus; + TPM_SECRET *sigKeyUsageAuth; + TPM_COMMAND_CODE nOrdinal; /* ordinal in nbo */ + TPM_DIGEST m2Digest; /* message to sign */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_CertifySelfTest: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&sig); /* freed @1 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get the antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifySelfTest: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CertifySelfTest: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. The TPM SHALL perform TPM_SelfTestFull. If the test fails the TPM returns the appropriate + error code. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifySelfTest: Running self test\n"); + returnCode = TPM_SelfTestFullCmd(tpm_state); + } + /* 2. After successful completion of the self-test the TPM then validates the authorization to + use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &sigKeyPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CertifySelfTest: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&sigKeyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + sigKeyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* Validate the command parameters using privAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* a. If the key pointed to by keyHandle has a signature scheme that is not + TPM_SS_RSASSAPKCS1v15_SHA1, the TPM may either return TPM_BAD_SCHEME or may return + TPM_SUCCESS and a vendor specific signature. */ + if (returnCode == TPM_SUCCESS) { + if (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_Process_CertifySelfTest: Error, invalid sigKey sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_BAD_SCHEME; + } + } + /* The key in keyHandle MUST have a KEYUSAGE value of type TPM_KEY_SIGNING or TPM_KEY_LEGACY or + TPM_KEY_IDENTITY. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + (sigKey->keyUsage != TPM_KEY_LEGACY) && + (sigKey->keyUsage != TPM_KEY_IDENTITY)) { + printf("TPM_Process_CertifySelfTest: Error, Illegal keyUsage %04hx\n", + sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Create t1 the NOT null terminated string of "Test Passed" */ + /* 4. The TPM creates m2 the message to sign by concatenating t1 || AntiReplay || ordinal. */ + if (returnCode == TPM_SUCCESS) { + nOrdinal = htonl(ordinal); + returnCode = TPM_SHA1(m2Digest, + sizeof("Test Passed") - 1, "Test Passed", + TPM_NONCE_SIZE, antiReplay, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + 0, NULL); + } + /* 5. The TPM signs the SHA-1 of m2 using the key identified by keyHandle, and returns the + signature as sig. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CertifySelfTest: Signing certifyInfo digest\n"); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + m2Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CertifySelfTest: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return sig */ + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&sig); /* @1 */ + return rcf; +} diff --git a/src/tpm_cryptoh.h b/src/tpm_cryptoh.h new file mode 100644 index 00000000..1f01aae0 --- /dev/null +++ b/src/tpm_cryptoh.h @@ -0,0 +1,358 @@ +/********************************************************************************/ +/* */ +/* High Level Platform Independent Crypto */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_cryptoh.h 4300 2011-01-18 18:00:27Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_CRYPTOH_H +#define TPM_CRYPTOH_H + +#include "tpm_global.h" +#include "tpm_types.h" +#include "tpm_sizedbuffer.h" +#include "tpm_structures.h" + +/* + TPM_SIGN_INFO +*/ + +void TPM_SignInfo_Init(TPM_SIGN_INFO *tpm_sign_info); +TPM_RESULT TPM_SignInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SIGN_INFO *tpm_sign_info); +void TPM_SignInfo_Delete(TPM_SIGN_INFO *tpm_sign_info); + +/* + TPM_CERTIFY_INFO +*/ + +void TPM_CertifyInfo_Init(TPM_CERTIFY_INFO *tpm_certify_info); +TPM_RESULT TPM_CertifyInfo_Load(TPM_CERTIFY_INFO *tpm_certify_info, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CertifyInfo_Store(TPM_STORE_BUFFER *sbuffer, + TPM_CERTIFY_INFO *tpm_certify_info); +void TPM_CertifyInfo_Delete(TPM_CERTIFY_INFO *tpm_certify_info); + +TPM_RESULT TPM_CertifyInfo_Set(TPM_CERTIFY_INFO *tpm_certify_info, + TPM_KEY *tpm_key); + +/* + TPM_CERTIFY_INFO2 +*/ + +void TPM_CertifyInfo2_Init(TPM_CERTIFY_INFO2 *tpm_certify_info2); +TPM_RESULT TPM_CertifyInfo2_Load(TPM_CERTIFY_INFO2 *tpm_certify_info2, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CertifyInfo2_Store(TPM_STORE_BUFFER *sbuffer, + TPM_CERTIFY_INFO2 *tpm_certify_info2); +void TPM_CertifyInfo2_Delete(TPM_CERTIFY_INFO2 *tpm_certify_info2); + +TPM_RESULT TPM_CertifyInfo2_Set(TPM_CERTIFY_INFO2 *tpm_certify_info2, + TPM_KEY *tpm_key); + +/* + TPM_SYMMETRIC_KEY +*/ + +void TPM_SymmetricKey_Init(TPM_SYMMETRIC_KEY *tpm_symmetric_key); +TPM_RESULT TPM_SymmetricKey_Load(TPM_SYMMETRIC_KEY *tpm_symmetric_key, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_SymmetricKey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY *tpm_symmetric_key); +void TPM_SymmetricKey_Delete(TPM_SYMMETRIC_KEY *tpm_symmetric_key); + +TPM_RESULT TPM_SymmetricKeyData_EncryptSbuffer(TPM_SIZED_BUFFER *encrypt_data, + TPM_STORE_BUFFER *sbuffer, + const TPM_SYMMETRIC_KEY_TOKEN + tpm_symmetric_key_data); +TPM_RESULT TPM_SymmetricKeyData_StreamCrypt(unsigned char *data_out, + const unsigned char *data_in, + uint32_t data_size, + TPM_ALGORITHM_ID algId, + TPM_ENC_SCHEME encScheme, + const unsigned char *symmetric_key, + uint32_t symmetric_key_size, + unsigned char *pad_in, + uint32_t pad_in_size); + +/* + RSA functions +*/ + + +TPM_RESULT TPM_RSAPrivateDecryptMalloc(unsigned char **decrypt_data, + uint32_t *decrypt_data_length, + unsigned char *encrypt_data, + uint32_t encrypt_data_size, + TPM_KEY *tpm_key); + +TPM_RESULT TPM_RSAPrivateDecryptH(unsigned char *decrypt_data, + uint32_t *decrypt_data_length, + uint32_t decrypt_data_size, + unsigned char *encrypt_data, + uint32_t encrypt_data_size, + TPM_KEY *tpm_key); + +TPM_RESULT TPM_RSAPublicEncryptSbuffer_Key(TPM_SIZED_BUFFER *enc_data, + TPM_STORE_BUFFER *sbuffer, + TPM_KEY *tpm_key); +TPM_RESULT TPM_RSAPublicEncrypt_Key(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_KEY *tpm_key); +TPM_RESULT TPM_RSAPublicEncrypt_Pubkey(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_PUBKEY *tpm_pubkey); + +TPM_RESULT TPM_RSAPublicEncrypt_Common(TPM_SIZED_BUFFER *enc_data, + const unsigned char *decrypt_data, + size_t decrypt_data_size, + TPM_ENC_SCHEME encScheme, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); + +TPM_RESULT TPM_RSASignH(unsigned char *signature, + unsigned int *signature_length, + unsigned int signature_size, + const unsigned char *message, + size_t message_size, + TPM_KEY *tpm_key); + +TPM_RESULT TPM_RSASignToSizedBuffer(TPM_SIZED_BUFFER *signature, + const unsigned char *message, + size_t message_size, + TPM_KEY *tpm_key); + +TPM_RESULT TPM_RSAVerifyH(TPM_SIZED_BUFFER *signature, + const unsigned char *message, + uint32_t message_size, + TPM_PUBKEY *tpm_pubkey); +TPM_RESULT TPM_RSAVerify(unsigned char *signature, + unsigned int signature_size, + TPM_SIG_SCHEME sigScheme, + const unsigned char *message, + uint32_t message_size, + unsigned char *narr, + uint32_t nbytes, + unsigned char *earr, + uint32_t ebytes); + +TPM_RESULT TPM_RSA_exponent_verify(unsigned long exponent); + +/* + OAEP Padding +*/ + +TPM_RESULT TPM_RSA_padding_add_PKCS1_OAEP(unsigned char *em, uint32_t emLen, + const unsigned char *from, uint32_t fLen, + const unsigned char *pHash, + const unsigned char *seed); +TPM_RESULT TPM_RSA_padding_check_PKCS1_OAEP(unsigned char *to, uint32_t *tLen, uint32_t tSize, + const unsigned char *em, uint32_t emLen, + unsigned char *pHash, + unsigned char *seed); + +/* + Digest functions - SHA-1 and HMAC +*/ + +TPM_RESULT TPM_SHA1(TPM_DIGEST md, ...); +TPM_RESULT TPM_SHA1_Check(TPM_DIGEST digest_expect, ...); +TPM_RESULT TPM_SHA1Sbuffer(TPM_DIGEST tpm_digest, + TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_SHA1_GenerateStructure(TPM_DIGEST tpm_digest, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction); +TPM_RESULT TPM_SHA1_CheckStructure(TPM_DIGEST expected_digest, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction, + TPM_RESULT error); + +TPM_RESULT TPM_HMAC_GenerateSbuffer(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_HMAC_GenerateStructure(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction); +TPM_RESULT TPM_HMAC_Generate(TPM_HMAC tpm_hmac, + const TPM_SECRET hmac_key, + ...); + +TPM_RESULT TPM_HMAC_CheckSbuffer(TPM_BOOL *valid, + TPM_HMAC expect, + const TPM_SECRET hmac_key, + TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_HMAC_Check(TPM_BOOL *valid, + TPM_HMAC expect, + const TPM_SECRET key, + ...); +TPM_RESULT TPM_HMAC_CheckStructure(const TPM_SECRET hmac_key, + void *structure, + TPM_HMAC expect, + TPM_STORE_FUNCTION_T storeFunction, + TPM_RESULT error); + +/* + XOR +*/ + +void TPM_XOR(unsigned char *out, + const unsigned char *in1, + const unsigned char *in2, + size_t length); + +/* + MGF1 +*/ + +TPM_RESULT TPM_MGF1(unsigned char *array, + uint32_t arrayLen, + const unsigned char *seed, + uint32_t seedLen); +TPM_RESULT TPM_MGF1_GenerateArray(unsigned char **array, + uint32_t arrayLen, + uint32_t seedLen, + ...); +/* bignum */ + +TPM_RESULT TPM_bn2binMalloc(unsigned char **bin, + unsigned int *bytes, + TPM_BIGNUM bn_in, + uint32_t padBytes); +TPM_RESULT TPM_bn2binArray(unsigned char *bin, + unsigned int bytes, + TPM_BIGNUM bn); +TPM_RESULT TPM_2bin2bn(TPM_BIGNUM *bignum_in, + const unsigned char *bin0, uint32_t size0, + const unsigned char *bin1, uint32_t size1); + +/* + Self Test +*/ + +TPM_RESULT TPM_CryptoTest(void); + + +/* + Processing functions +*/ + +TPM_RESULT TPM_Process_Sign(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_SHA1Start(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_SHA1Update(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_SHA1Complete(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_SHA1CompleteExtend(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_GetRandom(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_StirRandom(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_CertifyKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_CertifyKey2(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_CertifySelfTest(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + +#endif diff --git a/src/tpm_daa.c b/src/tpm_daa.c new file mode 100644 index 00000000..1ac96ffe --- /dev/null +++ b/src/tpm_daa.c @@ -0,0 +1,5728 @@ +/********************************************************************************/ +/* */ +/* DAA Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_daa.c 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_process.h" +#include "tpm_sizedbuffer.h" + +#include "tpm_daa.h" + +/* + TPM_DAA_SESSION_DATA (the entire array) +*/ + +void TPM_DaaSessions_Init(TPM_DAA_SESSION_DATA *daaSessions) +{ + size_t i; + + printf(" TPM_DaaSessions_Init:\n"); + for (i = 0 ; i < TPM_MIN_DAA_SESSIONS ; i++) { + TPM_DaaSessionData_Init(&(daaSessions[i])); + } + return; +} + +/* TPM_DaaSessions_Load() reads a count of the number of stored sessions and then loads those + sessions. + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DaaSessions_Init() +*/ + +TPM_RESULT TPM_DaaSessions_Load(TPM_DAA_SESSION_DATA *daaSessions, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t activeCount; + + printf(" TPM_DaaSessions_Load:\n"); + /* load active count */ + if (rc == 0) { + rc = TPM_Load32(&activeCount, stream, stream_size); + } + if (rc == 0) { + if (activeCount > TPM_MIN_DAA_SESSIONS) { + printf("TPM_DaaSessions_Load: Error (fatal) %u sessions, %u slots\n", + activeCount, TPM_MIN_DAA_SESSIONS); + rc = TPM_FAIL; + } + } + if (rc == 0) { + printf(" TPM_DaaSessions_Load: Loading %u sessions\n", activeCount); + } + /* load DAA sessions */ + for (i = 0 ; (rc == 0) && (i < activeCount) ; i++) { + rc = TPM_DaaSessionData_Load(&(daaSessions[i]), stream, stream_size); + } + return rc; +} + +/* TPM_DaaSessions_Store() stores a count of the active sessions, followed by the sessions. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DaaSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_DAA_SESSION_DATA *daaSessions) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t space; + uint32_t activeCount; + + /* store active count */ + if (rc == 0) { + TPM_DaaSessions_GetSpace(&space, daaSessions); + activeCount = TPM_MIN_DAA_SESSIONS - space; + printf(" TPM_DaaSessions_Store: Storing %u sessions\n", activeCount); + rc = TPM_Sbuffer_Append32(sbuffer, activeCount); + } + /* store DAA sessions */ + for (i = 0 ; (rc == 0) && (i < TPM_MIN_DAA_SESSIONS) ; i++) { + if ((daaSessions[i]).valid) { /* if the session is active */ + rc = TPM_DaaSessionData_Store(sbuffer, &(daaSessions[i])); + } + } + return rc; +} + +/* TPM_DaaSessions_Delete() terminates all loaded DAA sessions + +*/ + +void TPM_DaaSessions_Delete(TPM_DAA_SESSION_DATA *daaSessions) +{ + size_t i; + + printf(" TPM_DaaSessions_Delete:\n"); + for (i = 0 ; i < TPM_MIN_DAA_SESSIONS ; i++) { + TPM_DaaSessionData_Delete(&(daaSessions[i])); + } + return; +} + +/* TPM_DaaSessions_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not. + + If TRUE, 'index' holds the first free position. +*/ + +void TPM_DaaSessions_IsSpace(TPM_BOOL *isSpace, + uint32_t *index, + TPM_DAA_SESSION_DATA *daaSessions) +{ + printf(" TPM_DaaSessions_IsSpace:\n"); + for (*index = 0, *isSpace = FALSE ; *index < TPM_MIN_DAA_SESSIONS ; (*index)++) { + if (!((daaSessions[*index]).valid)) { + printf(" TPM_DaaSessions_IsSpace: Found space at %u\n", *index); + *isSpace = TRUE; + break; + } + } + return; +} + +/* TPM_DaaSessions_GetSpace() returns the number of unused daaHandle's. + +*/ + +void TPM_DaaSessions_GetSpace(uint32_t *space, + TPM_DAA_SESSION_DATA *daaSessions) +{ + uint32_t i; + + printf(" TPM_DaaSessions_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_MIN_DAA_SESSIONS ; i++) { + if (!((daaSessions[i]).valid)) { + (*space)++; + } + } + return; +} + +/* TPM_DaaSessions_StoreHandles() stores + + - the number of loaded sessions + - a list of session handles +*/ + +TPM_RESULT TPM_DaaSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_DAA_SESSION_DATA *daaSessions) +{ + TPM_RESULT rc = 0; + uint16_t i; + uint32_t space; + + printf(" TPM_DaaSessions_StoreHandles:\n"); + /* get the number of loaded handles */ + if (rc == 0) { + TPM_DaaSessions_GetSpace(&space, daaSessions); + /* store loaded handle count. Safe case because of TPM_MIN_DAA_SESSIONS value */ + rc = TPM_Sbuffer_Append16(sbuffer, (uint16_t)(TPM_MIN_DAA_SESSIONS - space)); + } + for (i = 0 ; (rc == 0) && (i < TPM_MIN_DAA_SESSIONS) ; i++) { + if ((daaSessions[i]).valid) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, (daaSessions[i]).daaHandle); /* store it */ + } + } + return rc; +} + +/* TPM_DaaSessions_GetNewHandle() checks for space in the DAA sessions table. + + If there is space, it returns a TPM_DAA_SESSION_DATA entry in 'tpm_daa_session_data' and its + handle in 'daaHandle'. The entry is marked 'valid'. + + If *daaHandle non-zero, the suggested value is tried first. + + Returns TPM_RESOURCES if there is no space in the sessions table. +*/ + +TPM_RESULT TPM_DaaSessions_GetNewHandle(TPM_DAA_SESSION_DATA **tpm_daa_session_data, /* entry */ + TPM_HANDLE *daaHandle, + TPM_BOOL *daaHandleValid, + TPM_DAA_SESSION_DATA *daaSessions) /* array */ +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_DaaSessions_GetNewHandle:\n"); + *daaHandle = FALSE; + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_DaaSessions_IsSpace(&isSpace, /* TRUE if space available */ + &index, /* if space available, index into array */ + daaSessions); /* array */ + if (!isSpace) { + printf("TPM_DaaSessions_GetNewHandle: Error, no space in daaSessions table\n"); + rc = TPM_RESOURCES; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(daaHandle, /* I/O, pointer to handle */ + daaSessions, /* handle array */ + FALSE, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_DaaSessions_GetEntry); + } + if (rc == 0) { + printf(" TPM_DaaSessions_GetNewHandle: Assigned handle %08x\n", *daaHandle); + *tpm_daa_session_data = &(daaSessions[index]); + TPM_DaaSessionData_Init(*tpm_daa_session_data); /* should be redundant since + terminate should have done + this */ + (*tpm_daa_session_data)->daaHandle = *daaHandle; + (*tpm_daa_session_data)->valid = TRUE; + *daaHandleValid = TRUE; + } + return rc; +} + +/* TPM_DaaSessions_GetEntry() searches all entries for the entry matching the handle, and + returns the TPM_DAA_SESSION_DATA entry associated with the handle. + + Returns + 0 for success + TPM_BAD_HANDLE if the handle is not found +*/ + +TPM_RESULT TPM_DaaSessions_GetEntry(TPM_DAA_SESSION_DATA **tpm_daa_session_data, /* session for + daaHandle */ + TPM_DAA_SESSION_DATA *daaSessions, /* points to first session in + array */ + TPM_HANDLE daaHandle) /* input */ +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_DaaSessions_GetEntry: daaHandle %08x\n", daaHandle); + for (i = 0, found = FALSE ; (i < TPM_MIN_DAA_SESSIONS) && !found ; i++) { + if ((daaSessions[i].valid) && + (daaSessions[i].daaHandle == daaHandle)) { /* found */ + found = TRUE; + *tpm_daa_session_data = &(daaSessions[i]); + } + } + if (!found) { + printf(" TPM_DaaSessions_GetEntry: session handle %08x not found\n", + daaHandle); + rc = TPM_BAD_HANDLE; + } + return rc; +} + +/* TPM_DaaSessions_AddEntry() adds an TPM_DAA_SESSION_DATA object to the list. + + If *tpm_handle == 0, a value is assigned. If *tpm_handle != 0, that value is used if it it not + currently in use. + + The handle is returned in tpm_handle. +*/ + +TPM_RESULT TPM_DaaSessions_AddEntry(TPM_HANDLE *tpm_handle, /* i/o */ + TPM_BOOL keepHandle, /* input */ + TPM_DAA_SESSION_DATA *daaSessions, /* input */ + TPM_DAA_SESSION_DATA *tpm_daa_session_data) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_DaaSessions_AddEntry:\n"); + /* check for valid TPM_DAA_SESSION_DATA */ + if (rc == 0) { + if (tpm_daa_session_data == NULL) { /* NOTE: should never occur */ + printf("TPM_DaaSessions_AddEntry: Error (fatal), NULL TPM_DAA_SESSION_DATA\n"); + rc = TPM_FAIL; + } + } + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_DaaSessions_IsSpace(&isSpace, &index, daaSessions); + if (!isSpace) { + printf("TPM_DaaSessions_AddEntry: Error, session entries full\n"); + rc = TPM_RESOURCES; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(tpm_handle, /* I/O */ + daaSessions, /* handle array */ + keepHandle, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_DaaSessions_GetEntry); + } + if (rc == 0) { + TPM_DaaSessionData_Copy(&(daaSessions[index]), *tpm_handle, tpm_daa_session_data); + daaSessions[index].valid = TRUE; + printf(" TPM_DaaSessions_AddEntry: Index %u handle %08x\n", + index, daaSessions[index].daaHandle); + } + return rc; +} + +/* TPM_DaaSessions_TerminateHandle() terminates the session associated with 'daaHandle'. + +*/ + +TPM_RESULT TPM_DaaSessions_TerminateHandle(TPM_DAA_SESSION_DATA *daaSessions, + TPM_HANDLE daaHandle) +{ + TPM_RESULT rc = 0; + TPM_DAA_SESSION_DATA *tpm_daa_session_data; + + printf(" TPM_DaaSessions_TerminateHandle: daaHandle %08x\n", daaHandle); + /* get the TPM_DAA_SESSION_DATA associated with the TPM_HANDLE */ + if (rc == 0) { + rc = TPM_DaaSessions_GetEntry(&tpm_daa_session_data, /* returns entry in array */ + daaSessions, /* array */ + daaHandle); + } + /* invalidate the valid handle */ + if (rc == 0) { + TPM_DaaSessionData_Delete(tpm_daa_session_data); + } + return rc; +} + +/* + TPM_DAA_SESSION_DATA (one element of the array) +*/ + +/* TPM_DaaSessionData_Init() initializes the DAA session. + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DaaSessionData_Init(TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + printf(" TPM_DaaSessionData_Init:\n"); + TPM_DAAIssuer_Init(&(tpm_daa_session_data->DAA_issuerSettings)); + TPM_DAATpm_Init(&(tpm_daa_session_data->DAA_tpmSpecific)); + TPM_DAAContext_Init(&(tpm_daa_session_data->DAA_session)); + TPM_DAAJoindata_Init(&(tpm_daa_session_data->DAA_joinSession)); + tpm_daa_session_data->daaHandle = 0; + tpm_daa_session_data->valid = FALSE; + return; +} + +/* TPM_DaaSessionData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DaaSessionData_Init() + After use, call TPM_DaaSessionData_Delete() to free memory +*/ + +TPM_RESULT TPM_DaaSessionData_Load(TPM_DAA_SESSION_DATA *tpm_daa_session_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DaaSessionData_Load:\n"); + /* load DAA_issuerSettings */ + if (rc == 0) { + rc = TPM_DAAIssuer_Load(&(tpm_daa_session_data->DAA_issuerSettings), stream, stream_size); + } + /* load DAA_tpmSpecific */ + if (rc == 0) { + rc = TPM_DAATpm_Load(&(tpm_daa_session_data->DAA_tpmSpecific), stream, stream_size); + } + /* load DAA_session */ + if (rc == 0) { + rc = TPM_DAAContext_Load(&(tpm_daa_session_data->DAA_session),stream, stream_size); + } + /* load DAA_joinSession */ + if (rc == 0) { + rc = TPM_DAAJoindata_Load(&(tpm_daa_session_data->DAA_joinSession), stream, stream_size); + } + /* load daaHandle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_daa_session_data->daaHandle), stream, stream_size); + } + /* set valid */ + if (rc == 0) { + tpm_daa_session_data->valid = TRUE; + } + return rc; +} + +/* TPM_DaaSessionData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DaaSessionData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DaaSessionData_Store:\n"); + /* store DAA_issuerSettings */ + if (rc == 0) { + rc = TPM_DAAIssuer_Store(sbuffer, &(tpm_daa_session_data->DAA_issuerSettings)); + } + /* store DAA_tpmSpecific */ + if (rc == 0) { + rc = TPM_DAATpm_Store(sbuffer, &(tpm_daa_session_data->DAA_tpmSpecific)); + } + /* store DAA_session */ + if (rc == 0) { + rc = TPM_DAAContext_Store(sbuffer, &(tpm_daa_session_data->DAA_session)); + } + /* store DAA_joinSession */ + if (rc == 0) { + rc = TPM_DAAJoindata_Store(sbuffer, &(tpm_daa_session_data->DAA_joinSession)); + } + /* store daaHandle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_daa_session_data->daaHandle); + } + return rc; +} + +/* TPM_DaaSessionData_Delete() terminates the DAA session. + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DaaSessionData_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DaaSessionData_Delete(TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + printf(" TPM_DaaSessionData_Delete:\n"); + if (tpm_daa_session_data != NULL) { + TPM_DAAIssuer_Delete(&(tpm_daa_session_data->DAA_issuerSettings)); + TPM_DAATpm_Delete(&(tpm_daa_session_data->DAA_tpmSpecific)); + TPM_DAAContext_Delete(&(tpm_daa_session_data->DAA_session)); + TPM_DAAJoindata_Delete(&(tpm_daa_session_data->DAA_joinSession)); + TPM_DaaSessionData_Init(tpm_daa_session_data); + } + return; +} + +/* TPM_DaaSessionData_Copy() copies the source to the destination. The source handle is ignored, + since it might already be used. +*/ + +void TPM_DaaSessionData_Copy(TPM_DAA_SESSION_DATA *dest_daa_session_data, + TPM_HANDLE tpm_handle, + TPM_DAA_SESSION_DATA *src_daa_session_data) +{ + dest_daa_session_data->daaHandle = tpm_handle; + TPM_DAAIssuer_Copy(&(dest_daa_session_data->DAA_issuerSettings), + &(src_daa_session_data->DAA_issuerSettings)); + TPM_DAATpm_Copy(&(dest_daa_session_data->DAA_tpmSpecific), + &(src_daa_session_data->DAA_tpmSpecific)); + TPM_DAAContext_Copy(&(dest_daa_session_data->DAA_session), + &(src_daa_session_data->DAA_session)); + TPM_DAAJoindata_Copy(&(dest_daa_session_data->DAA_joinSession), + &(src_daa_session_data->DAA_joinSession)); + dest_daa_session_data->valid= src_daa_session_data->valid; + return; +} + +/* TPM_DaaSessionData_CheckStage() verifies that the actual command processing stage is consistent + with the stage expected by the TPM state. +*/ + +TPM_RESULT TPM_DaaSessionData_CheckStage(TPM_DAA_SESSION_DATA *tpm_daa_session_data, + BYTE stage) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DaaSessionData_CheckStage:\n"); + if (tpm_daa_session_data->DAA_session.DAA_stage != stage) { + printf("TPM_DaaSessionData_CheckStage: Error, stage expected %u actual %u\n", + tpm_daa_session_data->DAA_session.DAA_stage, stage); + rc = TPM_DAA_STAGE; + } + return rc; +} + +/* + TPM_DAA_ISSUER +*/ + +/* TPM_DAAIssuer_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAAIssuer_Init(TPM_DAA_ISSUER *tpm_daa_issuer) +{ + printf(" TPM_DAAIssuer_Init:\n"); + + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_R0); + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_R1); + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_S0); + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_S1); + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_n); + TPM_Digest_Init(tpm_daa_issuer->DAA_digest_gamma); + memset(tpm_daa_issuer->DAA_generic_q, 0, sizeof(tpm_daa_issuer->DAA_generic_q)); + return; +} + +/* TPM_DAAIssuer_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAAIssuer_Init() + After use, call TPM_DAAIssuer_Delete() to free memory +*/ + +TPM_RESULT TPM_DAAIssuer_Load(TPM_DAA_ISSUER *tpm_daa_issuer, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAIssuer_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DAA_ISSUER, stream, stream_size); + } + /* load DAA_digest_R0 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_issuer->DAA_digest_R0, stream, stream_size); + } + /* load DAA_digest_R1 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_issuer->DAA_digest_R1, stream, stream_size); + } + /* load DAA_digest_S0 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_issuer->DAA_digest_S0, stream, stream_size); + } + /* load DAA_digest_S1 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_issuer->DAA_digest_S1, stream, stream_size); + } + /* load DAA_digest_n */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_issuer->DAA_digest_n, stream, stream_size); + } + /* load DAA_digest_gamma */ + if (rc == 0) { + rc = TPM_Digest_Load (tpm_daa_issuer->DAA_digest_gamma, stream, stream_size); + } + /* load DAA_generic_q */ + if (rc == 0) { + rc = TPM_Loadn(tpm_daa_issuer->DAA_generic_q, sizeof(tpm_daa_issuer->DAA_generic_q), + stream, stream_size); + } + return rc; +} + +/* TPM_DAAIssuer_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAAIssuer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_ISSUER *tpm_daa_issuer) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAIssuer_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DAA_ISSUER); + } + /* store DAA_digest_R0 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_issuer->DAA_digest_R0); + } + /* store DAA_digest_R1 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_issuer->DAA_digest_R1); + } + /* store DAA_digest_S0 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_issuer->DAA_digest_S0); + } + /* store DAA_digest_S1 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_issuer->DAA_digest_S1); + } + /* store DAA_digest_n */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_issuer->DAA_digest_n); + } + /* store DAA_digest_gamma */ + if (rc == 0) { + rc = TPM_Digest_Store (sbuffer, tpm_daa_issuer->DAA_digest_gamma); + } + /* store DAA_generic_q */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + tpm_daa_issuer->DAA_generic_q, + sizeof(tpm_daa_issuer->DAA_generic_q)); + } + return rc; +} + +/* TPM_DAAIssuer_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAAIssuer_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAAIssuer_Delete(TPM_DAA_ISSUER *tpm_daa_issuer) +{ + printf(" TPM_DAAIssuer_Delete:\n"); + if (tpm_daa_issuer != NULL) { + TPM_DAAIssuer_Init(tpm_daa_issuer); + } + return; +} + +/* TPM_DAAIssuer_Copy() copies the source to the destination + +*/ + +void TPM_DAAIssuer_Copy(TPM_DAA_ISSUER *dest_daa_issuer, + TPM_DAA_ISSUER *src_daa_issuer) +{ + printf(" TPM_DAAIssuer_Copy:\n"); + + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_R0, src_daa_issuer->DAA_digest_R0); + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_R1, src_daa_issuer->DAA_digest_R1); + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_S0, src_daa_issuer->DAA_digest_S0); + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_S1, src_daa_issuer->DAA_digest_S1); + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_n, src_daa_issuer->DAA_digest_n); + TPM_Digest_Copy(dest_daa_issuer->DAA_digest_gamma, src_daa_issuer->DAA_digest_gamma); + memcpy(dest_daa_issuer->DAA_generic_q, src_daa_issuer->DAA_generic_q, + sizeof(src_daa_issuer->DAA_generic_q)); + return; +} + +/* + TPM_DAA_TPM +*/ + +/* TPM_DAATpm_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAATpm_Init(TPM_DAA_TPM *tpm_daa_tpm) +{ + printf(" TPM_DAATpm_Init:\n"); + TPM_Digest_Init(tpm_daa_tpm->DAA_digestIssuer); + TPM_Digest_Init(tpm_daa_tpm->DAA_digest_v0); + TPM_Digest_Init(tpm_daa_tpm->DAA_digest_v1); + TPM_Digest_Init(tpm_daa_tpm->DAA_rekey); + tpm_daa_tpm->DAA_count = 0; + return; +} + +/* TPM_DAATpm_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAATpm_Init() + After use, call TPM_DAATpm_Delete() to free memory +*/ + +TPM_RESULT TPM_DAATpm_Load(TPM_DAA_TPM *tpm_daa_tpm, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAATpm_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DAA_TPM, stream, stream_size); + } + /* load DAA_digestIssuer */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_tpm->DAA_digestIssuer, stream, stream_size); + } + /* load DAA_digest_v0 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_tpm->DAA_digest_v0, stream, stream_size); + } + /* load DAA_digest_v1 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_tpm->DAA_digest_v1, stream, stream_size); + } + /* load DAA_rekey */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_tpm->DAA_rekey, stream, stream_size); + } + /* load DAA_count */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_daa_tpm->DAA_count), stream, stream_size); + } + return rc; +} + +/* TPM_DAATpm_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAATpm_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_TPM *tpm_daa_tpm) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAATpm_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DAA_TPM); + } + /* store DAA_digestIssuer */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_tpm->DAA_digestIssuer); + } + /* store DAA_digest_v0 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_tpm->DAA_digest_v0); + } + /* store DAA_digest_v1 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_tpm->DAA_digest_v1); + } + /* store DAA_rekey */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_tpm->DAA_rekey); + } + /* store DAA_count */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_daa_tpm->DAA_count); + } + return rc; +} + +/* TPM_DAATpm_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAATpm_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAATpm_Delete(TPM_DAA_TPM *tpm_daa_tpm) +{ + printf(" TPM_DAATpm_Delete:\n"); + if (tpm_daa_tpm != NULL) { + TPM_DAATpm_Init(tpm_daa_tpm); + } + return; +} + +/* TPM_DAATpm_Copy() copies the source to the destination + +*/ + +void TPM_DAATpm_Copy(TPM_DAA_TPM *dest_daa_tpm, TPM_DAA_TPM *src_daa_tpm) +{ + printf(" TPM_DAATpm_Copy:\n"); + TPM_Digest_Copy(dest_daa_tpm->DAA_digestIssuer, src_daa_tpm->DAA_digestIssuer); + TPM_Digest_Copy(dest_daa_tpm->DAA_digest_v0, src_daa_tpm->DAA_digest_v0); + TPM_Digest_Copy(dest_daa_tpm->DAA_digest_v1, src_daa_tpm->DAA_digest_v1); + TPM_Digest_Copy(dest_daa_tpm->DAA_rekey, src_daa_tpm->DAA_rekey); + dest_daa_tpm->DAA_count = src_daa_tpm->DAA_count; + return; +} + +/* + TPM_DAA_CONTEXT +*/ + +/* TPM_DAAContext_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAAContext_Init(TPM_DAA_CONTEXT *tpm_daa_context) +{ + printf(" TPM_DAAContext_Init:\n"); + TPM_Digest_Init(tpm_daa_context->DAA_digestContext); + TPM_Digest_Init(tpm_daa_context->DAA_digest); + TPM_Nonce_Init(tpm_daa_context->DAA_contextSeed); + memset(tpm_daa_context->DAA_scratch, 0, sizeof(tpm_daa_context->DAA_scratch)); + tpm_daa_context->DAA_stage = 0; + tpm_daa_context->DAA_scratch_null = TRUE; + return; +} + +/* TPM_DAAContext_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAAContext_Init() + After use, call TPM_DAAContext_Delete() to free memory +*/ + +TPM_RESULT TPM_DAAContext_Load(TPM_DAA_CONTEXT *tpm_daa_context, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAContext_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DAA_CONTEXT, stream, stream_size); + } + /* load DAA_digestContext */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_context->DAA_digestContext, stream, stream_size); + } + /* load DAA_digest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_context->DAA_digest, stream, stream_size); + } + /* load DAA_contextSeed */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_daa_context->DAA_contextSeed, stream, stream_size); + } + /* load DAA_scratch */ + if (rc == 0) { + rc = TPM_Loadn(tpm_daa_context->DAA_scratch, sizeof(tpm_daa_context->DAA_scratch), + stream, stream_size); + } + /* load DAA_stage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_daa_context->DAA_stage), stream, stream_size); + } + /* load DAA_scratch_null */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_daa_context->DAA_scratch_null), stream, stream_size); + } + return rc; +} + +/* TPM_DAAContext_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAAContext_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_CONTEXT *tpm_daa_context) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAContext_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DAA_CONTEXT); + } + /* store DAA_digestContext */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_context->DAA_digestContext); + } + /* store DAA_digest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_context->DAA_digest); + } + /* store DAA_contextSeed */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_daa_context->DAA_contextSeed); + } + /* store DAA_scratch */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_daa_context->DAA_scratch, + sizeof(tpm_daa_context->DAA_scratch)); + } + /* store DAA_stage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_daa_context->DAA_stage), sizeof(BYTE)); + } + /* store DAA_scratch_null */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_daa_context->DAA_scratch_null), sizeof(TPM_BOOL)); + } + return rc; +} + +/* TPM_DAAContext_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAAContext_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAAContext_Delete(TPM_DAA_CONTEXT *tpm_daa_context) +{ + printf(" TPM_DAAContext_Delete:\n"); + if (tpm_daa_context != NULL) { + TPM_DAAContext_Init(tpm_daa_context); + } + return; +} + +/* TPM_DAAContext_Copy() copies the source to the destination + +*/ + +void TPM_DAAContext_Copy(TPM_DAA_CONTEXT *dest_daa_context, TPM_DAA_CONTEXT *src_daa_context) +{ + printf(" TPM_DAAContext_Copy:\n"); + TPM_Digest_Copy(dest_daa_context->DAA_digestContext, src_daa_context->DAA_digestContext); + TPM_Digest_Copy(dest_daa_context->DAA_digest, src_daa_context->DAA_digest); + TPM_Nonce_Copy(dest_daa_context->DAA_contextSeed, src_daa_context->DAA_contextSeed); + memcpy(dest_daa_context->DAA_scratch, src_daa_context->DAA_scratch, + sizeof(src_daa_context->DAA_scratch)); + dest_daa_context->DAA_stage = src_daa_context->DAA_stage; + dest_daa_context->DAA_scratch_null = src_daa_context->DAA_scratch_null; + return; +} + +/* + TPM_DAA_JOINDATA +*/ + +/* TPM_DAAJoindata_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAAJoindata_Init(TPM_DAA_JOINDATA *tpm_daa_joindata) +{ + printf(" TPM_DAAJoindata_Init:\n"); + memset(tpm_daa_joindata->DAA_join_u0, 0, sizeof(tpm_daa_joindata->DAA_join_u0)); + memset(tpm_daa_joindata->DAA_join_u1, 0, sizeof(tpm_daa_joindata->DAA_join_u1)); + TPM_Digest_Init(tpm_daa_joindata->DAA_digest_n0); + return; +} + +/* TPM_DAAJoindata_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAAJoindata_Init() + After use, call TPM_DAAJoindata_Delete() to free memory +*/ + +TPM_RESULT TPM_DAAJoindata_Load(TPM_DAA_JOINDATA *tpm_daa_joindata, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAJoindata_Load:\n"); + /* load DAA_join_u0 */ + if (rc == 0) { + rc = TPM_Loadn(tpm_daa_joindata->DAA_join_u0, + sizeof(tpm_daa_joindata->DAA_join_u0), + stream, stream_size); + } + /* load DAA_join_u1 */ + if (rc == 0) { + rc = TPM_Loadn(tpm_daa_joindata->DAA_join_u1, + sizeof(tpm_daa_joindata->DAA_join_u1), + stream, stream_size); + } + /* load DAA_digest_n0 */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_daa_joindata->DAA_digest_n0, stream, stream_size); + } + return rc; +} + +/* TPM_DAAJoindata_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAAJoindata_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_JOINDATA *tpm_daa_joindata) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAAJoindata_Store:\n"); + /* store DAA_join_u0 */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_daa_joindata->DAA_join_u0, + sizeof(tpm_daa_joindata->DAA_join_u0)); + } + /* store DAA_join_u1 */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_daa_joindata->DAA_join_u1, + sizeof(tpm_daa_joindata->DAA_join_u1)); + } + /* store DAA_digest_n0 */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_daa_joindata->DAA_digest_n0); + } + return rc; +} + +/* TPM_DAAJoindata_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAAJoindata_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAAJoindata_Delete(TPM_DAA_JOINDATA *tpm_daa_joindata) +{ + printf(" TPM_DAAJoindata_Delete:\n"); + if (tpm_daa_joindata != NULL) { + TPM_DAAJoindata_Init(tpm_daa_joindata); + } + return; +} + +/* TPM_DAAJoindata_Copy() copies the source to the destination + +*/ + +void TPM_DAAJoindata_Copy(TPM_DAA_JOINDATA *dest_daa_joindata, TPM_DAA_JOINDATA *src_daa_joindata) +{ + printf(" TPM_DAAJoindata_Copy:\n"); + memcpy(dest_daa_joindata->DAA_join_u0, src_daa_joindata->DAA_join_u0, + sizeof(src_daa_joindata->DAA_join_u0)); + memcpy(dest_daa_joindata->DAA_join_u1, src_daa_joindata->DAA_join_u1, + sizeof(src_daa_joindata->DAA_join_u1)); + TPM_Digest_Copy(dest_daa_joindata->DAA_digest_n0, src_daa_joindata->DAA_digest_n0); + return; +} + +/* + TPM_DAA_BLOB +*/ + +/* TPM_DAABlob_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAABlob_Init(TPM_DAA_BLOB *tpm_daa_blob) +{ + printf(" TPM_DAABlob_Init:\n"); + tpm_daa_blob->resourceType = 0; + memset(tpm_daa_blob->label, 0, sizeof(tpm_daa_blob->label)); + TPM_Digest_Init(tpm_daa_blob->blobIntegrity); + TPM_SizedBuffer_Init(&(tpm_daa_blob->additionalData)); + TPM_SizedBuffer_Init(&(tpm_daa_blob->sensitiveData)); + return; +} + +/* TPM_DAABlob_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAABlob_Init() + After use, call TPM_DAABlob_Delete() to free memory +*/ + +TPM_RESULT TPM_DAABlob_Load(TPM_DAA_BLOB *tpm_daa_blob, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAABlob_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DAA_BLOB, stream, stream_size); + } + /* load resourceType */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_daa_blob->resourceType), stream, stream_size); + } + /* load label */ + if (rc == 0) { + rc = TPM_Loadn(tpm_daa_blob->label, sizeof(tpm_daa_blob->label), stream, stream_size); + } + /* load blobIntegrity */ + if (rc == 0) { + TPM_Digest_Load(tpm_daa_blob->blobIntegrity, stream, stream_size); + } + /* load additionalData */ + if (rc == 0) { + TPM_SizedBuffer_Load(&(tpm_daa_blob->additionalData), stream, stream_size); + } + /* load sensitiveData */ + if (rc == 0) { + TPM_SizedBuffer_Load(&(tpm_daa_blob->sensitiveData), stream, stream_size); + } + return rc; +} + +/* TPM_DAABlob_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAABlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_BLOB *tpm_daa_blob) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAABlob_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DAA_BLOB); + } + /* store resourceType */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_daa_blob->resourceType); + } + /* store label */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_daa_blob->label, sizeof(tpm_daa_blob->label)); + } + /* store blobIntegrity */ + if (rc == 0) { + TPM_Digest_Store(sbuffer, tpm_daa_blob->blobIntegrity); + } + /* store additionalData */ + if (rc == 0) { + TPM_SizedBuffer_Store(sbuffer, &(tpm_daa_blob->additionalData)); + } + /* store sensitiveData */ + if (rc == 0) { + TPM_SizedBuffer_Store(sbuffer, &(tpm_daa_blob->sensitiveData)); + } + return rc; +} + +/* TPM_DAABlob_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAABlob_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAABlob_Delete(TPM_DAA_BLOB *tpm_daa_blob) +{ + printf(" TPM_DAABlob_Delete:\n"); + if (tpm_daa_blob != NULL) { + TPM_SizedBuffer_Delete(&(tpm_daa_blob->additionalData)); + TPM_SizedBuffer_Delete(&(tpm_daa_blob->sensitiveData)); + TPM_DAABlob_Init(tpm_daa_blob); + } + return; +} + +/* + TPM_DAA_SENSITIVE +*/ + +/* TPM_DAASensitive_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DAASensitive_Init(TPM_DAA_SENSITIVE *tpm_daa_sensitive) +{ + printf(" TPM_DAASensitive_Init:\n"); + TPM_SizedBuffer_Init(&(tpm_daa_sensitive->internalData)); + return; +} + +/* TPM_DAASensitive_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DAASensitive_Init() + After use, call TPM_DAASensitive_Delete() to free memory +*/ + +TPM_RESULT TPM_DAASensitive_Load(TPM_DAA_SENSITIVE *tpm_daa_sensitive, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAASensitive_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DAA_SENSITIVE, stream, stream_size); + } + /* load internalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_daa_sensitive->internalData), stream, stream_size); + } + return rc; +} + +/* TPM_DAASensitive_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DAASensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_SENSITIVE *tpm_daa_sensitive) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DAASensitive_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DAA_SENSITIVE); + } + /* store internalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_daa_sensitive->internalData)); + } + return rc; +} + +/* TPM_DAASensitive_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DAASensitive_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DAASensitive_Delete(TPM_DAA_SENSITIVE *tpm_daa_sensitive) +{ + printf(" TPM_DAASensitive_Delete:\n"); + if (tpm_daa_sensitive != NULL) { + TPM_SizedBuffer_Delete(&(tpm_daa_sensitive->internalData)); + TPM_DAASensitive_Init(tpm_daa_sensitive); + } + return; +} + + +/* + Processing Common Stage Functions +*/ + +TPM_RESULT TPM_DAAJoin_Stage00(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA **tpm_daa_session_data, + TPM_BOOL *daaHandleValid, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + uint32_t count; + TPM_HANDLE daaHandle = 0; /* no preassigned handle */ + + printf("TPM_DAAJoin_Stage00:\n"); + if (rc == 0) { + /* a. Determine that sufficient resources are available to perform a TPM_DAA_Join. */ + /* i. The TPM MUST support sufficient resources to perform one (1) + TPM_DAA_Join/TPM_DAA_Sign. The TPM MAY support additional TPM_DAA_Join/TPM_DAA_Sign + sessions. */ + /* ii. The TPM may share internal resources between the DAA operations and other variable + resource requirements: */ + /* iii. If there are insufficient resources within the stored key pool (and one or more keys + need to be removed to permit the DAA operation to execute) return TPM_NOSPACE */ + /* iv. If there are insufficient resources within the stored session pool (and one or more + authorization or transport sessions need to be removed to permit the DAA operation to + execute), return TPM_RESOURCES. */ + rc = TPM_DaaSessions_GetNewHandle(tpm_daa_session_data, + &daaHandle, /* output */ + daaHandleValid, /* output */ + tpm_state->tpm_stclear_data.daaSessions); /* array */ + } + if (rc == 0) { + /* b. Set all fields in DAA_issuerSettings = NULL */ + /* c. set all fields in DAA_tpmSpecific = NULL */ + /* d. set all fields in DAA_session = NULL */ + /* e. Set all fields in DAA_joinSession = NULL */ + /* NOTE Done by TPM_DaaSessions_GetNewHandle() */ + /* f. Verify that sizeOf(inputData0) == sizeof(DAA_tpmSpecific -> DAA_count) and return + error TPM_DAA_INPUT_DATA0 on mismatch */ + if (inputData0->size != sizeof((*tpm_daa_session_data)->DAA_tpmSpecific.DAA_count)) { + printf("TPM_DAAJoin_Stage00: Error, inputData0 size %u should be %lu\n", + inputData0->size, + (unsigned long)sizeof((*tpm_daa_session_data)->DAA_tpmSpecific.DAA_count)); + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + /* g. Verify that inputData0 > 0, and return error TPM_DAA_INPUT_DATA0 on mismatch */ + stream = inputData0->buffer; + stream_size = inputData0->size; + rc = TPM_Load32(&count, &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + printf("TPM_DAAJoin_Stage00: count %u\n", count); + if (count == 0) { + printf("TPM_DAAJoin_Stage00: Error, count is zero\n"); + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + /* h. Set DAA_tpmSpecific -> DAA_count = inputData0 */ + (*tpm_daa_session_data)->DAA_tpmSpecific.DAA_count = count; + /* i. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + rc = TPM_DAADigestContext_GenerateDigestJoin + ((*tpm_daa_session_data)->DAA_session.DAA_digestContext, + (*tpm_daa_session_data)); + } + if (rc == 0) { + /* j. set DAA_session -> DAA_stage = 1 */ + (*tpm_daa_session_data)->DAA_session.DAA_stage = 1; + /* k. Assign session handle for TPM_DAA_Join */ + /* NOTE Done by TPM_DaaSessions_GetNewHandle() */ + printf("TPM_DAAJoin_Stage00: handle %08x\n", (*tpm_daa_session_data)->daaHandle); + /* l. set outputData = new session handle */ + /* i. The handle in outputData is included the output HMAC. */ + rc = TPM_SizedBuffer_Append32(outputData, (*tpm_daa_session_data)->daaHandle); + } + /* m. return TPM_SUCCESS */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage01(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + TPM_DIGEST signedDataDigest; + + printf("TPM_DAAJoin_Stage01:\n"); + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==1. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that sizeOf(inputData0) == DAA_SIZE_issuerModulus and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + if (inputData0->size != DAA_SIZE_issuerModulus) { + printf("TPM_DAAJoin_Stage01: Error, bad input0 size %u\n", inputData0->size); + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + /* d. If DAA_session -> DAA_scratch == NULL: */ + if (tpm_daa_session_data->DAA_session.DAA_scratch_null) { + printf("TPM_DAAJoin_Stage01: DAA_scratch null\n"); + if (rc == 0) { + /* i. Set DAA_session -> DAA_scratch = inputData0 */ + tpm_daa_session_data->DAA_session.DAA_scratch_null = FALSE; + memcpy(tpm_daa_session_data->DAA_session.DAA_scratch, + inputData0->buffer, DAA_SIZE_issuerModulus); + /* ii. set DAA_joinSession -> DAA_digest_n0 = SHA-1(DAA_session -> DAA_scratch) */ + rc = + TPM_SHA1(tpm_daa_session_data->DAA_joinSession.DAA_digest_n0, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_daa_session_data->DAA_session.DAA_scratch, + 0, NULL); + } + /* iii. set DAA_tpmSpecific -> DAA_rekey = SHA-1(tpmDAASeed || DAA_joinSession -> + DAA_digest_n0) */ + if (rc == 0) { + rc = TPM_SHA1(tpm_daa_session_data->DAA_tpmSpecific.DAA_rekey, + TPM_NONCE_SIZE, tpm_state->tpm_permanent_data.tpmDAASeed, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_joinSession.DAA_digest_n0, + 0, NULL); + } + } + /* e. Else (If DAA_session -> DAA_scratch != NULL): */ + else { + printf("TPM_DAAJoin_Stage01: DAA_scratch not null\n"); + /* i. Set signedData = inputData0 */ + /* ii. Verify that sizeOf(inputData1) == DAA_SIZE_issuerModulus and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + if (inputData1->size != DAA_SIZE_issuerModulus) { + printf("TPM_DAAJoin_Stage01: Error, bad input1 size %u\n", inputData1->size); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* iii. Set signatureValue = inputData1 */ + /* iv. Use the RSA key == [DAA_session -> DAA_scratch] to verify that signatureValue is + a signature on signedData using TPM_SS_RSASSAPKCS1v15_SHA1 (RSA PKCS1.5 with SHA-1), + and return error TPM_DAA_ISSUER_VALIDITY on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage01: Digesting signedData\n"); + rc = TPM_SHA1(signedDataDigest, + inputData0->size, inputData0->buffer, + 0, NULL); + } + if (rc == 0) { + printf("TPM_DAAJoin_Stage01: Verifying signature\n"); + rc = TPM_RSAVerify(inputData1->buffer, /* signature */ + inputData1->size, + TPM_SS_RSASSAPKCS1v15_INFO, /* signature scheme */ + signedDataDigest, /* signed data */ + TPM_DIGEST_SIZE, + tpm_daa_session_data->DAA_session.DAA_scratch, /* pub modulus */ + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_default_rsa_exponent, /* public exponent */ + 3); + if (rc != 0) { + printf("TPM_DAAJoin_Stage01: Error, bad signature\n"); + rc = TPM_DAA_ISSUER_VALIDITY; + } + } + /* v. Set DAA_session -> DAA_scratch = signedData */ + if (rc == 0) { + memcpy(tpm_daa_session_data->DAA_session.DAA_scratch, + inputData0->buffer, inputData1->size); + } + } + } + if (rc == 0) { + /* f. Decrement DAA_tpmSpecific -> DAA_count by 1 (unity) */ + tpm_daa_session_data->DAA_tpmSpecific.DAA_count--; + /* g. If DAA_tpmSpecific -> DAA_count ==0: */ + if (tpm_daa_session_data->DAA_tpmSpecific.DAA_count == 0) { + /* h. increment DAA_session -> DAA_Stage by 1 */ + tpm_daa_session_data->DAA_session.DAA_stage++; + } + /* i. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + rc = TPM_DAADigestContext_GenerateDigestJoin + (tpm_daa_session_data->DAA_session.DAA_digestContext, tpm_daa_session_data); + } + /* j. set outputData = NULL */ + /* NOTE Done by caller */ + /* k. return TPM_SUCCESS */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage02(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + TPM_STORE_BUFFER signedDataSbuffer; + TPM_DIGEST signedDataDigest; + + printf("TPM_DAAJoin_Stage02:\n"); + outputData = outputData; /* not used */ + tpm_state = tpm_state; /* not used */ + TPM_Sbuffer_Init(&signedDataSbuffer); /* freed @1*/ + /* a. Verify that DAA_session ->DAA_stage==2. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that sizeOf(inputData0) == sizeOf(TPM_DAA_ISSUER) and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + /* NOTE cannot use sizeof because packing may not be exact */ + /* d. Set DAA_issuerSettings = inputData0. Verify that all fields in DAA_issuerSettings are + present and return error TPM_DAA_INPUT_DATA0 if not. */ + if (rc == 0) { + stream = inputData0->buffer; + stream_size = inputData0->size; + rc = TPM_DAAIssuer_Load(&(tpm_daa_session_data->DAA_issuerSettings), &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_DAAJoin_Stage02: Error, bad input0 size %u\n", inputData0->size); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Verify that sizeOf(inputData1) == DAA_SIZE_issuerModulus and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + if (inputData1->size != DAA_SIZE_issuerModulus) { + printf("TPM_DAAJoin_Stage02: Error, bad input1 size %u\n", inputData1->size); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* f. Set signatureValue = inputData1 */ + /* g. Set signedData = (DAA_joinSession -> DAA_digest_n0 || DAA_issuerSettings) */ + if (rc == 0) { + rc = TPM_Digest_Store(&signedDataSbuffer, + tpm_daa_session_data->DAA_joinSession.DAA_digest_n0); + } + if (rc == 0) { + rc = TPM_DAAIssuer_Store(&signedDataSbuffer, &(tpm_daa_session_data->DAA_issuerSettings)); + } + /* h. Use the RSA key [DAA_session -> DAA_scratch] to verify that signatureValue is a */ + /* signature on signedData using TPM_SS_RSASSAPKCS1v15_SHA1 (RSA PKCS1.5 with SHA-1), and return + error TPM_DAA_ISSUER_VALIDITY on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage02: Digesting signedData\n"); + rc = TPM_SHA1Sbuffer(signedDataDigest, &signedDataSbuffer); + } + if (rc == 0) { + printf("TPM_DAAJoin_Stage02: Verifying signature\n"); + rc = TPM_RSAVerify(inputData1->buffer, /* signature */ + inputData1->size, + TPM_SS_RSASSAPKCS1v15_INFO, /* signature scheme */ + signedDataDigest, /* signed data */ + TPM_DIGEST_SIZE, + tpm_daa_session_data->DAA_session.DAA_scratch, /* public modulus */ + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_default_rsa_exponent, /* public exponent */ + 3); + if (rc != 0) { + printf("TPM_DAAJoin_Stage02: Error, bad signature\n"); + rc = TPM_DAA_ISSUER_VALIDITY; + } + } + /* i. Set DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) */ + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(tpm_daa_session_data->DAA_tpmSpecific.DAA_digestIssuer, + &(tpm_daa_session_data->DAA_issuerSettings), + (TPM_STORE_FUNCTION_T)TPM_DAAIssuer_Store); + } + /* j. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + if (rc == 0) { + rc = TPM_DAADigestContext_GenerateDigestJoin + (tpm_daa_session_data->DAA_session.DAA_digestContext, tpm_daa_session_data); + } + if (rc == 0) { + /* k. Set DAA_session -> DAA_scratch = NULL */ + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + /* l. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + } + /* m. return TPM_SUCCESS */ + TPM_Sbuffer_Delete(&signedDataSbuffer); /* @1*/ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage03(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + + printf("TPM_DAAJoin_Stage03:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==3. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify that sizeOf(inputData0) == sizeOf(DAA_tpmSpecific -> DAA_count) and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + if (inputData0->size != sizeof(tpm_daa_session_data->DAA_tpmSpecific.DAA_count)) { + printf("TPM_DAAJoin_Stage03: Error, inputData0 size %u should be %lu\n", + inputData0->size, + (unsigned long)sizeof(tpm_daa_session_data->DAA_tpmSpecific.DAA_count)); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Set DAA_tpmSpecific -> DAA_count = inputData0 */ + if (rc == 0) { + stream = inputData0->buffer; + stream_size = inputData0->size; + rc = TPM_Load32(&(tpm_daa_session_data->DAA_tpmSpecific.DAA_count), &stream, &stream_size); + } + /* f. Obtain random data from the RNG and store it as DAA_joinSession -> DAA_join_u0 */ + if (rc == 0) { + rc = TPM_Random(tpm_daa_session_data->DAA_joinSession.DAA_join_u0, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u0)); + } + /* g. Obtain random data from the RNG and store it as DAA_joinSession -> DAA_join_u1 */ + if (rc == 0) { + rc = TPM_Random(tpm_daa_session_data->DAA_joinSession.DAA_join_u1, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u1)); + } + /* h. set outputData = NULL */ + /* NOTE Done by caller */ + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + if (rc == 0) { + rc = TPM_DAADigestContext_GenerateDigestJoin + (tpm_daa_session_data->DAA_session.DAA_digestContext, tpm_daa_session_data); + } + /* k. return TPM_SUCCESS */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage04(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM xBignum = NULL; /* freed @1 */ + TPM_BIGNUM nBignum = NULL; /* freed @2 */ + TPM_BIGNUM fBignum = NULL; /* freed @3 */ + TPM_BIGNUM rBignum = NULL; /* freed @4 */ + + printf("TPM_DAAJoin_Stage04:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==4. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_R0 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_R0) == DAA_issuerSettings -> DAA_digest_R0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage04: Checking DAA_generic_R0\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_R0, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_R0 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage04: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Set X = DAA_generic_R0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage04: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* i. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage04: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* j. 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 */ + if (rc == 0) { + rc = TPM_ComputeF(&fBignum, tpm_daa_session_data); /* freed @3 */ + } + /* k. Set f0 = f mod 2^DAA_power0 (erase all but the lowest DAA_power0 bits of f) */ + if (rc == 0) { + rc = TPM_BN_mask_bits(fBignum, DAA_power0); /* f becomes f0 */ + } + /* l. Set DAA_session -> DAA_scratch = (X^f0) mod n */ + if (rc == 0) { + rc = TPM_ComputeAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + &rBignum, /* R */ + xBignum, /* A */ + fBignum, /* P */ + nBignum); /* n */ + } + /* m. set outputData = NULL */ + /* NOTE Done by caller */ + /* n. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* o. return TPM_SUCCESS */ + TPM_BN_free(xBignum); /* @1 */ + TPM_BN_free(nBignum); /* @2 */ + TPM_BN_free(fBignum); /* @3 */ + TPM_BN_free(rBignum); /* @4 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage05(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM xBignum = NULL; /* freed @1 */ + TPM_BIGNUM nBignum = NULL; /* freed @2 */ + TPM_BIGNUM fBignum = NULL; /* freed @3 */ + TPM_BIGNUM f1Bignum = NULL; /* freed @4 */ + TPM_BIGNUM zBignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage05:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==5. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_R1 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_R1) == DAA_issuerSettings -> DAA_digest_R1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage05: Checking DAA_generic_R1\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_R1, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_R1 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage05: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Set X = DAA_generic_R1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage05: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* i. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage05: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* j. 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. */ + if (rc == 0) { + rc = TPM_ComputeF(&fBignum, tpm_daa_session_data); /* freed @3 */ + } + /* k. Shift f right by DAA_power0 bits (discard the lowest DAA_power0 bits) and label the result + f1 */ + if (rc == 0) { + rc = TPM_BN_rshift(&f1Bignum, fBignum, DAA_power0); /* f becomes f1 */ + } + /* l. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage05: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* m. Set DAA_session -> DAA_scratch = Z*(X^f1) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + f1Bignum, /* P */ + nBignum); /* N */ + } + /* n. set outputData = NULL */ + /* NOTE Done by caller */ + /* o. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* p. return TPM_SUCCESS */ + TPM_BN_free(xBignum); /* @1 */ + TPM_BN_free(nBignum); /* @2 */ + TPM_BN_free(fBignum); /* @3 */ + TPM_BN_free(f1Bignum); /* @4 */ + TPM_BN_free(zBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage06(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM xBignum = NULL; /* freed @1 */ + TPM_BIGNUM nBignum = NULL; /* freed @2 */ + TPM_BIGNUM zBignum = NULL; /* freed @3 */ + TPM_BIGNUM yBignum = NULL; /* freed @4 */ + + printf("TPM_DAAJoin_Stage06:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==6. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_S0 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_S0) == DAA_issuerSettings -> DAA_digest_S0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Checking DAA_generic_S0\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_S0, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_S0 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Set X = DAA_generic_S0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* i. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* j. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* k. Set Y = DAA_joinSession -> DAA_join_u0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage06: Creating Y\n"); + rc = TPM_bin2bn(&yBignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u0, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u0)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. set outputData = NULL */ + /* NOTE Done by caller */ + /* n. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* o. return TPM_SUCCESS */ + TPM_BN_free(xBignum); /* @1 */ + TPM_BN_free(nBignum); /* @2 */ + TPM_BN_free(zBignum); /* @3 */ + TPM_BN_free(yBignum); /* @4 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage07(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + uint32_t nCount; /* DAA_count in nbo */ + TPM_BIGNUM xBignum = NULL; /* freed @1 */ + TPM_BIGNUM nBignum = NULL; /* freed @2 */ + TPM_BIGNUM yBignum = NULL; /* freed @3 */ + TPM_BIGNUM zBignum = NULL; /* freed @4 */ + + printf("TPM_DAAJoin_Stage07:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==7. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_S1 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_S1) == DAA_issuerSettings -> DAA_digest_S1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Checking DAA_generic_S1\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_S1, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_S1 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Set X = DAA_generic_S1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* i. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* j. Set Y = DAA_joinSession -> DAA_join_u1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Creating Y\n"); + rc = TPM_bin2bn(&yBignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u1, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u1)); + } + /* k. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. Set DAA_session -> DAA_digest to the SHA-1 (DAA_session -> DAA_scratch || DAA_tpmSpecific + -> DAA_count || DAA_joinSession -> DAA_digest_n0) */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage07: Computing DAA_digest\n"); + nCount = htonl(tpm_daa_session_data->DAA_tpmSpecific.DAA_count); + rc = TPM_SHA1(tpm_daa_session_data->DAA_session.DAA_digest, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(uint32_t), &nCount, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_joinSession.DAA_digest_n0, + 0, NULL); + } + /* n. set outputData = DAA_session -> DAA_scratch */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_daa_session_data->DAA_session.DAA_scratch); + } + /* o. set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* p. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* q. return TPM_SUCCESS */ + TPM_BN_free(xBignum); /* @1 */ + TPM_BN_free(nBignum); /* @2 */ + TPM_BN_free(yBignum); /* @3 */ + TPM_BN_free(zBignum); /* @4 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage08(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *NE = NULL; /* freed @1 */ + uint32_t NELength; + TPM_DIGEST outDigest; + + printf("TPM_DAAJoin_Stage08:\n"); + /* a. Verify that DAA_session ->DAA_stage==8. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify inputSize0 == DAA_SIZE_NE and return error TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + if (inputData0->size != DAA_SIZE_NE) { + printf("TPM_DAAJoin_Stage08: Error, inputData0 size %u should be %u\n", + inputData0->size, DAA_SIZE_NE); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Set NE = decrypt(inputData0, privEK) */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptMalloc(&NE, /* decrypted data */ + &NELength, /* length of data put into decrypt_data */ + inputData0->buffer, /* encrypted data */ + inputData0->size, /* encrypted data size */ + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* f. set outputData = SHA-1(DAA_session -> DAA_digest || NE) */ + if (rc == 0) { + rc = TPM_SHA1(outDigest, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_session.DAA_digest, + NELength, NE, + 0, NULL); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, TPM_DIGEST_SIZE, outDigest); + } + /* g. set DAA_session -> DAA_digest = NULL */ + if (rc == 0) { + TPM_Digest_Init(tpm_daa_session_data->DAA_session.DAA_digest); + } + /* h. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* i. return TPM_SUCCESS */ + free(NE); /* @1 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage09_Sign_Stage2(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *Y = NULL; /* freed @1 */ + TPM_BIGNUM yBignum = NULL; /* freed @2 */ + TPM_BIGNUM xBignum = NULL; /* freed @3 */ + TPM_BIGNUM nBignum = NULL; /* freed @4 */ + TPM_BIGNUM rBignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage09_Sign_Stage2:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==9. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific ||DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_R0 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_R0) == DAA_issuerSettings -> DAA_digest_R0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage09_Sign_Stage2: Checking DAA_generic_R0\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_R0, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_R0 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage09_Sign_Stage2: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Obtain random data from the RNG and store it as DAA_session -> DAA_contextSeed */ + if (rc == 0) { + rc = TPM_Nonce_Generate(tpm_daa_session_data->DAA_session.DAA_contextSeed); + } + /* i. Obtain DAA_SIZE_r0 bytes using the MGF1 function and label them Y. "r0" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage09_Sign_Stage2: Creating Y\n"); + rc = TPM_MGF1_GenerateArray(&Y, /* returned MGF1 array */ + DAA_SIZE_r0, /* size of Y */ + /* length of the entire seed */ + sizeof("r0") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r0") -1, "r0", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&yBignum, Y, DAA_SIZE_r0); + } + /* j. Set X = DAA_generic_R0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage09_Sign_Stage2: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* k. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage09_Sign_Stage2: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* l. Set DAA_session -> DAA_scratch = (X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + &rBignum, /* R */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* n */ + + } + /* m. set outputData = NULL */ + /* NOTE Done by caller */ + /* n. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* o. return TPM_SUCCESS */ + free(Y); /* @1 */ + TPM_BN_free(yBignum); /* @2 */ + TPM_BN_free(xBignum); /* @3 */ + TPM_BN_free(nBignum); /* @4 */ + TPM_BN_free(rBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage10_Sign_Stage3(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *Y= NULL; /* freed @1 */ + TPM_BIGNUM xBignum = NULL; /* freed @2 */ + TPM_BIGNUM nBignum = NULL; /* freed @3 */ + TPM_BIGNUM zBignum = NULL; /* freed @4 */ + TPM_BIGNUM yBignum = NULL; /* freed @5*/ + + printf("TPM_DAAJoin_Stage10_Sign_Stage3:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==10. Return TPM_DAA_STAGE and flush handle on mismatch + h */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_R1 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_R1) == DAA_issuerSettings -> DAA_digest_R1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Checking DAA_generic_R1\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_R1, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_R1 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Obtain DAA_SIZE_r1 bytes using the MGF1 function and label them Y. "r1" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Creating Y\n"); + rc = TPM_MGF1_GenerateArray(&Y, /* returned MGF1 array */ + DAA_SIZE_r1, /* size of Y */ + /* length of the entire seed */ + sizeof("r1") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r1") -1, "r1", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&yBignum, Y, DAA_SIZE_r1); + } + /* i. Set X = DAA_generic_R1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* j. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* k. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage10_Sign_Stage3: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. set outputData = NULL */ + /* NOTE Done by caller */ + /* n. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* o. return TPM_SUCCESS */ + free(Y); /* @1 */ + TPM_BN_free(xBignum); /* @2 */ + TPM_BN_free(nBignum); /* @3 */ + TPM_BN_free(zBignum); /* @4 */ + TPM_BN_free(yBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage11_Sign_Stage4(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *Y= NULL; /* freed @1 */ + TPM_BIGNUM yBignum = NULL; /* freed @2 */ + TPM_BIGNUM xBignum = NULL; /* freed @3 */ + TPM_BIGNUM nBignum = NULL; /* freed @4 */ + TPM_BIGNUM zBignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage11_Sign_Stage4:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==11. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_S0 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_S0) == DAA_issuerSettings -> DAA_digest_S0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Checking DAA_generic_S0\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_S0, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_S0 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Obtain DAA_SIZE_r2 bytes using the MGF1 function and label them Y. "r2" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Creating Y\n"); + rc = TPM_MGF1_GenerateArray(&Y, /* returned MGF1 array */ + DAA_SIZE_r2, /* size of Y */ + /* length of the entire seed */ + sizeof("r2") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r2") -1, "r2", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&yBignum, Y, DAA_SIZE_r2); + } + /* i. Set X = DAA_generic_S0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* j. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* k. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage11_Sign_Stage4: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. set outputData = NULL */ + /* NOTE Done by caller */ + /* n. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* o. return TPM_SUCCESS */ + free(Y); /* @1 */ + TPM_BN_free(yBignum); /* @2 */ + TPM_BN_free(xBignum); /* @3 */ + TPM_BN_free(nBignum); /* @4 */ + TPM_BN_free(zBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage12(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *Y = NULL; /* freed @1 */ + TPM_BIGNUM yBignum = NULL; /* freed @2 */ + TPM_BIGNUM xBignum = NULL; /* freed @3 */ + TPM_BIGNUM nBignum = NULL; /* freed @4 */ + TPM_BIGNUM zBignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage12:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==12. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings ) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_S1 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_S1) == DAA_issuerSettings -> DAA_digest_S1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Checking DAA_generic_S1\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_S1, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_S1 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Obtain DAA_SIZE_r3 bytes using the MGF1 function and label them Y. "r3" || DAA_session -> + DAA_contextSeed) is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Creating Y\n"); + rc = TPM_MGF1_GenerateArray(&Y, /* returned MGF1 array */ + DAA_SIZE_r3, /* size of Y */ + /* length of the entire seed */ + sizeof("r3") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r3") -1, "r3", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&yBignum, Y, DAA_SIZE_r3); + } + /* i. Set X = DAA_generic_S1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* j. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* k. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage12: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. set outputData = DAA_session -> DAA_scratch */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_daa_session_data->DAA_session.DAA_scratch); + } + /* n. Set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* o. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* p. return TPM_SUCCESS */ + free(Y); /* @1 */ + TPM_BN_free(yBignum); /* @2 */ + TPM_BN_free(xBignum); /* @3 */ + TPM_BN_free(nBignum); /* @4 */ + TPM_BN_free(zBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage13_Sign_Stage6(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM wBignum = NULL; /* freed @1 */ + TPM_BIGNUM qBignum = NULL; /* freed @2 */ + TPM_BIGNUM nBignum = NULL; /* freed @3 */ + TPM_BIGNUM w1Bignum = NULL; /* freed @4 */ + + printf("TPM_DAAJoin_Stage13_Sign_Stage6:\n"); + tpm_state = tpm_state; /* not used */ + outputData = outputData; /* not used */ + /* a. Verify that DAA_session->DAA_stage==13. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_gamma = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_gamma) == DAA_issuerSettings -> DAA_digest_gamma and return + error TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Checking DAA_generic_gamma\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_gamma, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_gamma */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Verify that inputSize1 == DAA_SIZE_w and return error TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + if (inputData1->size != DAA_SIZE_w) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Error, inputData1 size %u should be %u\n", + inputData0->size, DAA_SIZE_w); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* g. Set w = inputData1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Creating w\n"); + rc = TPM_bin2bn(&wBignum, inputData1->buffer, inputData1->size); + } + /* FIXME added Set q = DAA_issuerSettings -> DAA_generic_q */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Creating q from DAA_generic_q\n"); + rc = TPM_bin2bn(&qBignum, + tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q, + sizeof(tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q)); + } + /* FIXME Set n = DAA_generic_gamma */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData0->buffer, inputData0->size); + } + /* h. Set w1 = w^( DAA_issuerSettings -> DAA_generic_q) mod (DAA_generic_gamma) */ + /* FIXME w1 = (w^q) mod n */ + if (rc == 0) { + rc = TPM_ComputeAexpPmodn(NULL, + 0, + &w1Bignum, /* R */ + wBignum, /* A */ + qBignum, /* P */ + nBignum); /* n */ + } + /* i. If w1 != 1 (unity), return error TPM_DAA_WRONG_W */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage13_Sign_Stage6: Testing w1\n"); + rc = TPM_BN_is_one(w1Bignum); + } + /* j. Set DAA_session -> DAA_scratch = w */ + if (rc == 0) { + rc = TPM_ComputeDAAScratch(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + wBignum); + } + /* k. set outputData = NULL */ + /* NOTE Done by caller */ + /* l. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* m. return TPM_SUCCESS. */ + TPM_BN_free(wBignum); /* @1 */ + TPM_BN_free(qBignum); /* @2 */ + TPM_BN_free(nBignum); /* @3 */ + TPM_BN_free(w1Bignum); /* @4 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage14_Sign_Stage7(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM fBignum = NULL; /* freed @1 */ + TPM_BIGNUM wBignum = NULL; /* freed @2 */ + TPM_BIGNUM nBignum = NULL; /* freed @3 */ + TPM_BIGNUM eBignum = NULL; /* freed @4 */ + + unsigned int numBytes; /* for debug */ + + printf("TPM_DAAJoin_Stage14_Sign_Stage7:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==14. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings ) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_gamma = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_gamma) == DAA_issuerSettings -> DAA_digest_gamma and return + error TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage14_Sign_Stage7: Checking DAA_generic_gamma\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_gamma, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_gamma */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. 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. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage14_Sign_Stage7: Creating f\n"); + rc = TPM_ComputeF(&fBignum, tpm_daa_session_data); /* freed @1 */ + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, fBignum); + printf("TPM_DAAJoin_Stage14_Sign_Stage7: f. f size %u\n", numBytes); + } + /* FIXME Set W = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage14_Sign_Stage7: Creating W\n"); + rc = TPM_bin2bn(&wBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, wBignum); + printf("TPM_DAAJoin_Stage14_Sign_Stage7: W size %u\n", numBytes); + } + /* FIXME Set n = DAA_generic_gamma */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage14_Sign_Stage7: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData0->buffer, inputData0->size); + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, nBignum); + printf("TPM_DAAJoin_Stage14_Sign_Stage7: n size %u\n", numBytes); + } + /* g. Set E = ((DAA_session -> DAA_scratch)^f) mod (DAA_generic_gamma). */ + /* FIXME E = (w^f) mod n */ + if (rc == 0) { + rc = TPM_ComputeAexpPmodn(NULL, + 0, + &eBignum, /* R */ + wBignum, /* A */ + fBignum, /* P */ + nBignum); /* n */ + } + /* h. Set outputData = E */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage14_Sign_Stage7: Output E\n"); + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + eBignum, 0); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS. */ + TPM_BN_free(fBignum); /* @1 */ + TPM_BN_free(wBignum); /* @2 */ + TPM_BN_free(nBignum); /* @3 */ + TPM_BN_free(eBignum); /* @4 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage15_Sign_Stage8(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *r0 = NULL; /* freed @1 */ + unsigned char *r1 = NULL; /* freed @2 */ + TPM_BIGNUM r0Bignum = NULL; /* freed @3 */ + TPM_BIGNUM r1Bignum = NULL; /* freed @4 */ + TPM_BIGNUM r1sBignum = NULL; /* freed @5 */ + TPM_BIGNUM rBignum = NULL; /* freed @6 */ + TPM_BIGNUM e1Bignum = NULL; /* freed @7 */ + TPM_BIGNUM qBignum = NULL; /* freed @8 */ + TPM_BIGNUM nBignum = NULL; /* freed @9 */ + TPM_BIGNUM wBignum = NULL; /* freed @10 */ + + printf("TPM_DAAJoin_Stage15_Sign_Stage8:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==15. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_gamma = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_gamma) == DAA_issuerSettings -> DAA_digest_gamma and return + error TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Checking DAA_generic_gamma\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_gamma, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_gamma */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Obtain DAA_SIZE_r0 bytes using the MGF1 function and label them r0. "r0" || DAA_session + -> DAA_contextSeed) is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Creating r0\n"); + rc = TPM_MGF1_GenerateArray(&r0, /* returned MGF1 array */ + DAA_SIZE_r0, /* size of Y */ + /* length of the entire seed */ + sizeof("r0") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r0") -1, "r0", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r0Bignum, r0, DAA_SIZE_r0); + } + /* g. Obtain DAA_SIZE_r1 bytes using the MGF1 function and label them r1. "r1" || DAA_session + -> DAA_contextSeedis the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Creating r1\n"); + rc = TPM_MGF1_GenerateArray(&r1, /* returned MGF1 array */ + DAA_SIZE_r1, /* size of Y */ + /* length of the entire seed */ + sizeof("r1") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r1") -1, "r1", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r1Bignum, r1, DAA_SIZE_r1); + } + /* FIXME Set q = DAA_generic_q */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Creating n from DAA_generic_q\n"); + rc = TPM_bin2bn(&qBignum, + tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q, + sizeof(tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q)); + } + /* h. set r = r0 + 2^DAA_power0 * r1 mod (DAA_issuerSettings -> DAA_generic_q). */ + /* FIXME added parentheses + h. set r = (r0 + (2^DAA_power0 * r1)) mod (DAA_issuerSettings -> DAA_generic_q). + h. set r = (r0 + (2^DAA_power0 * r1)) mod q */ + if (rc == 0) { + rc = TPM_BN_lshift(&r1sBignum, /* result, freed @5 */ + r1Bignum, /* input */ + DAA_power0); /* n */ + } + if (rc == 0) { + rc = TPM_ComputeApBmodn(&rBignum, /* result, freed @6 */ + r0Bignum, /* A */ + r1sBignum, /* B */ + qBignum); /* n */ + } + /* FIXME Set n = DAA_generic_gamma */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Creating n1 from DAA_generic_gamma\n"); + rc = TPM_bin2bn(&nBignum, inputData0->buffer, inputData0->size); + } + /* FIXME Set w = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage15_Sign_Stage8: Creating w from DAA_scratch\n"); + rc = TPM_bin2bn(&wBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* i. set E1 = ((DAA_session -> DAA_scratch)^r) mod (DAA_generic_gamma). */ + /* (w ^ r) mod n */ + if (rc == 0) { + rc = TPM_ComputeAexpPmodn(NULL, + 0, + &e1Bignum, /* R */ + wBignum, /* A */ + rBignum, /* P */ + nBignum); /* n */ + } + /* j. Set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* k. Set outputData = E1 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + e1Bignum, 0); + } + /* l. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* m. return TPM_SUCCESS. */ + free(r0); /* @1 */ + free(r1); /* @2 */ + TPM_BN_free(r0Bignum); /* @3 */ + TPM_BN_free(r1Bignum); /* @4 */ + TPM_BN_free(r1sBignum); /* @5 */ + TPM_BN_free(rBignum); /* @6 */ + TPM_BN_free(e1Bignum); /* @7 */ + TPM_BN_free(qBignum); /* @8 */ + TPM_BN_free(nBignum); /* @9 */ + TPM_BN_free(wBignum); /* @10 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage16_Sign_Stage9(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *nt = NULL; /* freed @1 */ + + printf("TPM_DAAJoin_Stage16_Sign_Stage9:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==16. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify that inputSize0 == sizeOf(TPM_DIGEST) and return error TPM_DAA_INPUT_DATA0 on + mismatch */ + if (rc == 0) { + if (inputData0->size != TPM_DIGEST_SIZE) { + printf("TPM_DAAJoin_Stage16_Sign_Stage9: Error, inputData0 size %u should be %u\n", + inputData0->size, TPM_DIGEST_SIZE); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Set DAA_session -> DAA_digest = inputData0 */ + if (rc == 0) { + /* e. Set DAA_session -> DAA_digest = inputData0 */ + /* NOTE: This step is unnecessary, since the value is overridden in g. */ + /* f. Obtain DAA_SIZE_NT bytes from the RNG and label them NT */ + rc = TPM_Malloc(&nt, DAA_SIZE_NT); + } + if (rc == 0) { + rc = TPM_Random(nt, DAA_SIZE_NT); + } + /* g. Set DAA_session -> DAA_digest to the SHA-1 ( DAA_session -> DAA_digest || NT ) */ + if (rc == 0) { + rc = TPM_SHA1(tpm_daa_session_data->DAA_session.DAA_digest, + inputData0->size, inputData0->buffer, /* e. DAA_session -> DAA_digest */ + DAA_SIZE_NT, nt, + 0, NULL); + } + /* h. Set outputData = NT */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, DAA_SIZE_NT, nt); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS. */ + free(nt); /* @1 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage17_Sign_Stage11(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + unsigned char *r0 = NULL; /* freed @1 */ + TPM_BIGNUM r0Bignum = NULL; /* freed @2 */ + TPM_BIGNUM fBignum = NULL; /* freed @3 */ + TPM_BIGNUM s0Bignum = NULL; /* freed @4 */ + TPM_BIGNUM cBignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage17_Sign_Stage11:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==17. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Obtain DAA_SIZE_r0 bytes using the MGF1 function and label them r0. "r0" || DAA_session + -> DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage17_Sign_Stage11: Creating r0\n"); + rc = TPM_MGF1_GenerateArray(&r0, /* returned MGF1 array */ + DAA_SIZE_r0, /* size of Y */ + /* length of the entire seed */ + sizeof("r0") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r0") -1, "r0", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r0Bignum, r0, DAA_SIZE_r0); + } + /* e. 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. */ + if (rc == 0) { + rc = TPM_ComputeF(&fBignum, tpm_daa_session_data); /* freed @3 */ + } + /* f. Set f0 = f mod 2^DAA_power0 (erase all but the lowest DAA_power0 bits of f) */ + if (rc == 0) { + rc = TPM_BN_mask_bits(fBignum, DAA_power0); /* f becomes f0 */ + } + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage17_Sign_Stage11: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* g. Set s0 = r0 + (DAA_session -> DAA_digest) * f0 in Z. Compute over the integers. The + computation is not reduced with a modulus. */ + /* s0 = r0 + (c * f0) */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s0Bignum, /* result */ + r0Bignum, /* A */ + cBignum, /* B */ + fBignum); /* C */ + } + /* h. set outputData = s0 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s0Bignum, 0); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS */ + free(r0); /* @1 */ + TPM_BN_free(r0Bignum); /* @2 */ + TPM_BN_free(fBignum); /* @3 */ + TPM_BN_free(s0Bignum); /* @4 */ + TPM_BN_free(cBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage18_Sign_Stage12(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + unsigned char *r1 = NULL; /* freed @1 */ + TPM_BIGNUM r1Bignum = NULL; /* freed @2 */ + TPM_BIGNUM fBignum = NULL; /* freed @3 */ + TPM_BIGNUM f1Bignum = NULL; /* freed @4 */ + TPM_BIGNUM s1Bignum = NULL; /* freed @5 */ + TPM_BIGNUM cBignum = NULL; /* freed @6 */ + + printf("TPM_DAAJoin_Stage18_Sign_Stage12:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==18. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Obtain DAA_SIZE_r1 bytes using the MGF1 function and label them r1. "r1" || DAA_session + -> DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage18_Sign_Stage12: Creating r1\n"); + rc = TPM_MGF1_GenerateArray(&r1, /* returned MGF1 array */ + DAA_SIZE_r1, /* size of Y */ + /* length of the entire seed */ + sizeof("r1") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r1") -1, "r1", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r1Bignum, r1, DAA_SIZE_r1); + } + /* e. 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. */ + if (rc == 0) { + rc = TPM_ComputeF(&fBignum, tpm_daa_session_data); /* freed @3 */ + } + /* f. Shift f right by DAA_power0 bits (discard the lowest DAA_power0 bits) and label the result + f1 */ + if (rc == 0) { + rc = TPM_BN_rshift(&f1Bignum, fBignum, DAA_power0); /* f becomes f1 */ + } + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage18_Sign_Stage12: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* g. Set s1 = r1 + (DAA_session -> DAA_digest)* f1 in Z. Compute over the integers. The + computation is not reduced with a modulus. */ + /* s1 = r1 + (c * f1) */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s1Bignum, /* result */ + r1Bignum, /* A */ + cBignum, /* B */ + f1Bignum); /* C */ + } + /* h. set outputData = s1 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s1Bignum, 0); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS */ + free(r1); /* @1 */ + TPM_BN_free(r1Bignum); /* @2 */ + TPM_BN_free(fBignum); /* @3 */ + TPM_BN_free(f1Bignum); /* @4 */ + TPM_BN_free(s1Bignum); /* @5 */ + TPM_BN_free(cBignum); /* @6 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage19(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + unsigned char *r2 = NULL; /* freed @1 */ + TPM_BIGNUM r2Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s2Bignum = NULL; /* freed @3 */ + TPM_BIGNUM cBignum = NULL; /* freed @4 */ + TPM_BIGNUM u0Bignum = NULL; /* freed @5 */ + + printf("TPM_DAAJoin_Stage19:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==19. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Obtain DAA_SIZE_r2 bytes using the MGF1 function and label them r2. "r2" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage19: Creating r2\n"); + rc = TPM_MGF1_GenerateArray(&r2, /* returned MGF1 array */ + DAA_SIZE_r2, /* size of Y */ + /* length of the entire seed */ + sizeof("r2") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r2") -1, "r2", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r2Bignum, r2, DAA_SIZE_r2); + } + /* e. 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) */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage19: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* FIXME Set u0 = DAA_joinSession -> DAA_join_u0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage19: Creating u0 from DAA_joinSession -> DAA_join_u0\n"); + rc = TPM_bin2bn(&u0Bignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u0, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u0)); + } + /* s2 = (r2 + c * u0) mod_pow */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s2Bignum, /* result */ + r2Bignum, /* A */ + cBignum, /* B */ + u0Bignum); /* C */ + } + if (rc == 0) { + rc = TPM_BN_mask_bits(s2Bignum, DAA_power1); + } + /* f. set outputData = s2 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s2Bignum, 0); + } + /* insure that outputData is DAA_power1 bits */ + if (rc == 0) { + rc = TPM_SizedBuffer_ComputeEnlarge(outputData, DAA_power1 / 8); + } + /* g. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* h. return TPM_SUCCESS */ + free(r2); /* @1 */ + TPM_BN_free(r2Bignum); /* @2 */ + TPM_BN_free(s2Bignum); /* @3 */ + TPM_BN_free(cBignum); /* @4 */ + TPM_BN_free(u0Bignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage20(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + unsigned char *r2 = NULL; /* freed @1 */ + TPM_BIGNUM r2Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s12Bignum = NULL; /* freed @3 */ + TPM_BIGNUM s12sBignum = NULL; /* freed @4 */ + TPM_BIGNUM cBignum = NULL; /* freed @5 */ + TPM_BIGNUM u0Bignum = NULL; /* freed @6 */ + + unsigned int numBytes; /* just for debug */ + + printf("TPM_DAAJoin_Stage20:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==20. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Obtain DAA_SIZE_r2 bytes using the MGF1 function and label them r2. "r2" || DAA_session + -> DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage20: Creating r2\n"); + rc = TPM_MGF1_GenerateArray(&r2, /* returned MGF1 array */ + DAA_SIZE_r2, /* size of Y */ + /* length of the entire seed */ + sizeof("r2") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r2") -1, "r2", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r2Bignum, r2, DAA_SIZE_r2); + } + /* e. Set s12 = r2 + (DAA_session -> DAA_digest)*( DAA_joinSession -> DAA_join_u0) */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage20: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* FIXME Set u0 = DAA_joinSession -> DAA_join_u0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage20: Creating u0 from DAA_joinSession -> DAA_join_u0\n"); + rc = TPM_bin2bn(&u0Bignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u0, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u0)); + } + /* s12 = (r2 + c * u0) mod_pow */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s12Bignum, /* result */ + r2Bignum, /* A */ + cBignum, /* B */ + u0Bignum); /* C */ + } + /* FIXME for debug */ + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, s12Bignum); + printf("TPM_DAAJoin_Stage20: e. s12 size %u\n", numBytes); + } + /* f. Shift s12 right by DAA_power1 bit (discard the lowest DAA_power1 bits). */ + if (rc == 0) { + rc = TPM_BN_rshift(&s12sBignum, s12Bignum, DAA_power1); /* s12 becomes s12s */ + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, s12sBignum); + printf("TPM_DAAJoin_Stage20: f. s12 size %u\n", numBytes); + } + /* g. Set DAA_session -> DAA_scratch = s12 */ + if (rc == 0) { + rc = TPM_ComputeDAAScratch(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + s12sBignum); + } + /* h. Set outputData = DAA_session -> DAA_digest */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_session.DAA_digest); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS */ + free(r2); /* @1 */ + TPM_BN_free(r2Bignum); /* @2 */ + TPM_BN_free(s12Bignum); /* @3 */ + TPM_BN_free(s12sBignum); /* @4 */ + TPM_BN_free(cBignum); /* @5 */ + TPM_BN_free(u0Bignum); /* @6 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage21(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + unsigned char *r3 = NULL; /* freed @1 */ + TPM_BIGNUM r3Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s3Bignum = NULL; /* freed @3 */ + TPM_BIGNUM cBignum = NULL; /* freed @4 */ + TPM_BIGNUM u1Bignum = NULL; /* freed @5 */ + TPM_BIGNUM s12Bignum = NULL; /* freed @6 */ + + unsigned int numBytes; /* just for debug */ + + printf("TPM_DAAJoin_Stage21:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==21. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Obtain DAA_SIZE_r3 bytes using the MGF1 function and label them r3. "r3" || DAA_session + -> DAA_contextSeed) is the Z seed. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage21: Creating r3\n"); + rc = TPM_MGF1_GenerateArray(&r3, /* returned MGF1 array */ + DAA_SIZE_r3, /* size of r3 */ + /* length of the entire seed */ + sizeof("r3") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r3") -1, "r3", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r3Bignum, r3, DAA_SIZE_r3); + } + /* just for debug */ + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, r3Bignum); + printf("TPM_DAAJoin_Stage21: r3 size %u\n", numBytes); + } + /* e. Set s3 = r3 + (DAA_session -> DAA_digest)*( DAA_joinSession -> DAA_join_u1) + (DAA_session + -> DAA_scratch). */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage21: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* just for debug */ + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, cBignum); + printf("TPM_DAAJoin_Stage21: c size %u\n", numBytes); + } + /* FIXME Set u1 = DAA_joinSession -> DAA_join_u1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage21: Creating u1 from DAA_joinSession -> DAA_join_u1\n"); + rc = TPM_bin2bn(&u1Bignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u1, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u1)); + } + /* just for debug */ + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, u1Bignum); + printf("TPM_DAAJoin_Stage21: u1 size %u\n", numBytes); + } + /* FIXME Set s12 = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage21: Creating s12 from DAA_session -> DAA_scratch\n"); + rc = TPM_bin2bn(&s12Bignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, s12Bignum); + printf("TPM_DAAJoin_Stage21: s12 size %u\n", numBytes); + } + /* s3 = r3 + c * u1 + s12 */ + if (rc == 0) { + rc = TPM_ComputeApBxCpD(&s3Bignum, /* freed by caller */ + r3Bignum, /* A */ + cBignum, /* B */ + u1Bignum, /* C */ + s12Bignum); /* D */ + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, s3Bignum); + printf("TPM_DAAJoin_Stage21: s3 size %u\n", numBytes); + } + /* f. Set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* g. set outputData = s3 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s3Bignum, 0); + } + /* h. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* i. return TPM_SUCCESS */ + free(r3); /* @1 */ + TPM_BN_free(r3Bignum); /* @2 */ + TPM_BN_free(s3Bignum); /* @3 */ + TPM_BN_free(cBignum); /* @4 */ + TPM_BN_free(u1Bignum); /* @5 */ + TPM_BN_free(s12Bignum); /* @6 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage22(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM v10Bignum = NULL; /* freed @1 */ + TPM_BIGNUM v10sBignum = NULL; /* freed @2 */ + TPM_BIGNUM u0Bignum = NULL; /* freed @3 */ + TPM_BIGNUM u2Bignum = NULL; /* freed @4 */ + TPM_BIGNUM v0Bignum = NULL; /* freed @5 */ + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + unsigned int numBytes; /* just for debug */ + + printf("TPM_DAAJoin_Stage22:\n"); + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @6 */ + /* a. Verify that DAA_session ->DAA_stage==22. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify inputSize0 == DAA_SIZE_v0 and return error TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + if (inputData0->size != DAA_SIZE_v0) { + printf("TPM_DAAJoin_Stage22: Error, inputData0 size %u should be %u\n", + inputData0->size, DAA_SIZE_v0); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Set u2 = inputData0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage22: Creating u2\n"); + rc = TPM_bin2bn(&u2Bignum, inputData0->buffer, inputData0->size); + } + /* f. Set v0 = u2 + (DAA_joinSession -> DAA_join_u0) mod 2^DAA_power1 (Erase all but the lowest + DAA_power1 bits of v0). */ + /* FIXME Set u0 = DAA_joinSession -> DAA_join_u0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage22: Creating u0 from DAA_joinSession -> DAA_join_u0\n"); + rc = TPM_bin2bn(&u0Bignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u0, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u0)); + } + /* FIXME factor this? */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage22: Calculate v0\n"); + rc = TPM_BN_new(&v0Bignum); + } + /* v0 = u2 + u0 */ + if (rc == 0) { + rc = TPM_BN_add(v0Bignum, u2Bignum, u0Bignum); + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, v0Bignum); + printf("TPM_DAAJoin_Stage22: f. v0 size before mask %u\n", numBytes); + } + /* v0 = v0 mod 2^DAA_power1 */ + if (rc == 0) { + rc = TPM_BN_mask_bits(v0Bignum, DAA_power1); + } + if (rc == 0) { + rc = TPM_BN_num_bytes(&numBytes, v0Bignum); + printf("TPM_DAAJoin_Stage22: f. v0 size after mask %u\n", numBytes); + } + /* g. Set DAA_tpmSpecific -> DAA_digest_v0 = SHA-1(v0) */ + if (rc == 0) { + rc = TPM_SHA1_BignumGenerate(tpm_daa_session_data->DAA_tpmSpecific.DAA_digest_v0, + v0Bignum, + (DAA_power1 + 7) / 8); /* canonicalize the number of + bytes */ + } + /* h. Set v10 = u2 + (DAA_joinSession -> DAA_join_u0) in Z. Compute over the integers. + The computation is not reduced with a modulus. */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage22: Calculate v10\n"); + rc = TPM_BN_new(&v10Bignum); + } + /* v0 = u2 + u0 */ + if (rc == 0) { + rc = TPM_BN_add(v10Bignum, u2Bignum, u0Bignum); + } + /* i. Shift v10 right by DAA_power1 bits (erase the lowest DAA_power1 bits). */ + if (rc == 0) { + rc = TPM_BN_rshift(&v10sBignum, v10Bignum, DAA_power1); + } + /* j. Set DAA_session -> DAA_scratch = v10 */ + if (rc == 0) { + rc = TPM_ComputeDAAScratch(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + v10sBignum); + } + /* k. Set outputData */ + /* i. Fill in TPM_DAA_BLOB with a type of TPM_RT_DAA_V0 and encrypt the v0 parameters using + TPM_PERMANENT_DATA -> daaBlobKey */ + /* Create a TPM_DAA_SENSITIVE structure */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage22: Create TPM_DAA_SENSITIVE\n"); + /* Set TPM_DAA_SENSITIVE -> internalData to v0Bignum */ + rc = TPM_bn2binMalloc(&(tpm_daa_sensitive.internalData.buffer), + &(tpm_daa_sensitive.internalData.size), + v0Bignum, 0); + } + if (rc == 0) { + rc = TPM_ComputeEncrypt(outputData, + tpm_state, + &tpm_daa_sensitive, + TPM_RT_DAA_V0); + } + /* l. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* m. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + if (rc == 0) { + rc = TPM_DAADigestContext_GenerateDigestJoin + (tpm_daa_session_data->DAA_session.DAA_digestContext, tpm_daa_session_data); + } + /* n. return TPM_SUCCESS */ + TPM_BN_free(v10Bignum); /* @1 */ + TPM_BN_free(v10sBignum); /* @2 */ + TPM_BN_free(u0Bignum); /* @3 */ + TPM_BN_free(u2Bignum); /* @4 */ + TPM_BN_free(v0Bignum); /* @5 */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @6 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage23(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM u1Bignum = NULL; /* freed @1 */ + TPM_BIGNUM u3Bignum = NULL; /* freed @2 */ + TPM_BIGNUM v1Bignum = NULL; /* freed @3 */ + TPM_BIGNUM v10Bignum = NULL; /* freed @4 */ + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + printf("TPM_DAAJoin_Stage23:\n"); + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @5 */ + /* a. Verify that DAA_session ->DAA_stage==23. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify inputSize0 == DAA_SIZE_v1 and return error TPM_DAA_INPUT_DATA0 on */ + /* mismatch */ + if (rc == 0) { + if (inputData0->size != DAA_SIZE_v1) { + printf("TPM_DAAJoin_Stage23: Error, inputData0 size %u should be %u\n", + inputData0->size, DAA_SIZE_v1); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Set u3 = inputData0 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage23: Creating u3\n"); + rc = TPM_bin2bn(&u3Bignum, inputData0->buffer, inputData0->size); + } + /* f. Set v1 = u3 + DAA_joinSession -> DAA_join_u1 + DAA_session -> DAA_scratch */ + /* FIXME Set u1 = DAA_joinSession -> DAA_join_u1 */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage23: Creating u1 from DAA_joinSession -> DAA_join_u1\n"); + rc = TPM_bin2bn(&u1Bignum, + tpm_daa_session_data->DAA_joinSession.DAA_join_u1, + sizeof(tpm_daa_session_data->DAA_joinSession.DAA_join_u1)); + } + /* FIXME Set v10 = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage23: Creating v10\n"); + rc = TPM_bin2bn(&v10Bignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + if (rc == 0) { + rc = TPM_BN_new(&v1Bignum); + } + /* f. Set v1 = u3 + u1 + v10 */ + if (rc == 0) { + rc = TPM_BN_add(v1Bignum, u3Bignum, u1Bignum); + } + if (rc == 0) { + rc = TPM_BN_add(v1Bignum, v1Bignum,v10Bignum); + } + /* g. Set DAA_tpmSpecific -> DAA_digest_v1 = SHA-1(v1) */ + if (rc == 0) { + rc = TPM_SHA1_BignumGenerate(tpm_daa_session_data->DAA_tpmSpecific.DAA_digest_v1, + v1Bignum, + DAA_SIZE_v1); /* canonicalize the number of bytes */ + } + /* h. Set outputData */ + /* i. Fill in TPM_DAA_BLOB with a type of TPM_RT_DAA_V1 and encrypt the v1 parameters using + TPM_PERMANENT_DATA -> daaBlobKey */ + /* Create a TPM_DAA_SENSITIVE structure */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage23: Create TPM_DAA_SENSITIVE\n"); + /* Set TPM_DAA_SENSITIVE -> internalData to v1Bignum */ + rc = TPM_bn2binMalloc(&(tpm_daa_sensitive.internalData.buffer), + &(tpm_daa_sensitive.internalData.size), + v1Bignum, 0); + } + if (rc == 0) { + rc = TPM_ComputeEncrypt(outputData, + tpm_state, + &tpm_daa_sensitive, + TPM_RT_DAA_V1); + } + + + /* i. Set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* j. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* k. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific || DAA_joinSession) */ + if (rc == 0) { + rc = TPM_DAADigestContext_GenerateDigestJoin + (tpm_daa_session_data->DAA_session.DAA_digestContext, tpm_daa_session_data); + } + /* l. return TPM_SUCCESS */ + TPM_BN_free(u1Bignum); /* @1 */ + TPM_BN_free(u3Bignum); /* @2 */ + TPM_BN_free(v1Bignum); /* @3 */ + TPM_BN_free(v10Bignum); /* @4 */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAAJoin_Stage24(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData) +{ + TPM_RESULT rc = 0; + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + printf("TPM_DAAJoin_Stage24:\n"); + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @1 */ + /* a. Verify that DAA_session ->DAA_stage==24. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) + and return error TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. set outputData = enc(DAA_tpmSpecific) using TPM_PERMANENT_DATA -> daaBlobKey */ + /* Create a TPM_DAA_SENSITIVE structure */ + if (rc == 0) { + printf("TPM_DAAJoin_Stage24 Create TPM_DAA_SENSITIVE\n"); + /* Set TPM_DAA_SENSITIVE -> internalData to DAA_tpmSpecific */ + rc = TPM_SizedBuffer_SetStructure(&(tpm_daa_sensitive.internalData), + &(tpm_daa_session_data->DAA_tpmSpecific), + (TPM_STORE_FUNCTION_T)TPM_DAATpm_Store); + } + if (rc == 0) { + rc = TPM_ComputeEncrypt(outputData, + tpm_state, + &tpm_daa_sensitive, + TPM_RT_DAA_TPM); + } + /* e. return TPM_SUCCESS */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @2 */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage00(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA **tpm_daa_session_data, /* returns entry in + array */ + TPM_BOOL *daaHandleValid, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + TPM_HANDLE daaHandle = 0; /* no preassigned handle */ + + printf("TPM_DAASign_Stage00:\n"); + /* a. Determine that sufficient resources are available to perform a TPM_DAA_Sign. */ + /* i. The TPM MUST support sufficient resources to perform one (1) + TPM_DAA_Join/TPM_DAA_Sign. The TPM MAY support addition TPM_DAA_Join/ TPM_DAA_Sign + sessions. */ + /* ii. The TPM may share internal resources between the DAA operations and other variable + resource requirements: */ + /* iii. If there are insufficient resources within the stored key pool (and one or more keys + need to be removed to permit the DAA operation to execute) return TPM_NOSPACE */ + /* iv. If there are insufficient resources within the stored session pool (and one or more + authorization or transport sessions need to be removed to permit the DAA operation to + execute), return TPM_RESOURCES. */ + if (rc == 0) { + rc = TPM_DaaSessions_GetNewHandle(tpm_daa_session_data, /* returns entry in array */ + &daaHandle, /* output */ + daaHandleValid, /* output */ + tpm_state->tpm_stclear_data.daaSessions); /* array */ + } + /* b. Set DAA_issuerSettings = inputData0 */ + if (rc == 0) { + stream = inputData0->buffer; + stream_size = inputData0->size; + rc = TPM_DAAIssuer_Load(&((*tpm_daa_session_data)->DAA_issuerSettings), + &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* c. Verify that all fields in DAA_issuerSettings are present and return error + TPM_DAA_INPUT_DATA0 if not. */ + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_DAASign_Stage00: Error, bad input0 size %u\n", inputData0->size); + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + /* d. set all fields in DAA_session = NULL */ + /* e. Assign new handle for session */ + /* NOTE Done by TPM_DaaSessions_GetNewHandle() */ + printf("TPM_DAASign_Stage00: handle %08x\n", (*tpm_daa_session_data)->daaHandle); + /* f. Set outputData to new handle */ + /* i. The handle in outputData is included the output HMAC. */ + rc = TPM_SizedBuffer_Append32(outputData, (*tpm_daa_session_data)->daaHandle); + } + /* g. set DAA_session -> DAA_stage = 1 */ + /* NOTE Done by common code */ + /* h. return TPM_SUCCESS */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage01(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + TPM_DAA_SENSITIVE tpm_daa_sensitive; + unsigned char *stream; + uint32_t stream_size; + + printf("TPM_DAASign_Stage01:\n"); + outputData = outputData; /* not used */ + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @1 */ + /* a. Verify that DAA_session ->DAA_stage==1. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Set DAA_tpmSpecific = unwrap(inputData0) using TPM_PERMANENT_DATA -> daaBlobKey */ + if (rc == 0) { + rc = TPM_ComputeDecrypt(&tpm_daa_sensitive, /* output */ + tpm_state, /* decryption and HMAC keys */ + inputData0, /* encrypted stream */ + TPM_RT_DAA_TPM); /* resourceType expected */ + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + stream = tpm_daa_sensitive.internalData.buffer; + stream_size = tpm_daa_sensitive.internalData.size; + rc = TPM_DAATpm_Load(&(tpm_daa_session_data->DAA_tpmSpecific), &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* c. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + + /* d. set DAA_session -> DAA_digestContext = SHA-1(DAA_tpmSpecific) */ + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(tpm_daa_session_data->DAA_session.DAA_digestContext, + &(tpm_daa_session_data->DAA_tpmSpecific), + (TPM_STORE_FUNCTION_T)TPM_DAATpm_Store); + } + /* e set outputData = NULL */ + /* NOTE Done by caller */ + /* f. set DAA_session -> DAA_stage =2 */ + /* NOTE Done by common code */ + /* g. return TPM_SUCCESS */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @1 */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage05(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *Y = NULL; /* freed @1 */ + TPM_BIGNUM yBignum = NULL; /* freed @2 */ + TPM_BIGNUM xBignum = NULL; /* freed @3 */ + TPM_BIGNUM nBignum = NULL; /* freed @4 */ + TPM_BIGNUM zBignum = NULL; /* freed @5 */ + + printf("TPM_DAASign_Stage05:\n"); + tpm_state = tpm_state; /* not used */ + /* a. Verify that DAA_session ->DAA_stage==5. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_generic_S1 = inputData0 */ + /* e. Verify that SHA-1(DAA_generic_S1) == DAA_issuerSettings -> DAA_digest_S1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAASign_Stage05: Checking DAA_generic_S1\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_S1, /* expect */ + inputData0->size, inputData0->buffer, /* DAA_generic_S1 */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Set DAA_generic_n = inputData1 */ + /* g. Verify that SHA-1(DAA_generic_n) == DAA_issuerSettings -> DAA_digest_n and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + printf("TPM_DAASign_Stage05: Checking DAA_digest_n\n"); + rc = TPM_SHA1_Check(tpm_daa_session_data->DAA_issuerSettings.DAA_digest_n, /* expect */ + inputData1->size, inputData1->buffer, /* DAA_generic_n */ + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* h. Obtain DAA_SIZE_r4 bytes using the MGF1 function and label them Y. "r4" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAASign_Stage05: Creating Y\n"); + rc = TPM_MGF1_GenerateArray(&Y, /* returned MGF1 array */ + DAA_SIZE_r4, /* size of Y */ + /* length of the entire seed */ + sizeof("r4") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r4") -1, "r4", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&yBignum, Y, DAA_SIZE_r4); + } + /* i. Set X = DAA_generic_S1 */ + if (rc == 0) { + printf("TPM_DAASign_Stage05 Creating X\n"); + rc = TPM_bin2bn(&xBignum, inputData0->buffer, inputData0->size); + } + /* j. Set n = DAA_generic_n */ + if (rc == 0) { + printf("TPM_DAASign_Stage05: Creating n\n"); + rc = TPM_bin2bn(&nBignum, inputData1->buffer, inputData1->size); + } + /* k. Set Z = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAASign_Stage05: Creating Z\n"); + rc = TPM_bin2bn(&zBignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* l. Set DAA_session -> DAA_scratch = Z*(X^Y) mod n */ + if (rc == 0) { + rc = TPM_ComputeZxAexpPmodn(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + zBignum, /* Z */ + xBignum, /* A */ + yBignum, /* P */ + nBignum); /* N */ + } + /* m. set outputData = DAA_session -> DAA_scratch */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + tpm_daa_session_data->DAA_session.DAA_scratch); + } + /* n. set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* o. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* p. return TPM_SUCCESS */ + free(Y); /* @1 */ + TPM_BN_free(yBignum); /* @2 */ + TPM_BN_free(xBignum); /* @3 */ + TPM_BN_free(nBignum); /* @4 */ + TPM_BN_free(zBignum); /* @5 */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage10(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + uint8_t selector; + TPM_BOOL parentPCRStatus; + TPM_KEY_HANDLE keyHandle; + TPM_KEY *identityKey = NULL; /* the key specified by keyHandle */ + + printf("TPM_DAASign_Stage10:\n"); + /* a. Verify that DAA_session ->DAA_stage==10. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Verify that inputSize0 == sizeOf(BYTE), and return error TPM_DAA_INPUT_DATA0 on + mismatch */ + /* e. Set selector = inputData0, verify that selector == 0 or 1, and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + stream = inputData0->buffer; + stream_size = inputData0->size; + rc = TPM_Load8(&selector, &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_DAASign_Stage10: Error, bad input0 size %u\n", inputData0->size); + rc = TPM_DAA_INPUT_DATA0; + } + } + if (rc == 0) + printf("TPM_DAASign_Stage10: selector %u\n", selector); + switch (selector) { + case 1: + /* f. If selector == 1, verify that inputSize1 == sizeOf(TPM_DIGEST), and return error + TPM_DAA_INPUT_DATA1 on mismatch */ + if (rc == 0) { + if (inputData1->size != TPM_DIGEST_SIZE) { + printf("TPM_DAASign_Stage10: Error, bad input1 size %u\n", inputData1->size); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* g. Set DAA_session -> DAA_digest to SHA-1 (DAA_session -> DAA_digest || 1 || + inputData1) */ + if (rc == 0) { + rc = TPM_SHA1(tpm_daa_session_data->DAA_session.DAA_digest, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_session.DAA_digest, + 1, &selector , + inputData1->size, inputData1->buffer, + 0, NULL); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + break; + case 0: + /* h. If selector == 0, verify that inputData1 is a handle to a TPM identity key (AIK), + and return error TPM_DAA_INPUT_DATA1 on mismatch */ + /* get the key handle */ + if (rc == 0) { + stream = inputData1->buffer; + stream_size = inputData1->size; + rc = TPM_Load32(&keyHandle, &stream, &stream_size); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* validate inputData1 */ + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_DAASign_Stage10: Error, bad input1 size %u\n", inputData1->size); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* get the key */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_GetKey(&identityKey, &parentPCRStatus, + tpm_state, keyHandle, + TRUE, /* read only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA1; + } + } + /* validate that it's an AIK */ + if (rc == 0) { + if (identityKey->keyUsage != TPM_KEY_IDENTITY) { + printf("TPM_DAASign_Stage10: Error, " + "key keyUsage %04hx must be TPM_KEY_IDENTITY\n", identityKey->keyUsage); + rc = TPM_DAA_INPUT_DATA1; + } + } + /* i. Set DAA_session -> DAA_digest to SHA-1 (DAA_session -> DAA_digest || 0 || n2) + where n2 is the modulus of the AIK */ + if (rc == 0) { + rc = TPM_SHA1(tpm_daa_session_data->DAA_session.DAA_digest, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_session.DAA_digest, + 1, &selector, + identityKey->pubKey.size, identityKey->pubKey.buffer, + 0, NULL); + } + break; + default: + printf("TPM_DAASign_Stage10: Error, bad selector %u\n", selector); + rc = TPM_DAA_INPUT_DATA0; + break; + } + /* j. Set outputData = DAA_session -> DAA_digest */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(outputData, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_session.DAA_digest); + } + /* k. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* l. return TPM_SUCCESS. */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage13(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *r2 = NULL; /* freed @1 */ + TPM_BIGNUM r2Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s2Bignum = NULL; /* freed @3 */ + TPM_BIGNUM cBignum = NULL; /* freed @4 */ + TPM_BIGNUM v0Bignum = NULL; /* freed @5 */ + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + printf("TPM_DAASign_Stage13:\n"); + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @6 */ + /* a. Verify that DAA_session ->DAA_stage==13. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_private_v0= unwrap(inputData0) using TPM_PERMANENT_DATA -> daaBlobKey */ + if (rc == 0) { + printf("TPM_DAASign_Stage13: unwrapping to v0\n"); + rc = TPM_ComputeDecrypt(&tpm_daa_sensitive, /* output */ + tpm_state, /* decryption and HMAC keys */ + inputData0, /* encrypted stream */ + TPM_RT_DAA_V0); /* resourceType expected */ + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Verify that SHA-1(DAA_private_v0) == DAA_tpmSpecific -> DAA_digest_v0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAASign_Stage13: Checking v0\n"); + rc = TPM_SHA1_SizedBufferCheck(tpm_daa_session_data->DAA_tpmSpecific.DAA_digest_v0, + &(tpm_daa_sensitive.internalData), + (DAA_power1 + 7) / 8); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Obtain DAA_SIZE_r2 bytes from the MGF1 function and label them r2. "r2" || DAA_session -> + DAA_contextSeed) is the Z seed. */ + if (rc == 0) { + printf("TPM_DAASign_Stage13 Creating r2\n"); + rc = TPM_MGF1_GenerateArray(&r2, /* returned MGF1 array */ + DAA_SIZE_r2, /* size of Y */ + /* length of the entire seed */ + sizeof("r2") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r2") -1, "r2", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r2Bignum, r2, DAA_SIZE_r2); + } + /* g. Set s2 = r2 + (DAA_session -> DAA_digest)*( DAA_private_v0) mod 2^DAA_power1 */ + /* (erase all but the lowest DAA_power1 bits of s2) */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAASign_Stage13: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* FIXME Set v0 = DAA_private_v0 */ + if (rc == 0) { + rc = TPM_bin2bn(&v0Bignum, + tpm_daa_sensitive.internalData.buffer, + tpm_daa_sensitive.internalData.size); + } + /* s2 = r2 + c * v0 mod 2^DAA_power1 */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s2Bignum, /* result */ + r2Bignum, /* A */ + cBignum, /* B */ + v0Bignum); /* C */ + } + if (rc == 0) { + rc = TPM_BN_mask_bits(s2Bignum, DAA_power1); + } + /* h. set outputData = s2 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s2Bignum, 0); + } + /* i. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* j. return TPM_SUCCESS */ + free(r2); /* @1 */ + TPM_BN_free(r2Bignum); /* @2 */ + TPM_BN_free(s2Bignum); /* @3 */ + TPM_BN_free(cBignum); /* @4 */ + TPM_BN_free(v0Bignum); /* @5 */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @6 */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage14(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *r2 = NULL; /* freed @1 */ + TPM_BIGNUM r2Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s12Bignum = NULL; /* freed @3 */ + TPM_BIGNUM s12sBignum = NULL; /* freed @4 */ + TPM_BIGNUM cBignum = NULL; /* freed @5 */ + TPM_BIGNUM v0Bignum = NULL; /* freed @6 */ + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + printf("TPM_DAASign_Stage14:\n"); + outputData = outputData; /* not used */ + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @7 */ + /* a. Verify that DAA_session ->DAA_stage==14. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_private_v0= unwrap(inputData0) using TPM_PERMANENT_DATA -> daaBlobKey */ + if (rc == 0) { + rc = TPM_ComputeDecrypt(&tpm_daa_sensitive, /* output */ + tpm_state, /* decryption and HMAC keys */ + inputData0, /* encrypted stream */ + TPM_RT_DAA_V0); /* resourceType expected */ + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Verify that SHA-1(DAA_private_v0) == DAA_tpmSpecific -> DAA_digest_v0 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAASign_Stage14: Checking v0\n"); + rc = TPM_SHA1_SizedBufferCheck(tpm_daa_session_data->DAA_tpmSpecific.DAA_digest_v0, + &(tpm_daa_sensitive.internalData), + (DAA_power1 + 7) / 8); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Obtain DAA_SIZE_r2 bytes from the MGF1 function and label them r2. "r2" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAASign_Stage14: Creating r2\n"); + rc = TPM_MGF1_GenerateArray(&r2, /* returned MGF1 array */ + DAA_SIZE_r2, /* size of Y */ + /* length of the entire seed */ + sizeof("r2") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r2") -1, "r2", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r2Bignum, r2, DAA_SIZE_r2); + } + /* g. Set s12 = r2 + (DAA_session -> DAA_digest)*(DAA_private_v0). */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAASign_Stage14: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* FIXME Set v0 = DAA_private_v0 */ + if (rc == 0) { + rc = TPM_bin2bn(&v0Bignum, + tpm_daa_sensitive.internalData.buffer, + tpm_daa_sensitive.internalData.size); + } + /* s12 = r2 + c * v0 */ + if (rc == 0) { + rc = TPM_ComputeApBxC(&s12Bignum, /* result */ + r2Bignum, /* A */ + cBignum, /* B */ + v0Bignum); /* C */ + } + /* h. Shift s12 right by DAA_power1 bits (erase the lowest DAA_power1 bits). */ + if (rc == 0) { + rc = TPM_BN_rshift(&s12sBignum, s12Bignum, DAA_power1); /* f becomes f1 */ + } + /* i. Set DAA_session -> DAA_scratch = s12 */ + if (rc == 0) { + rc = TPM_ComputeDAAScratch(tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch), + s12sBignum); + } + /* j. set outputData = NULL */ + /* NOTE Done by caller */ + /* k. increment DAA_session -> DAA_stage by 1 */ + /* NOTE Done by common code */ + /* l. return TPM_SUCCESS */ + free(r2); /* @1 */ + TPM_BN_free(r2Bignum); /* @2 */ + TPM_BN_free(s12Bignum); /* @3 */ + TPM_BN_free(s12sBignum); /* @4 */ + TPM_BN_free(cBignum); /* @5 */ + TPM_BN_free(v0Bignum); /* @6 */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @7 */ + return rc; +} + +TPM_RESULT TPM_DAASign_Stage15(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0) +{ + TPM_RESULT rc = 0; + unsigned char *r4 = NULL; /* freed @1 */ + TPM_BIGNUM r4Bignum = NULL; /* freed @2 */ + TPM_BIGNUM s3Bignum = NULL; /* freed @3 */ + TPM_BIGNUM cBignum = NULL; /* freed @4 */ + TPM_BIGNUM v1Bignum = NULL; /* freed @5 */ + TPM_BIGNUM s12Bignum = NULL; /* freed @6 */ + TPM_DAA_SENSITIVE tpm_daa_sensitive; + + printf("TPM_DAASign_Stage15:\n"); + TPM_DAASensitive_Init(&tpm_daa_sensitive); /* freed @7 */ + /* a. Verify that DAA_session ->DAA_stage==15. Return TPM_DAA_STAGE and flush handle on + mismatch */ + /* NOTE Done by common code */ + /* b. Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return + error TPM_DAA_ISSUER_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* c. Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + /* NOTE Done by common code */ + /* d. Set DAA_private_v1 = unwrap(inputData0) using TPM_PERMANENT_DATA -> daaBlobKey */ + if (rc == 0) { + rc = TPM_ComputeDecrypt(&tpm_daa_sensitive, /* output */ + tpm_state, /* decryption and HMAC keys */ + inputData0, /* encrypted stream */ + TPM_RT_DAA_V1); /* resourceType expected */ + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* e. Verify that SHA-1(DAA_private_v1) == DAA_tpmSpecific -> DAA_digest_v1 and return error + TPM_DAA_INPUT_DATA0 on mismatch */ + if (rc == 0) { + printf("TPM_DAASign_Stage15: Checking v1\n"); + rc = TPM_SHA1_SizedBufferCheck(tpm_daa_session_data->DAA_tpmSpecific.DAA_digest_v1, + &(tpm_daa_sensitive.internalData), + DAA_SIZE_v1); + if (rc != 0) { + rc = TPM_DAA_INPUT_DATA0; + } + } + /* f. Obtain DAA_SIZE_r4 bytes from the MGF1 function and label them r4. "r4" || DAA_session -> + DAA_contextSeed is the Z seed. */ + if (rc == 0) { + printf("TPM_DAASign_Stage15: Creating r4\n"); + rc = TPM_MGF1_GenerateArray(&r4, /* returned MGF1 array */ + DAA_SIZE_r4, /* size of Y */ + /* length of the entire seed */ + sizeof("r4") -1 + + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + sizeof("r4") -1, "r4", + sizeof(tpm_daa_session_data->DAA_session.DAA_contextSeed), + tpm_daa_session_data->DAA_session.DAA_contextSeed, + 0, NULL); + } + if (rc == 0) { + rc = TPM_bin2bn(&r4Bignum, r4, DAA_SIZE_r4); + } + /* g. Set s3 = r4 + (DAA_session -> DAA_digest)*(DAA_private_v1) + (DAA_session -> + DAA_scratch). */ + /* FIXME Set c = DAA_session -> DAA_digest */ + if (rc == 0) { + printf("TPM_DAASign_Stage15: Creating c from DAA_session -> DAA_digest\n"); + rc = TPM_bin2bn(&cBignum, tpm_daa_session_data->DAA_session.DAA_digest, TPM_DIGEST_SIZE); + } + /* FIXME Set v1 = DAA_private_v1 */ + if (rc == 0) { + rc = TPM_bin2bn(&v1Bignum, + tpm_daa_sensitive.internalData.buffer, + tpm_daa_sensitive.internalData.size); + } + /* FIXME Set s12 = DAA_session -> DAA_scratch */ + if (rc == 0) { + printf("TPM_DAASign_Stage15: Creating s12 from DAA_session -> DAA_scratch\n"); + rc = TPM_bin2bn(&s12Bignum, + tpm_daa_session_data->DAA_session.DAA_scratch, + sizeof(tpm_daa_session_data->DAA_session.DAA_scratch)); + } + /* s3 = r4 + c * v1 + s12 */ + if (rc == 0) { + rc = TPM_ComputeApBxCpD(&s3Bignum, /* freed by caller */ + r4Bignum, /* A */ + cBignum, /* B */ + v1Bignum, /* C */ + s12Bignum); /* D */ + } + /* h. Set DAA_session -> DAA_scratch = NULL */ + if (rc == 0) { + tpm_daa_session_data->DAA_session.DAA_scratch_null = TRUE; + } + /* i. set outputData = s3 */ + if (rc == 0) { + rc = TPM_bn2binMalloc(&(outputData->buffer), + &(outputData->size), + s3Bignum, 0); + } + /* j. Terminate the DAA session and all resources associated with the DAA sign session + handle. */ + /* NOTE Done by caller */ + /* k. return TPM_SUCCESS */ + free(r4); /* @1 */ + TPM_BN_free(r4Bignum); /* @2 */ + TPM_BN_free(s3Bignum); /* @3 */ + TPM_BN_free(cBignum); /* @4 */ + TPM_BN_free(v1Bignum); /* @5 */ + TPM_BN_free(s12Bignum); /* @6 */ + TPM_DAASensitive_Delete(&tpm_daa_sensitive); /* @7 */ + return rc; +} + +/* + Stage Common Code +*/ + +/* TPM_DAADigestContext_GenerateDigestJoin() sets tpm_digest to SHA-1(DAA_tpmSpecific || + DAA_joinSession)) +*/ + +TPM_RESULT TPM_DAADigestContext_GenerateDigestJoin(TPM_DIGEST tpm_digest, + TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_STORED_DATA serialization */ + + printf(" TPM_DAADigestContext_GenerateDigestJoin:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize DAA_tpmSpecific */ + if (rc == 0) { + rc = TPM_DAATpm_Store(&sbuffer, &(tpm_daa_session_data->DAA_tpmSpecific)); + } + /* serialize DAA_joinSession */ + if (rc == 0) { + rc = TPM_DAAJoindata_Store(&sbuffer, &(tpm_daa_session_data->DAA_joinSession)); + } + /* calculate and return the digest */ + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_DAADigestContext_CheckDigestJoin() verifies that DAA_session -> DAA_digestContext == + SHA-1(DAA_tpmSpecific || DAA_joinSession). + + Returns TPM_DAA_TPM_SETTINGS on mismatch +*/ + +TPM_RESULT TPM_DAADigestContext_CheckDigestJoin(TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + TPM_RESULT rc = 0; + TPM_DIGEST tpm_digest; /* actual digest */ + + printf(" TPM_DAADigestContext_CheckDigestJoin:\n"); + if (rc == 0) { + rc = TPM_DAADigestContext_GenerateDigestJoin(tpm_digest, tpm_daa_session_data); + } + if (rc == 0) { + rc = TPM_Digest_Compare(tpm_digest, tpm_daa_session_data->DAA_session.DAA_digestContext); + if (rc != 0) { + rc = TPM_DAA_TPM_SETTINGS; + } + } + return rc; +} + +/* TPM_ComputeF() computes the value F common to stages 4.j., 5.j., 14.f., 17.e., 18.e. + + j. 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_RESULT TPM_ComputeF(TPM_BIGNUM *fBignum, /* freed by caller */ + TPM_DAA_SESSION_DATA *tpm_daa_session_data) +{ + TPM_RESULT rc = 0; + BYTE nZero = 0; + BYTE nOne = 1; + uint32_t nCount; /* DAA_count in nbo */ + TPM_DIGEST digest0; /* first SHA1 calculation */ + TPM_DIGEST digest1; /* second SHA1 calculation */ + TPM_BIGNUM dividend; /* digest0 || digest1 as a BIGNUM */ + TPM_BIGNUM modulus; /* DAA_generic_q as a BIGNUM */ + + printf(" TPM_ComputeF:\n"); + modulus = NULL; /* freed @1 */ + dividend = NULL; /* freed @2 */ + if (rc == 0) { + rc = TPM_BN_new(fBignum); + } + /* SHA1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 0) */ + if (rc == 0) { + printf(" TPM_ComputeF: Calculate digest0\n"); + nCount = htonl(tpm_daa_session_data->DAA_tpmSpecific.DAA_count); + rc = TPM_SHA1(digest0, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_tpmSpecific.DAA_rekey, + sizeof(uint32_t), &nCount, + sizeof(BYTE), &nZero, + 0, NULL); + } + /* SHA1(DAA_tpmSpecific -> DAA_rekey || DAA_tpmSpecific -> DAA_count || 1 ) */ + if (rc == 0) { + printf(" TPM_ComputeF: Calculate digest1\n"); + rc = TPM_SHA1(digest1, + TPM_DIGEST_SIZE, tpm_daa_session_data->DAA_tpmSpecific.DAA_rekey, + sizeof(uint32_t), &nCount, + sizeof(BYTE), &nOne, + 0, NULL); + } + /* Construct digest0 || digest1 as a positive BIGNUM */ + if (rc == 0) { + rc = TPM_2bin2bn(÷nd, + digest0, TPM_DIGEST_SIZE, + digest1, TPM_DIGEST_SIZE); + } + /* DAA_generic_q as a positive BIGNUM */ + if (rc == 0) { + rc = TPM_bin2bn(&modulus, + tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q, + sizeof(tpm_daa_session_data->DAA_issuerSettings.DAA_generic_q)); + } + /* digest mod DAA_generic_q */ + if (rc == 0) { + rc = TPM_BN_mod(*fBignum, dividend, modulus); + } + TPM_BN_free(modulus); /* @1 */ + TPM_BN_free(dividend); /* @2 */ + return rc; +} + +/* TPM_ComputeAexpPmodn() performs R = (A ^ P) mod n. + + rBignum is new'ed by this function and must be freed by the caller + + If DAA_scratch is not NULL, r is returned in DAA_scratch. +*/ + +TPM_RESULT TPM_ComputeAexpPmodn(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM *rBignum, /* freed by caller */ + TPM_BIGNUM aBignum, + TPM_BIGNUM pBignum, + TPM_BIGNUM nBignum) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ComputeAexpPmodn:\n"); + if (rc == 0) { + rc = TPM_BN_new(rBignum); + } + if (rc == 0) { + rc = TPM_BN_mod_exp(*rBignum, aBignum, pBignum, nBignum); + } + /* if the result should be returned in DAA_scratch */ + if ((rc == 0) && (DAA_scratch != NULL)) { + /* store the result in DAA_scratch */ + rc = TPM_ComputeDAAScratch(DAA_scratch, DAA_scratch_size, *rBignum); + } + return rc; +} + +/* TPM_ComputeZxAexpPmodn() performs DAA_scratch = Z * (A ^ P) mod n. + +*/ + +TPM_RESULT TPM_ComputeZxAexpPmodn(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM zBignum, + TPM_BIGNUM aBignum, + TPM_BIGNUM pBignum, + TPM_BIGNUM nBignum) +{ + TPM_RESULT rc = 0; + TPM_BIGNUM rBignum = NULL; /* freed @1 */ + + printf(" TPM_ComputeZxAexpPmodn:\n"); + if (rc == 0) { + printf(" TPM_ComputeZxAexpPmodn: Calculate R = A ^ P mod n\n"); + rc = TPM_ComputeAexpPmodn(NULL, /* DAA_scratch */ + 0, + &rBignum, /* R */ + aBignum, /* A */ + pBignum, + nBignum); + } + if (rc == 0) { + printf(" TPM_ComputeZxAexpPmodn: Calculate R = Z * R mod n\n"); + rc = TPM_BN_mod_mul(rBignum, zBignum, rBignum, nBignum); + } + /* store the result in DAA_scratch */ + if (rc == 0) { + rc = TPM_ComputeDAAScratch(DAA_scratch, DAA_scratch_size, rBignum); + } + TPM_BN_free(rBignum); /* @1 */ + return rc; +} + +/* TPM_ComputeApBmodn() performs R = A + B mod n + +*/ + +TPM_RESULT TPM_ComputeApBmodn(TPM_BIGNUM *rBignum, /* freed by caller */ + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM nBignum) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ComputeApBmodn:\n"); + if (rc == 0) { + rc = TPM_BN_new(rBignum); /* freed by caller */ + } + if (rc == 0) { + rc = TPM_BN_mod_add(*rBignum, aBignum, bBignum, nBignum); + } + return rc; +} + +/* TPM_ComputeApBxC() performs R = A + B * C + +*/ + +TPM_RESULT TPM_ComputeApBxC(TPM_BIGNUM *rBignum, /* freed by caller */ + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM cBignum) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ComputeApBxC:\n"); + if (rc == 0) { + rc = TPM_BN_new(rBignum); /* freed by caller */ + } + /* R = B * C */ + if (rc == 0) { + rc = TPM_BN_mul(*rBignum, bBignum, cBignum); + } + /* R = R + A */ + if (rc == 0) { + rc = TPM_BN_add(*rBignum, *rBignum, aBignum); + } + return rc; +} + +/* TPM_ComputeApBxCpD() performs R = A + B * C + D + +*/ + +TPM_RESULT TPM_ComputeApBxCpD(TPM_BIGNUM *rBignum, /* freed by caller */ + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM cBignum, + TPM_BIGNUM dBignum) +{ + TPM_RESULT rc = 0; + printf(" TPM_ComputeApBxCpD:\n"); + /* R = A + B * C */ + if (rc == 0) { + rc = TPM_ComputeApBxC(rBignum, /* freed by caller */ + aBignum, + bBignum, + cBignum); + } + /* R = R + D */ + if (rc == 0) { + rc = TPM_BN_add(*rBignum, *rBignum, dBignum); + } + return rc; +} + +/* TPM_ComputeDAAScratch() stores 'bn' in DAA_scratch + +*/ + +TPM_RESULT TPM_ComputeDAAScratch(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM bn) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ComputeDAAScratch:\n"); + if (rc == 0) { + rc = TPM_bn2binArray(DAA_scratch, DAA_scratch_size, bn); + } + return rc; +} + +/* TPM_ComputeEnlarge() creates a buffer of size 'outSize' + + It copies 'outSize - inSize' zero bytes and then appends 'in' + + 'out' must be freed by the caller +*/ + +TPM_RESULT TPM_ComputeEnlarge(unsigned char **out, /* freed by caller */ + uint32_t outSize, + unsigned char *in, + uint32_t inSize) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if (outSize <= inSize) { + printf("TPM_ComputeEnlarge: Error (fatal), inSize %u outSize %u\n", inSize, outSize); + rc = TPM_FAIL; + } + } + if (rc == 0) { + rc = TPM_Malloc(out, outSize); + } + if (rc == 0) { + memset(*out, 0, outSize - inSize); /* zero left bytes */ + memcpy(*out + outSize - inSize, in, inSize); /* copy right bytes */ + } + return rc; +} + +/* TPM_SizedBuffer_ComputeEnlarge() forces 'tpm_sized_buffer' to be 'size' bytes in length. + + If generally useful, this function should be moved to tpm_sizedbuffer.c +*/ + +TPM_RESULT TPM_SizedBuffer_ComputeEnlarge(TPM_SIZED_BUFFER *tpm_sized_buffer, uint32_t size) +{ + TPM_RESULT rc = 0; + unsigned char *newPtr; /* new buffer, enlarged */ + + newPtr = NULL; /* freed by caller */ + /* if tpm_sized_buffer needs to be enlarged */ + if (tpm_sized_buffer->size != size) { + if (rc == 0) { + /* copy the TPM_SIZED_BUFFER data. enlarged, to newPtr */ + rc = TPM_ComputeEnlarge(&newPtr, size, /* output buffer */ + tpm_sized_buffer->buffer, + tpm_sized_buffer->size); + } + if (rc == 0) { + /* after the copy, the old buffer is no longer needed */ + free(tpm_sized_buffer->buffer); + /* assign the with the enlarged buffer to the TPM_SIZED_BUFFER */ + tpm_sized_buffer->buffer = newPtr; + /* update size */ + tpm_sized_buffer->size = size; + } + } + return rc; +} + +/* TPM_ComputeEncrypt() does join steps common to encrypting output data. + + It serializes the TPM_DAA_SENSITIVE, encrypts it to TPM_DAA_BLOB ->sensitiveData, adds the + resourceType, generates the TPM_DAA_BLOB -> blobIntegrity HMAC using daaProof, and serializes the + result to outputData. +*/ + +TPM_RESULT TPM_ComputeEncrypt(TPM_SIZED_BUFFER *outputData, + tpm_state_t *tpm_state, + TPM_DAA_SENSITIVE *tpm_daa_sensitive, + TPM_RESOURCE_TYPE resourceType) +{ + TPM_RESULT rc = 0; + TPM_DAA_BLOB tpm_daa_blob; + TPM_STORE_BUFFER daaSensitiveSbuffer; + + printf(" TPM_ComputeEncrypt:\n"); + TPM_DAABlob_Init(&tpm_daa_blob); /* freed @1 */ + TPM_Sbuffer_Init(&daaSensitiveSbuffer); /* freed @2 */ + + /* serialize the TPM_DAA_SENSITIVE */ + if (rc == 0) { + rc = TPM_DAASensitive_Store(&daaSensitiveSbuffer, tpm_daa_sensitive); + } + /* Create a TPM_DAA_BLOB structure */ + if (rc == 0) { + printf(" TPM_ComputeEncrypt: Create TPM_DAA_BLOB\n"); + tpm_daa_blob.resourceType = resourceType; + /* Set TPM_DAA_BLOB -> sensitiveData to the encryption of serialized TPM_DAA_SENSITIVE */ + rc = TPM_SymmetricKeyData_EncryptSbuffer + (&(tpm_daa_blob.sensitiveData), /* output buffer */ + &daaSensitiveSbuffer, /* input buffer */ + tpm_state->tpm_permanent_data.daaBlobKey); /* key */ + } + /* set TPM_DAA_BLOB -> blobIntegrity to the HMAC of TPM_DAA_BLOB using daaProof as the secret */ + if (rc == 0) { + rc = TPM_HMAC_GenerateStructure(tpm_daa_blob.blobIntegrity, /* HMAC */ + tpm_state->tpm_permanent_data.daaProof, /* HMAC key */ + &tpm_daa_blob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_DAABlob_Store); /* store + function */ + } + /* ii. set outputData to the encrypted TPM_DAA_BLOB */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(outputData, &tpm_daa_blob, + (TPM_STORE_FUNCTION_T )TPM_DAABlob_Store); + } + TPM_DAABlob_Delete(&tpm_daa_blob); /* @1 */ + TPM_Sbuffer_Delete(&daaSensitiveSbuffer); /* @2 */ + return rc; +} + +/* TPM_ComputeDecrypt() does sign steps common to decrypting input data + + It deserializes 'inputData" to a TPM_DAA_BLOB, and validates the resourceType and blobIntegrity + HMAC using daaProof. It decrypts TPM_DAA_BLOB ->sensitiveData and deserializes it to a + TPM_DAA_SENSITIVE. + + tpm_daa_sensitive must be deleted by the caller +*/ + +TPM_RESULT TPM_ComputeDecrypt(TPM_DAA_SENSITIVE *tpm_daa_sensitive, + tpm_state_t *tpm_state, + TPM_SIZED_BUFFER *inputData, + TPM_RESOURCE_TYPE resourceType) + +{ + TPM_RESULT rc = 0; + TPM_DAA_BLOB tpm_daa_blob; + unsigned char *stream; + uint32_t stream_size; + unsigned char *sensitiveStream; + uint32_t sensitiveStreamSize; + + printf(" TPM_ComputeDecrypt:\n"); + TPM_DAABlob_Init(&tpm_daa_blob); /* freed @1 */ + sensitiveStream = NULL; /* freed @2 */ + /* deserialize inputData to a TPM_DAA_BLOB */ + if (rc == 0) { + stream = inputData->buffer; + stream_size = inputData->size; + rc = TPM_DAABlob_Load(&tpm_daa_blob, &stream, &stream_size); + } + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_ComputeDecrypt: Error, bad blob input size %u\n", inputData->size); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* check blobIntegrity */ + if (rc == 0) { + rc = TPM_HMAC_CheckStructure(tpm_state->tpm_permanent_data.daaProof, /* HMAC key */ + &tpm_daa_blob, /* structure */ + tpm_daa_blob.blobIntegrity, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DAABlob_Store, /* store function */ + TPM_DAA_INPUT_DATA0); /* error code */ + } + /* check resourceType */ + if (rc == 0) { + if (tpm_daa_blob.resourceType != resourceType) { + printf("TPM_ComputeDecrypt: Error, resourceType %08x\n", tpm_daa_blob.resourceType); + rc = TPM_DAA_INPUT_DATA0; + } + } + /* decrypt the TPM_DAA_BLOB -> sensitiveData */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Decrypt + (&sensitiveStream, /* output, caller frees */ + &sensitiveStreamSize, /* output */ + tpm_daa_blob.sensitiveData.buffer, /* input */ + tpm_daa_blob.sensitiveData.size, /* input */ + tpm_state->tpm_permanent_data.daaBlobKey); /* dec key */ + } + if (rc == 0) { + stream = sensitiveStream; + stream_size = sensitiveStreamSize; + rc = TPM_DAASensitive_Load(tpm_daa_sensitive, &stream, &stream_size); + } + if (rc == 0) { + if (stream_size != 0) { + printf("TPM_ComputeDecrypt: Error, bad sensitive input size %u\n", sensitiveStreamSize); + rc = TPM_DAA_INPUT_DATA0; + } + } + TPM_DAABlob_Delete(&tpm_daa_blob); /* @1 */ + free(sensitiveStream); /* @2 */ + return rc; +} + +/* TPM_SHA1_BignumGenerate() converts the BIGNUM 'bn' to an array, enlarges the array to 'size', and + computes the SHA-1 hash + +*/ + +TPM_RESULT TPM_SHA1_BignumGenerate(TPM_DIGEST tpm_digest, + TPM_BIGNUM bn, + uint32_t size) +{ + TPM_RESULT rc = 0; + unsigned char *bin = NULL; /* freed @1 */ + unsigned int bytes; + unsigned char *newBin = NULL; /* freed @2, new buffer, enlarged */ + + if (rc == 0) { + rc = TPM_bn2binMalloc(&bin, &bytes, bn, 0); /* freed @1 */ + } + if (rc == 0) { + printf(" TPM_SHA1_BignumGenerate: enlarge to %u bytes, is %u bytes\n", size, bytes); + if (bytes != size) { + /* canonicalize the array size */ + if (rc == 0) { + rc = TPM_ComputeEnlarge(&newBin, size, /* output buffer */ + bin, bytes ); /* inout buffer */ + } + if (rc == 0) { + rc = TPM_SHA1(tpm_digest, + size, newBin, + 0, NULL); + } + } + else { + /* already canonicalized */ + rc = TPM_SHA1(tpm_digest, + bytes, bin, + 0, NULL); + } + } + free(bin); /* @1 */ + free(newBin); /* @2 */ + return rc; +} + +/* TPM_SHA1_SizedBufferCheck() enlarges the TPM_SIZED_BUFFER to 'size', computes the SHA-1 hash, + and validates the digest against 'tpm_digest' + + As a side effect, the TPM_SIZED_BUFFER may be enlarged. +*/ + +TPM_RESULT TPM_SHA1_SizedBufferCheck(TPM_DIGEST tpm_digest, + TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + printf(" TPM_SHA1_SizedBufferCheck: enlarge to %u bytes, is %u bytes\n", + size, tpm_sized_buffer->size); + if (tpm_sized_buffer->size != size) { + /* canonicalize the array size */ + rc = TPM_SizedBuffer_ComputeEnlarge(tpm_sized_buffer, size); + } + } + if (rc == 0) { + rc = TPM_SHA1_Check(tpm_digest, + tpm_sized_buffer->size, tpm_sized_buffer->buffer, + 0, NULL); + } + return rc; +} + +/* + Processing functions +*/ + +/* 26.1 TPM_DAA_Join rev 99 + + TPM_DAA_Join is the process that establishes the DAA parameters in the TPM for a specific DAA + issuing authority. + + outputSize and outputData are always included in the outParamDigest. This includes stage + 0, where the outputData contains the DAA session handle. +*/ + +TPM_RESULT TPM_Process_DAAJoin(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_HANDLE daaHandle; /* Session handle */ + BYTE stage = 0; /* Processing stage of join */ + TPM_SIZED_BUFFER inputData0; /* Data to be used by this capability */ + TPM_SIZED_BUFFER inputData1; /* Data to be used by this capability */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Continue use flag, TRUE if handle is still + active */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and + owner. HMAC key: ownerAuth. */ + + /* processing */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_BOOL daaHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_DAA_SESSION_DATA *tpm_daa_session_data; /* DAA session for handle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outputData; /* Data produced by this capability */ + + printf("TPM_Process_DAAJoin: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inputData0); /* freed @1 */ + TPM_SizedBuffer_Init(&inputData1); /* freed @2 */ + TPM_SizedBuffer_Init(&outputData); /* freed @3 */ + /* + get inputs + */ + /* get handle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&daaHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get stage */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DAAJoin: daaHandle %08x\n", daaHandle); + returnCode = TPM_Load8(&stage, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DAAJoin: stage %u\n", stage); + /* For stages after stage 0, daaHandle is an input. Mark it valid so it can be terminated + on error. */ + if (stage > 0) { + daaHandleValid = TRUE; + } + /* get inputData0 */ + returnCode = TPM_SizedBuffer_Load(&inputData0, &command, ¶mSize); + } + /* get inputData1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inputData1, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DAAJoin: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Use ownerAuth to verify that the Owner authorized all TPM_DAA_Join input parameters. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* + Common to most or all stages + */ + /* Validate the DAA session handle after stage 0, stage 0 assigns the handle */ + if (returnCode == TPM_SUCCESS) { + if (stage > 0) { + returnCode = + TPM_DaaSessions_GetEntry(&tpm_daa_session_data, /* returns entry in array */ + tpm_state->tpm_stclear_data.daaSessions, /* array */ + daaHandle); + } + } + /* Verify that the input state is consistent with the current TPM state */ + if (returnCode == TPM_SUCCESS) { + if (stage > 0) { + returnCode = TPM_DaaSessionData_CheckStage(tpm_daa_session_data, stage); + } + } + /* Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific || DAA_joinSession) and + return error TPM_DAA_TPM_SETTINGS on mismatch */ + if (returnCode == TPM_SUCCESS) { + if (stage >= 1) { + returnCode = TPM_DAADigestContext_CheckDigestJoin(tpm_daa_session_data); + } + } + /* Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return error + TPM_DAA_ISSUER_SETTINGS on mismatch */ + if (returnCode == TPM_SUCCESS) { + if (stage >= 3) { + returnCode = + TPM_SHA1_CheckStructure(tpm_daa_session_data->DAA_tpmSpecific.DAA_digestIssuer, + &(tpm_daa_session_data->DAA_issuerSettings), + (TPM_STORE_FUNCTION_T)TPM_DAAIssuer_Store, + TPM_DAA_ISSUER_SETTINGS); + } + } + /* Stages */ + if (returnCode == TPM_SUCCESS) { + switch (stage) { + case 0 : + returnCode = TPM_DAAJoin_Stage00(tpm_state, + &tpm_daa_session_data, /* entry in array */ + &daaHandleValid, + &outputData, &inputData0); + if (daaHandleValid) { + /* For stage 0, daaHandle may be generated. Extract it from the DAA session and + mark it valid, so the session can be terminated on error. */ + daaHandle = tpm_daa_session_data->daaHandle; + } + break; + case 1 : + returnCode = TPM_DAAJoin_Stage01(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 2 : + returnCode = TPM_DAAJoin_Stage02(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 3 : + returnCode = TPM_DAAJoin_Stage03(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 4 : + returnCode = TPM_DAAJoin_Stage04(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 5 : + returnCode = TPM_DAAJoin_Stage05(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 6 : + returnCode = TPM_DAAJoin_Stage06(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 7 : + returnCode = TPM_DAAJoin_Stage07(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 8 : + returnCode = TPM_DAAJoin_Stage08(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 9 : + returnCode = TPM_DAAJoin_Stage09_Sign_Stage2(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 10 : + returnCode = TPM_DAAJoin_Stage10_Sign_Stage3(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 11 : + returnCode = TPM_DAAJoin_Stage11_Sign_Stage4(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 12 : + returnCode = TPM_DAAJoin_Stage12(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 13 : + returnCode = TPM_DAAJoin_Stage13_Sign_Stage6(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0, &inputData1); + break; + case 14 : + returnCode = TPM_DAAJoin_Stage14_Sign_Stage7(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 15 : + returnCode = TPM_DAAJoin_Stage15_Sign_Stage8(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 16 : + returnCode = TPM_DAAJoin_Stage16_Sign_Stage9(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 17 : + returnCode = TPM_DAAJoin_Stage17_Sign_Stage11(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 18 : + returnCode = TPM_DAAJoin_Stage18_Sign_Stage12(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 19 : + returnCode = TPM_DAAJoin_Stage19(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 20 : + returnCode = TPM_DAAJoin_Stage20(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 21 : + returnCode = TPM_DAAJoin_Stage21(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 22 : + returnCode = TPM_DAAJoin_Stage22(tpm_state, + tpm_daa_session_data, + &outputData, &inputData0); + break; + case 23 : + returnCode = TPM_DAAJoin_Stage23(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 24 : + returnCode = TPM_DAAJoin_Stage24(tpm_state, + tpm_daa_session_data, + &outputData); + break; + default : + printf("TPM_Process_DAAJoin: Error, Illegal stage\n"); + returnCode = TPM_DAA_STAGE; + } + } + /* + Common to most or all stages + */ + if (returnCode == TPM_SUCCESS) { + if (stage >= 2) { + tpm_daa_session_data->DAA_session.DAA_stage++; + } + } + /* 24.e.Terminate the DAA session and all resources associated with the DAA join session + handle. */ + if (returnCode == TPM_SUCCESS) { + if (stage == 24) { + printf("TPM_Process_DAAJoin: Stage 24, terminating DAA session %08x\n", + tpm_daa_session_data->daaHandle); + TPM_DaaSessionData_Delete(tpm_daa_session_data); + } + } + /* 2. Any error return results in the TPM invalidating all resources associated with the + join */ + /* NOTE Done after response processing */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DAAJoin: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return outputData */ + returnCode = TPM_SizedBuffer_Store(response, &outputData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + /* no outParam's, set authorization response data */ + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* on error, terminate the DAA session */ + if (((rcf != 0) || (returnCode != TPM_SUCCESS)) && daaHandleValid) { + TPM_DaaSessions_TerminateHandle(tpm_state->tpm_stclear_data.daaSessions, + daaHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inputData0); /* @1 */ + TPM_SizedBuffer_Delete(&inputData1); /* @2 */ + TPM_SizedBuffer_Delete(&outputData); /* @3 */ + return rcf; +} + +/* 26.2 TPM_DAA_Sign rev 99 + + TPM protected capability; user must provide authorizations from the TPM Owner. + + outputSize and outputData are always included in the outParamDigest. This includes stage + 0, where the outputData contains the DAA session handle. +*/ + +TPM_RESULT TPM_Process_DAASign(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_HANDLE daaHandle; /* Handle to the sign session */ + BYTE stage = 0; /* Stage of the sign process */ + TPM_SIZED_BUFFER inputData0; /* Data to be used by this capability */ + TPM_SIZED_BUFFER inputData1; /* Data to be used by this capability */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Continue use flag, TRUE if handle is still + active */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and + owner. HMAC key: ownerAuth. */ + + /* processing */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_BOOL daaHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_DAA_SESSION_DATA *tpm_daa_session_data; /* DAA session for handle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outputData; /* Data produced by this capability */ + + printf("TPM_Process_DAASign: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inputData0); /* freed @1 */ + TPM_SizedBuffer_Init(&inputData1); /* freed @2 */ + TPM_SizedBuffer_Init(&outputData); /* freed @3 */ + /* + get inputs + */ + /* get handle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&daaHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get stage */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DAASign: daaHandle %08x\n", daaHandle); + returnCode = TPM_Load8(&stage, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DAASign: stage %u\n", stage); + /* For stages after stage 0, daaHandle is an input. Mark it valid so it can be terminated + on error. */ + if (stage > 0) { + daaHandleValid = TRUE; + } + /* get inputData0 */ + returnCode = TPM_SizedBuffer_Load(&inputData0, &command, ¶mSize); + } + /* get inputData1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inputData1, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DAASign: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Use ownerAuth to verify that the Owner authorized all TPM_DAA_Sign input parameters. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* + Common to most or all stages + */ + /* Validate the DAA session handle after stage 0, stage 0 assigns the handle */ + if (returnCode == TPM_SUCCESS) { + if (stage > 0) { + returnCode = + TPM_DaaSessions_GetEntry(&tpm_daa_session_data, /* returns entry in array */ + tpm_state->tpm_stclear_data.daaSessions, /* array */ + daaHandle); + } + } + /* Verify that the input state is consistent with the current TPM state */ + if (returnCode == TPM_SUCCESS) { + if (stage > 0) { + returnCode = TPM_DaaSessionData_CheckStage(tpm_daa_session_data, stage); + } + } + /* Verify that DAA_session -> DAA_digestContext == SHA-1(DAA_tpmSpecific) and return error + TPM_DAA_TPM_SETTINGS on mismatch */ + if (returnCode == TPM_SUCCESS) { + if (stage >= 2) { + returnCode = + TPM_SHA1_CheckStructure(tpm_daa_session_data->DAA_session.DAA_digestContext, + &(tpm_daa_session_data->DAA_tpmSpecific), + (TPM_STORE_FUNCTION_T)TPM_DAATpm_Store, + TPM_DAA_TPM_SETTINGS); + } + } + /* Verify that DAA_tpmSpecific -> DAA_digestIssuer == SHA-1(DAA_issuerSettings) and return error + TPM_DAA_ISSUER_SETTINGS on mismatch */ + if (returnCode == TPM_SUCCESS) { + if (stage >= 2) { + returnCode = + TPM_SHA1_CheckStructure(tpm_daa_session_data->DAA_tpmSpecific.DAA_digestIssuer, + &(tpm_daa_session_data->DAA_issuerSettings), + (TPM_STORE_FUNCTION_T)TPM_DAAIssuer_Store, + TPM_DAA_ISSUER_SETTINGS); + } + } + /* Stages */ + if (returnCode == TPM_SUCCESS) { + switch (stage) { + case 0 : + returnCode = TPM_DAASign_Stage00(tpm_state, + &tpm_daa_session_data, /* returns entry in array */ + &daaHandleValid, + &outputData, + &inputData0); + if (daaHandleValid) { + /* For stage 0, daaHandle may be generated. Extract it from the DAA session and + mark it valid, so the session can be terminated on error. */ + daaHandle = tpm_daa_session_data->daaHandle; + } + break; + case 1 : + returnCode = TPM_DAASign_Stage01(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 2 : + returnCode = TPM_DAAJoin_Stage09_Sign_Stage2(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 3 : + returnCode = TPM_DAAJoin_Stage10_Sign_Stage3(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 4 : + returnCode = TPM_DAAJoin_Stage11_Sign_Stage4(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 5 : + returnCode = TPM_DAASign_Stage05(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 6 : + returnCode = TPM_DAAJoin_Stage13_Sign_Stage6(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 7 : + returnCode = TPM_DAAJoin_Stage14_Sign_Stage7(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 8 : + returnCode = TPM_DAAJoin_Stage15_Sign_Stage8(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 9 : + returnCode = TPM_DAAJoin_Stage16_Sign_Stage9(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 10 : + returnCode = TPM_DAASign_Stage10(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0, &inputData1); + break; + case 11 : + returnCode = TPM_DAAJoin_Stage17_Sign_Stage11(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 12 : + returnCode = TPM_DAAJoin_Stage18_Sign_Stage12(tpm_state, + tpm_daa_session_data, + &outputData); + break; + case 13 : + returnCode = TPM_DAASign_Stage13(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 14 : + returnCode = TPM_DAASign_Stage14(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + case 15 : + returnCode = TPM_DAASign_Stage15(tpm_state, + tpm_daa_session_data, + &outputData, + &inputData0); + break; + default : + printf("TPM_Process_DAASign: Error, Illegal stage\n"); + returnCode = TPM_DAA_STAGE; + } + } + /* + Common to most or all stages + */ + if (returnCode == TPM_SUCCESS) { + tpm_daa_session_data->DAA_session.DAA_stage++; + } + /* 15.j. Terminate the DAA session and all resources associated with the DAA sign session + handle. */ + if (returnCode == TPM_SUCCESS) { + if (stage == 15) { + printf("TPM_Process_DAASign: Stage 15, terminating DAA session %08x\n", + tpm_daa_session_data->daaHandle); + TPM_DaaSessionData_Delete(tpm_daa_session_data); + } + } + /* 2. Any error return results in the TPM invalidating all resources associated with the + join */ + /* NOTE Done after response processing */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DAASign: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return outputData */ + returnCode = TPM_SizedBuffer_Store(response, &outputData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + /* no outParam's, set authorization response data */ + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* on error, terminate the DAA session */ + if (((rcf != 0) || (returnCode != TPM_SUCCESS)) && daaHandleValid) { + TPM_DaaSessions_TerminateHandle(tpm_state->tpm_stclear_data.daaSessions, + daaHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inputData0); /* @1 */ + TPM_SizedBuffer_Delete(&inputData1); /* @2 */ + TPM_SizedBuffer_Delete(&outputData); /* @3 */ + return rcf; +} diff --git a/src/tpm_daa.h b/src/tpm_daa.h new file mode 100644 index 00000000..ae37a342 --- /dev/null +++ b/src/tpm_daa.h @@ -0,0 +1,405 @@ +/********************************************************************************/ +/* */ +/* DAA Functions */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_daa.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_DAA_H +#define TPM_DAA_H + +#include "tpm_global.h" +#include "tpm_store.h" + +/* + TPM_DAA_SESSION_DATA (the entire array) +*/ + + +void TPM_DaaSessions_Init(TPM_DAA_SESSION_DATA *daaSessions); +TPM_RESULT TPM_DaaSessions_Load(TPM_DAA_SESSION_DATA *daaSessions, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DaaSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_DAA_SESSION_DATA *daaSessions); +void TPM_DaaSessions_Delete(TPM_DAA_SESSION_DATA *daaSessions); + +void TPM_DaaSessions_IsSpace(TPM_BOOL *isSpace, + uint32_t *index, + TPM_DAA_SESSION_DATA *daaSessions); +void TPM_DaaSessions_GetSpace(uint32_t *space, + TPM_DAA_SESSION_DATA *daaSessions); +TPM_RESULT TPM_DaaSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_DAA_SESSION_DATA *daaSessions); +TPM_RESULT TPM_DaaSessions_GetNewHandle(TPM_DAA_SESSION_DATA **tpm_daa_session_data, + TPM_HANDLE *daaHandle, + TPM_BOOL *daaHandleValid, + TPM_DAA_SESSION_DATA *daaSessions); +TPM_RESULT TPM_DaaSessions_GetEntry(TPM_DAA_SESSION_DATA **tpm_daa_session_data, + TPM_DAA_SESSION_DATA *daaSessions, + TPM_HANDLE daaHandle); +TPM_RESULT TPM_DaaSessions_AddEntry(TPM_HANDLE *tpm_handle, + TPM_BOOL keepHandle, + TPM_DAA_SESSION_DATA *daaSessions, + TPM_DAA_SESSION_DATA *tpm_daa_session_data); +TPM_RESULT TPM_DaaSessions_TerminateHandle(TPM_DAA_SESSION_DATA *daaSessions, + TPM_HANDLE daaHandle); + + +/* + TPM_DAA_SESSION_DATA (one element of the array) +*/ + +void TPM_DaaSessionData_Init(TPM_DAA_SESSION_DATA *tpm_daa_session_data); +TPM_RESULT TPM_DaaSessionData_Load(TPM_DAA_SESSION_DATA *tpm_daa_session_data, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DaaSessionData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_SESSION_DATA *tpm_daa_session_data); +void TPM_DaaSessionData_Delete(TPM_DAA_SESSION_DATA *tpm_daa_session_data); + +void TPM_DaaSessionData_Copy(TPM_DAA_SESSION_DATA *dest_daa_session_data, + TPM_HANDLE tpm_handle, + TPM_DAA_SESSION_DATA *src_daa_session_data); +TPM_RESULT TPM_DaaSessionData_CheckStage(TPM_DAA_SESSION_DATA *tpm_daa_session_data, + BYTE stage); + +/* + TPM_DAA_ISSUER +*/ + +void TPM_DAAIssuer_Init(TPM_DAA_ISSUER *tpm_daa_issuer); +TPM_RESULT TPM_DAAIssuer_Load(TPM_DAA_ISSUER *tpm_daa_issuer, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAAIssuer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_ISSUER *tpm_daa_issuer); +void TPM_DAAIssuer_Delete(TPM_DAA_ISSUER *tpm_daa_issuer); + +void TPM_DAAIssuer_Copy(TPM_DAA_ISSUER *dest_daa_issuer, + TPM_DAA_ISSUER *src_daa_issuer); + +/* + TPM_DAA_TPM +*/ + +void TPM_DAATpm_Init(TPM_DAA_TPM *tpm_daa_tpm); +TPM_RESULT TPM_DAATpm_Load(TPM_DAA_TPM *tpm_daa_tpm, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAATpm_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_TPM *tpm_daa_tpm); +void TPM_DAATpm_Delete(TPM_DAA_TPM *tpm_daa_tpm); + +void TPM_DAATpm_Copy(TPM_DAA_TPM *dest_daa_tpm, TPM_DAA_TPM *src_daa_tpm); + +/* + TPM_DAA_CONTEXT +*/ + +void TPM_DAAContext_Init(TPM_DAA_CONTEXT *tpm_daa_context); +TPM_RESULT TPM_DAAContext_Load(TPM_DAA_CONTEXT *tpm_daa_context, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAAContext_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_CONTEXT *tpm_daa_context); +void TPM_DAAContext_Delete(TPM_DAA_CONTEXT *tpm_daa_context); + +void TPM_DAAContext_Copy(TPM_DAA_CONTEXT *dest_daa_context, TPM_DAA_CONTEXT *src_daa_context); + +/* + TPM_DAA_JOINDATA +*/ + +void TPM_DAAJoindata_Init(TPM_DAA_JOINDATA *tpm_daa_joindata); +TPM_RESULT TPM_DAAJoindata_Load(TPM_DAA_JOINDATA *tpm_daa_joindata, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAAJoindata_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_JOINDATA *tpm_daa_joindata); +void TPM_DAAJoindata_Delete(TPM_DAA_JOINDATA *tpm_daa_joindata); + +void TPM_DAAJoindata_Copy(TPM_DAA_JOINDATA *dest_daa_joindata, + TPM_DAA_JOINDATA *src_daa_joindata); + +/* + TPM_DAA_BLOB +*/ + +void TPM_DAABlob_Init(TPM_DAA_BLOB *tpm_daa_blob); +TPM_RESULT TPM_DAABlob_Load(TPM_DAA_BLOB *tpm_daa_blob, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAABlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_BLOB *tpm_daa_blob); +void TPM_DAABlob_Delete(TPM_DAA_BLOB *tpm_daa_blob); + +/* + TPM_DAA_SENSITIVE +*/ + +void TPM_DAASensitive_Init(TPM_DAA_SENSITIVE *tpm_daa_sensitive); +TPM_RESULT TPM_DAASensitive_Load(TPM_DAA_SENSITIVE *tpm_daa_sensitive, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DAASensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DAA_SENSITIVE *tpm_daa_sensitive); +void TPM_DAASensitive_Delete(TPM_DAA_SENSITIVE *tpm_daa_sensitive); + +/* + Stage Common Code +*/ + +TPM_RESULT TPM_DAADigestContext_GenerateDigestJoin(TPM_DIGEST tpm_digest, + TPM_DAA_SESSION_DATA *tpm_daa_session_data); +TPM_RESULT TPM_DAADigestContext_CheckDigestJoin(TPM_DAA_SESSION_DATA *tpm_daa_session_data); + +TPM_RESULT TPM_DAASession_CheckStage(TPM_DAA_SESSION_DATA *tpm_daa_session_data, + BYTE stage); +TPM_RESULT TPM_ComputeF(TPM_BIGNUM *fBignum, + TPM_DAA_SESSION_DATA *tpm_daa_session_data); +TPM_RESULT TPM_ComputeAexpPmodn(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM *rBignum, + TPM_BIGNUM xBignum, + TPM_BIGNUM fBignum, + TPM_BIGNUM nBignum); +TPM_RESULT TPM_ComputeZxAexpPmodn(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM zBignum, + TPM_BIGNUM aBignum, + TPM_BIGNUM pBignum, + TPM_BIGNUM nBignum); +TPM_RESULT TPM_ComputeApBmodn(TPM_BIGNUM *rBignum, + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM nBignum); +TPM_RESULT TPM_ComputeApBxC(TPM_BIGNUM *rBignum, + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM cBignum); +TPM_RESULT TPM_ComputeApBxCpD(TPM_BIGNUM *rBignum, + TPM_BIGNUM aBignum, + TPM_BIGNUM bBignum, + TPM_BIGNUM cBignum, + TPM_BIGNUM dBignum); +TPM_RESULT TPM_ComputeDAAScratch(BYTE *DAA_scratch, + uint32_t DAA_scratch_size, + TPM_BIGNUM bn); +TPM_RESULT TPM_ComputeEnlarge(unsigned char **out, + uint32_t outSize, + unsigned char *in, + uint32_t inSize); +TPM_RESULT TPM_SizedBuffer_ComputeEnlarge(TPM_SIZED_BUFFER *tpm_sized_buffer, uint32_t size); +TPM_RESULT TPM_ComputeEncrypt(TPM_SIZED_BUFFER *outputData, + tpm_state_t *tpm_state, + TPM_DAA_SENSITIVE *tpm_daa_sensitive, + TPM_RESOURCE_TYPE resourceType); +TPM_RESULT TPM_ComputeDecrypt(TPM_DAA_SENSITIVE *tpm_daa_sensitive, + tpm_state_t *tpm_state, + TPM_SIZED_BUFFER *inputData, + TPM_RESOURCE_TYPE resourceType); + +TPM_RESULT TPM_SHA1_BignumGenerate(TPM_DIGEST tpm_digest, + TPM_BIGNUM bn, + uint32_t size); +TPM_RESULT TPM_SHA1_SizedBufferCheck(TPM_DIGEST tpm_digest, + TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size); + +/* + Processing Common Functions +*/ + +TPM_RESULT TPM_DAAJoin_Stage00(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA **tpm_daa_session_data, + TPM_BOOL *daaHandleValid, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage01(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage02(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage03(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage04(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage05(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage06(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage07(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage08(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage09_Sign_Stage2(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage10_Sign_Stage3(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage11_Sign_Stage4(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage12(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage13_Sign_Stage6(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAAJoin_Stage14_Sign_Stage7(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage15_Sign_Stage8(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage16_Sign_Stage9(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage17_Sign_Stage11(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); +TPM_RESULT TPM_DAAJoin_Stage18_Sign_Stage12(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); +TPM_RESULT TPM_DAAJoin_Stage19(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); +TPM_RESULT TPM_DAAJoin_Stage20(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); +TPM_RESULT TPM_DAAJoin_Stage21(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); +TPM_RESULT TPM_DAAJoin_Stage22(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage23(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAAJoin_Stage24(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData); + +TPM_RESULT TPM_DAASign_Stage00(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA **tpm_daa_session_data, + TPM_BOOL *daaHandleValid, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAASign_Stage01(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAASign_Stage05(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAASign_Stage10(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0, + TPM_SIZED_BUFFER *inputData1); +TPM_RESULT TPM_DAASign_Stage13(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAASign_Stage14(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); +TPM_RESULT TPM_DAASign_Stage15(tpm_state_t *tpm_state, + TPM_DAA_SESSION_DATA *tpm_daa_session_data, + TPM_SIZED_BUFFER *outputData, + TPM_SIZED_BUFFER *inputData0); + +/* + Processing functions +*/ + +TPM_RESULT TPM_Process_DAAJoin(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_DAASign(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +#endif diff --git a/src/tpm_debug.c b/src/tpm_debug.c new file mode 100644 index 00000000..183ec709 --- /dev/null +++ b/src/tpm_debug.c @@ -0,0 +1,100 @@ +/********************************************************************************/ +/* */ +/* TPM Debug Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_debug.c 4179 2010-11-10 20:10:24Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_commands.h" +#include "tpm_load.h" + +#include "tpm_debug.h" + + +#ifndef TPM_DEBUG + +int swallow_rc = 0; + +int tpm_swallow_printf_args(const char *format, ...) +{ + format = format; /* to silence compiler */ + return 0; +} + +#else + +/* TPM_PrintFour() prints a prefix plus 4 bytes of a buffer */ + +void TPM_PrintFour(const char *string, const unsigned char* buff) +{ + if (buff != NULL) { + printf("%s %02x %02x %02x %02x\n", + string, + buff[0], + buff[1], + buff[2], + buff[3]); + } + else { + printf("%s null\n", string); + } + return; +} + +#endif + +/* TPM_PrintAll() prints 'string', the length, and then the entire byte array + */ + +void TPM_PrintAll(const char *string, const unsigned char* buff, uint32_t length) +{ + uint32_t i; + if (buff != NULL) { + printf("%s length %u\n ", string, length); + for (i = 0 ; i < length ; i++) { + if (i && !( i % 16 )) { + printf("\n "); + } + printf("%.2X ",buff[i]); + } + printf("\n"); + } + else { + printf("%s null\n", string); + } + return; +} diff --git a/src/tpm_debug.h b/src/tpm_debug.h new file mode 100644 index 00000000..4da904ae --- /dev/null +++ b/src/tpm_debug.h @@ -0,0 +1,65 @@ +/********************************************************************************/ +/* */ +/* TPM Debug Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_debug.h 4179 2010-11-10 20:10:24Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_DEBUG_H +#define TPM_DEBUG_H + +#include "tpm_types.h" + +/* prototypes */ + +void TPM_PrintFour(const char *string, const unsigned char* buff); +void TPM_PrintAll(const char *string, const unsigned char* buff, uint32_t length); + + +#ifndef TPM_DEBUG /* if debug is turned off */ + +/* dummy function to match the printf prototype */ +int tpm_swallow_printf_args(const char *format, ...); + +/* assign to this dummy value to eliminate "statement has no effect" warnings */ +extern int swallow_rc; + +/* redefine printf to null */ +#define printf swallow_rc = swallow_rc && tpm_swallow_printf_args +#define TPM_PrintFour(arg1, arg2) + +#endif /* TPM_DEBUG */ + +#endif diff --git a/src/tpm_delegate.c b/src/tpm_delegate.c new file mode 100644 index 00000000..311a36c6 --- /dev/null +++ b/src/tpm_delegate.c @@ -0,0 +1,3944 @@ +/********************************************************************************/ +/* */ +/* Delegate Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_delegate.c 4580 2011-06-10 17:55:41Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_pcr.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_secret.h" + +#include "tpm_delegate.h" + +/* + TPM_DELEGATE_PUBLIC +*/ + +/* TPM_DelegatePublic_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegatePublic_Init(TPM_DELEGATE_PUBLIC *tpm_delegate_public) +{ + printf(" TPM_DelegatePublic_Init:\n"); + tpm_delegate_public->rowLabel = 0; + TPM_PCRInfoShort_Init(&(tpm_delegate_public->pcrInfo)); + TPM_Delegations_Init(&(tpm_delegate_public->permissions)); + tpm_delegate_public->familyID = 0; + tpm_delegate_public->verificationCount = 0; + return; +} + +/* TPM_DelegatePublic_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_DelegatePublic_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegatePublic_Load(TPM_DELEGATE_PUBLIC *tpm_delegate_public, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegatePublic_Load:\n"); + /* check the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELEGATE_PUBLIC, stream, stream_size); + } + /* load rowLabel */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_delegate_public->rowLabel), stream, stream_size); + } + /* load pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Load(&(tpm_delegate_public->pcrInfo), stream, stream_size, FALSE); + } + /* load permissions */ + if (rc == 0) { + rc = TPM_Delegations_Load(&(tpm_delegate_public->permissions), stream, stream_size); + } + /* load the familyID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_delegate_public->familyID), stream, stream_size); + } + /* load the verificationCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_delegate_public->verificationCount), stream, stream_size); + } + return rc; +} + +/* TPM_DelegatePublic_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegatePublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_PUBLIC *tpm_delegate_public) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegatePublic_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_PUBLIC); + } + /* store rowLabel */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_delegate_public->rowLabel), + sizeof(TPM_DELEGATE_LABEL)); + } + /* store pcrInfo */ + if (rc == 0) { + rc =TPM_PCRInfoShort_Store(sbuffer, &(tpm_delegate_public->pcrInfo), FALSE); + } + /* store permissions */ + if (rc == 0) { + rc = TPM_Delegations_Store(sbuffer, &(tpm_delegate_public->permissions)); + } + /* store familyID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegate_public->familyID); + } + /* store verificationCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegate_public->verificationCount); + } + return rc; +} + +/* TPM_DelegatePublic_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegatePublic_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegatePublic_Delete(TPM_DELEGATE_PUBLIC *tpm_delegate_public) +{ + printf(" TPM_DeleteDelegatePublic:\n"); + if (tpm_delegate_public != NULL) { + TPM_PCRInfoShort_Delete(&(tpm_delegate_public->pcrInfo)); + TPM_Delegations_Delete(&(tpm_delegate_public->permissions)); + TPM_DelegatePublic_Init(tpm_delegate_public); + } + return; +} + +/* TPM_DelegatePublic_Copy() copies the 'src' to the 'dest' structure + +*/ + +TPM_RESULT TPM_DelegatePublic_Copy(TPM_DELEGATE_PUBLIC *dest, + TPM_DELEGATE_PUBLIC *src) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegatePublic_Copy:\n"); + if (rc == 0) { + /* copy rowLabel */ + dest->rowLabel = src->rowLabel; + /* copy pcrInfo */ + rc = TPM_PCRInfoShort_Copy(&(dest->pcrInfo), &(src->pcrInfo)); + } + if (rc == 0) { + /* copy permissions */ + TPM_Delegations_Copy(&(dest->permissions), &(src->permissions)); + /* copy familyID */ + dest->familyID = src->familyID; + /* copy verificationCount */ + dest->verificationCount = src->verificationCount; + } + return rc; +} + +/* + TPM_DELEGATE_SENSITIVE +*/ + +/* TPM_DelegateSensitive_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegateSensitive_Init(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive) +{ + printf(" TPM_DelegateSensitive_Init:\n"); + TPM_Secret_Init(tpm_delegate_sensitive->authValue); + return; +} + +/* TPM_DelegateSensitive_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_DelegateSensitive_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegateSensitive_Load(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateSensitive_Load:\n"); + /* check the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELEGATE_SENSITIVE, stream, stream_size); + } + /* load authValue */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_delegate_sensitive->authValue, stream, stream_size); + } + return rc; +} + +/* TPM_DelegateSensitive_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateSensitive_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_SENSITIVE); + } + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_delegate_sensitive->authValue); + } + return rc; +} + +/* TPM_DelegateSensitive_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegateSensitive_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegateSensitive_Delete(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive) +{ + printf(" TPM_DeleteDelegateSensitive:\n"); + if (tpm_delegate_sensitive != NULL) { + TPM_DelegateSensitive_Init(tpm_delegate_sensitive); + } + return; +} + +/* TPM_DelegateSensitive_DecryptEncData() decrypts 'sensitiveArea' to a stream using 'delegateKey' + and then deserializes the stream to a TPM_DELEGATE_SENSITIVE +*/ + +TPM_RESULT TPM_DelegateSensitive_DecryptEncData(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive, + TPM_SIZED_BUFFER *sensitiveArea, + TPM_SYMMETRIC_KEY_TOKEN delegateKey) +{ + TPM_RESULT rc = 0; + unsigned char *s1; /* decrypted sensitive data */ + uint32_t s1_length; + unsigned char *stream; /* temp input stream */ + uint32_t stream_size; + + printf(" TPM_DelegateSensitive_DecryptEncData:\n"); + s1 = NULL; /* freed @1 */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Decrypt(&s1, /* decrypted data */ + &s1_length, /* length decrypted data */ + sensitiveArea->buffer, + sensitiveArea->size, + delegateKey); + } + if (rc == 0) { + stream = s1; + stream_size = s1_length; + rc = TPM_DelegateSensitive_Load(tpm_delegate_sensitive, &stream, &stream_size); + } + free(s1); /* @1 */ + return rc; +} + +/* + TPM_DELEGATIONS +*/ + +/* TPM_Delegations_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_Delegations_Init(TPM_DELEGATIONS *tpm_delegations) +{ + printf(" TPM_Delegations_Init:\n"); + tpm_delegations->delegateType = TPM_DEL_KEY_BITS; /* any legal value */ + tpm_delegations->per1 = 0; + tpm_delegations->per2 = 0; + return; +} + +/* TPM_Delegations_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_DeleteDelegations() to free memory +*/ + +TPM_RESULT TPM_Delegations_Load(TPM_DELEGATIONS *tpm_delegations, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Delegations_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELEGATIONS, stream, stream_size); + } + /* load delegateType */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_delegations->delegateType), stream, stream_size); + } + /* load per1 */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_delegations->per1), stream, stream_size); + } + /* load per2 */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_delegations->per2), stream, stream_size); + } + /* validate parameters */ + if (rc == 0) { + if (tpm_delegations->delegateType == TPM_DEL_OWNER_BITS) { + if (tpm_delegations->per1 & ~TPM_DELEGATE_PER1_MASK) { + printf("TPM_Delegations_Load: Error, owner per1 %08x\n", tpm_delegations->per1); + rc = TPM_BAD_PARAMETER; + } + if (tpm_delegations->per2 & ~TPM_DELEGATE_PER2_MASK) { + printf("TPM_Delegations_Load: Error, owner per2 %08x\n", tpm_delegations->per2); + rc = TPM_BAD_PARAMETER; + } + } + else if (tpm_delegations->delegateType == TPM_DEL_KEY_BITS) { + if (tpm_delegations->per1 & ~TPM_KEY_DELEGATE_PER1_MASK) { + printf("TPM_Delegations_Load: Error, key per1 %08x\n", tpm_delegations->per1); + rc = TPM_BAD_PARAMETER; + } + if (tpm_delegations->per2 & ~TPM_KEY_DELEGATE_PER2_MASK) { + printf("TPM_Delegations_Load: Error, key per2 %08x\n", tpm_delegations->per2); + rc = TPM_BAD_PARAMETER; + } + } + else { + printf("TPM_Delegations_Load: Error, delegateType %08x\n", + tpm_delegations->delegateType); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_Delegations_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_Delegations_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATIONS *tpm_delegations) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Delegations_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATIONS); + } + /* store delegateType */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegations->delegateType); + } + /* store per1 */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegations->per1); + } + /* store per2 */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_delegations->per2); + } + return rc; +} + +/* TPM_Delegations_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_Delegations_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_Delegations_Delete(TPM_DELEGATIONS *tpm_delegations) +{ + printf(" TPM_Delegations_Delete:\n"); + if (tpm_delegations != NULL) { + TPM_Delegations_Init(tpm_delegations); + } + return; +} + +/* TPM_Delegations_Copy() copies the source to the destination + */ + +void TPM_Delegations_Copy(TPM_DELEGATIONS *dest, + TPM_DELEGATIONS *src) +{ + dest->delegateType = src->delegateType; + dest->per1 = src->per1; + dest->per2 = src->per2; + return; +} + +/* TPM_Delegations_CheckPermissionDelegation() verifies that the new delegation bits do not grant + more permissions then currently delegated. Otherwise return error TPM_AUTHFAIL. + + An error occurs if a bit is set in newDelegations -> per and clear in currentDelegations -> per +*/ + +TPM_RESULT TPM_Delegations_CheckPermissionDelegation(TPM_DELEGATIONS *newDelegations, + TPM_DELEGATIONS *currentDelegations) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Delegations_CheckPermissionDelegation:\n"); + /* check per1 */ + if (rc == 0) { + if (newDelegations->per1 & ~currentDelegations->per1) { + printf("TPM_Delegations_CheckPermissionDelegation: Error, " + "new per1 %08x current per1 %08x\n", + newDelegations->per1, currentDelegations->per1); + rc = TPM_AUTHFAIL; + } + } + /* check per2 */ + if (rc == 0) { + if (newDelegations->per2 & ~currentDelegations->per2) { + printf("TPM_Delegations_CheckPermissionDelegation: Error, " + "new per1 %08x current per1 %08x\n", + newDelegations->per1, currentDelegations->per1); + rc = TPM_AUTHFAIL; + } + } + return rc; +} + +/* TPM_Delegations_CheckPermission() verifies that the 'ordinal' has been delegated for execution + based on the TPM_DELEGATE_PUBLIC. + + It verifies that the TPM_DELEGATIONS is appropriate for the entityType. Currently, only key or + owner authorization can be delegated. + + It verifies that the TPM_DELEGATE_PUBLIC PCR's allow the delegation. +*/ + +TPM_RESULT TPM_Delegations_CheckPermission(tpm_state_t *tpm_state, + TPM_DELEGATE_PUBLIC *delegatePublic, + TPM_ENT_TYPE entityType, /* required */ + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Delegations_CheckPermission: ordinal %08x\n", ordinal); + if (rc == 0) { + switch (entityType) { + case TPM_ET_KEYHANDLE: + rc = TPM_Delegations_CheckKeyPermission(&(delegatePublic->permissions), ordinal); + break; + case TPM_ET_OWNER: + rc = TPM_Delegations_CheckOwnerPermission(&(delegatePublic->permissions), ordinal); + break; + default: + printf("TPM_Delegations_CheckPermission: Error, " + "DSAP session does not support entity type %02x\n", + entityType); + rc = TPM_AUTHFAIL; + break; + } + } + /* check that the TPM_DELEGATE_PUBLIC PCR's allow the delegation */ + if (rc == 0) { + rc = TPM_PCRInfoShort_CheckDigest(&(delegatePublic->pcrInfo), + tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.localityModifier); + } + return rc; +} + +/* TPM_Delegations_CheckOwnerPermission() verifies that the 'ordinal' has been delegated for + execution based on the TPM_DELEGATIONS. +*/ + +TPM_RESULT TPM_Delegations_CheckOwnerPermission(TPM_DELEGATIONS *tpm_delegations, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + uint16_t ownerPermissionBlock; /* 0:unused, 1:per1 2:per2 */ + uint32_t ownerPermissionPosition; /* owner permission bit position */ + + printf(" TPM_Delegations_CheckOwnerPermission: ordinal %08x\n", ordinal); + /* check that the TPM_DELEGATIONS structure is the correct type */ + if (rc == 0) { + if (tpm_delegations->delegateType != TPM_DEL_OWNER_BITS) { + printf("TPM_Delegations_CheckOwnerPermission: Error," + "Ordinal requires owner auth but delegateType is %08x\n", + tpm_delegations->delegateType); + rc = TPM_AUTHFAIL; + } + } + /* get the block and position in the block from the ordinals table */ + if (rc == 0) { + rc = TPM_OrdinalTable_GetOwnerPermission(&ownerPermissionBlock, + &ownerPermissionPosition, + ordinal); + } + /* check that the permission bit is set in the TPM_DELEGATIONS bit map */ + if (rc == 0) { + printf(" TPM_Delegations_CheckOwnerPermission: block %u position %u\n", + ownerPermissionBlock, ownerPermissionPosition); + switch (ownerPermissionBlock) { + case 1: /* per1 */ + if (!(tpm_delegations->per1 & (1 << ownerPermissionPosition))) { + printf("TPM_Delegations_CheckOwnerPermission: Error, per1 %08x\n", + tpm_delegations->per1); + rc = TPM_AUTHFAIL; + } + break; + case 2: /* per2 */ + if (!(tpm_delegations->per2 & (1 << ownerPermissionPosition))) { + printf("TPM_Delegations_CheckOwnerPermission: Error, per2 %08x\n", + tpm_delegations->per2); + rc = TPM_AUTHFAIL; + } + break; + default: + printf("TPM_Delegations_CheckOwnerPermission: Error, block not 1 or 2\n"); + rc = TPM_AUTHFAIL; + break; + } + } + return rc; +} + +/* TPM_Delegations_CheckKeyPermission() verifies that the 'ordinal' has been delegated for + execution based on the TPM_DELEGATIONS. +*/ + +TPM_RESULT TPM_Delegations_CheckKeyPermission(TPM_DELEGATIONS *tpm_delegations, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + uint16_t keyPermissionBlock; /* 0:unused, 1:per1 2:per2 */ + uint32_t keyPermissionPosition; /* key permission bit position */ + + printf(" TPM_Delegations_CheckKeyPermission: ordinal %08x\n", ordinal); + /* check that the TPM_DELEGATIONS structure is the correct type */ + if (rc == 0) { + if (tpm_delegations->delegateType != TPM_DEL_KEY_BITS) { + printf("TPM_Delegations_CheckKeyPermission: Error," + "Ordinal requires key auth but delegateType is %08x\n", + tpm_delegations->delegateType); + rc = TPM_AUTHFAIL; + } + } + /* get the block and position in the block from the ordinals table */ + if (rc == 0) { + rc = TPM_OrdinalTable_GetKeyPermission(&keyPermissionBlock, + &keyPermissionPosition, + ordinal); + } + /* check that the permission bit is set in the TPM_DELEGATIONS bit map */ + if (rc == 0) { + printf(" TPM_Delegations_CheckKeyPermission: block %u position %u\n", + keyPermissionBlock, keyPermissionPosition); + switch (keyPermissionBlock) { + case 1: /* per1 */ + if (!(tpm_delegations->per1 & (1 << keyPermissionPosition))) { + printf("TPM_Delegations_CheckKeyPermission: Error, per1 %08x\n", + tpm_delegations->per1); + rc = TPM_AUTHFAIL; + } + break; + case 2: /* per2 */ + if (!(tpm_delegations->per2 & (1 << keyPermissionPosition))) { + printf("TPM_Delegations_CheckKeyPermission: Error, per2 %08x\n", + tpm_delegations->per2); + rc = TPM_AUTHFAIL; + } + break; + default: + printf("TPM_Delegations_CheckKeyPermission: Error, block not 1 or 2\n"); + rc = TPM_AUTHFAIL; + break; + } + } + return rc; +} + +/* + TPM_DELEGATE_OWNER_BLOB +*/ + +/* TPM_DelegateOwnerBlob_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegateOwnerBlob_Init(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob) +{ + printf(" TPM_DelegateOwnerBlob_Init:\n"); + TPM_DelegatePublic_Init(&(tpm_delegate_owner_blob->pub)); + TPM_Digest_Init(tpm_delegate_owner_blob->integrityDigest); + TPM_SizedBuffer_Init(&(tpm_delegate_owner_blob->additionalArea)); + TPM_SizedBuffer_Init(&(tpm_delegate_owner_blob->sensitiveArea)); + return; +} + +/* TPM_DelegateOwnerBlob_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DelegateOwnerBlob_Init() + After use, call TPM_DelegateOwnerBlob_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegateOwnerBlob_Load(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateOwnerBlob_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELEGATE_OWNER_BLOB, stream, stream_size); + } + /* load pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Load(&(tpm_delegate_owner_blob->pub), stream, stream_size); + } + /* check that permissions are owner */ + if (rc == 0) { + if (tpm_delegate_owner_blob->pub.permissions.delegateType != TPM_DEL_OWNER_BITS) { + printf("TPM_DelegateOwnerBlob_Load: Error, delegateType expected %08x found %08x\n", + TPM_DEL_OWNER_BITS, tpm_delegate_owner_blob->pub.permissions.delegateType); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_delegate_owner_blob->integrityDigest, stream, stream_size); + } + /* load additionalArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_delegate_owner_blob->additionalArea), stream, stream_size); + } + /* load sensitiveArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_delegate_owner_blob->sensitiveArea), stream, stream_size); + } + return rc; +} + +/* TPM_DelegateOwnerBlob_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateOwnerBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateOwnerBlob_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_OWNER_BLOB); + } + /* store pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_owner_blob->pub)); + } + /* store integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_delegate_owner_blob->integrityDigest); + } + /* store additionalArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_owner_blob->additionalArea)); + } + /* store sensitiveArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_owner_blob->sensitiveArea)); + } + return rc; +} + +/* TPM_DelegateOwnerBlob_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegateOwnerBlob_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegateOwnerBlob_Delete(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob) +{ + printf(" TPM_DelegateOwnerBlob_Delete:\n"); + if (tpm_delegate_owner_blob != NULL) { + TPM_DelegatePublic_Delete(&(tpm_delegate_owner_blob->pub)); + TPM_SizedBuffer_Delete(&(tpm_delegate_owner_blob->additionalArea)); + TPM_SizedBuffer_Delete(&(tpm_delegate_owner_blob->sensitiveArea)); + TPM_DelegateOwnerBlob_Init(tpm_delegate_owner_blob); + } + return; +} + +/* + TPM_DELEGATE_KEY_BLOB +*/ + +/* TPM_DelegateKeyBlob_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegateKeyBlob_Init(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob) +{ + printf(" TPM_DelegateKeyBlob_Init:\n"); + TPM_DelegatePublic_Init(&(tpm_delegate_key_blob->pub)); + TPM_Digest_Init(tpm_delegate_key_blob->integrityDigest); + TPM_Digest_Init(tpm_delegate_key_blob->pubKeyDigest); + TPM_SizedBuffer_Init(&(tpm_delegate_key_blob->additionalArea)); + TPM_SizedBuffer_Init(&(tpm_delegate_key_blob->sensitiveArea)); + return; +} + +/* TPM_DelegateKeyBlob_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DelegateKeyBlob_Init() + After use, call TPM_DelegateKeyBlob_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegateKeyBlob_Load(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateKeyBlob_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELG_KEY_BLOB, stream, stream_size); + } + /* load pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Load(&(tpm_delegate_key_blob->pub), stream, stream_size); + } + /* check that permissions are key */ + if (rc == 0) { + if (tpm_delegate_key_blob->pub.permissions.delegateType != TPM_DEL_KEY_BITS) { + printf("TPM_DelegateKeyBlob_Load: Error, delegateType expected %08x found %08x\n", + TPM_DEL_KEY_BITS, tpm_delegate_key_blob->pub.permissions.delegateType); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_delegate_key_blob->integrityDigest, stream, stream_size); + } + /* load pubKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_delegate_key_blob->pubKeyDigest, stream, stream_size); + } + /* load additionalArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_delegate_key_blob->additionalArea), stream, stream_size); + } + /* load sensitiveArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_delegate_key_blob->sensitiveArea), stream, stream_size); + } + return rc; +} + +/* TPM_DelegateKeyBlob_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateKeyBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateKeyBlob_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELG_KEY_BLOB); + } + /* store pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_key_blob->pub)); + } + /* store integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_delegate_key_blob->integrityDigest); + } + /* store pubKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_delegate_key_blob->pubKeyDigest); + } + /* store additionalArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_key_blob->additionalArea)); + } + /* store sensitiveArea */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_delegate_key_blob->sensitiveArea)); + } + return rc; +} + +/* TPM_DelegateKeyBlob_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegateKeyBlob_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegateKeyBlob_Delete(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob) +{ + printf(" TPM_DelegateKeyBlob_Delete:\n"); + if (tpm_delegate_key_blob != NULL) { + TPM_DelegatePublic_Delete(&(tpm_delegate_key_blob->pub)); + TPM_SizedBuffer_Delete(&(tpm_delegate_key_blob->additionalArea)); + TPM_SizedBuffer_Delete(&(tpm_delegate_key_blob->sensitiveArea)); + TPM_DelegateKeyBlob_Init(tpm_delegate_key_blob); + } + return; +} + +/* + TPM_FAMILY_TABLE +*/ + +/* TPM_FamilyTable_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_FamilyTable_Init(TPM_FAMILY_TABLE *tpm_family_table) +{ + size_t i; + + printf(" TPM_FamilyTable_Init: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + for (i = 0 ; i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN ; i++) { + TPM_FamilyTableEntry_Init(&(tpm_family_table->famTableRow[i])); + } + return; +} + +/* TPM_FamilyTable_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_FamilyTable_Init() + After use, call TPM_FamilyTable_Delete() to free memory +*/ + +TPM_RESULT TPM_FamilyTable_Load(TPM_FAMILY_TABLE *tpm_family_table, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_FamilyTable_Load: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) ; i++) { + rc = TPM_FamilyTableEntry_Load(&(tpm_family_table->famTableRow[i]), + stream, + stream_size); + } + return rc; +} + +/* TPM_FamilyTable_Store() + + If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_FamilyTable_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE *tpm_family_table, + TPM_BOOL store_tag) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_FamilyTable_Store: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) ; i++) { + rc = TPM_FamilyTableEntry_Store(sbuffer, + &(tpm_family_table->famTableRow[i]), store_tag); + } + return rc; +} + +/* TPM_FamilyTable_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_FamilyTable_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_FamilyTable_Delete(TPM_FAMILY_TABLE *tpm_family_table) +{ + size_t i; + + printf(" TPM_FamilyTable_Delete: Qty %u\n", TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + if (tpm_family_table != NULL) { + for (i = 0 ; i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN ; i++) { + TPM_FamilyTableEntry_Delete(&(tpm_family_table->famTableRow[i])); + } + TPM_FamilyTable_Init(tpm_family_table); + } + return; +} + +/* TPM_FamilyTable_GetEntry() searches all entries for the entry matching the familyID, and returns + the TPM_FAMILY_TABLE_ENTRY associated with the familyID. + + Returns + 0 for success + TPM_BADINDEX if the familyID is not found +*/ + +TPM_RESULT TPM_FamilyTable_GetEntry(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, /* output */ + TPM_FAMILY_TABLE *tpm_family_table, + TPM_FAMILY_ID familyID) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_FamilyTable_GetEntry: familyID %08x\n", familyID); + for (i = 0, found = FALSE ; (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) && !found ; i++) { + if (tpm_family_table->famTableRow[i].valid && + (tpm_family_table->famTableRow[i].familyID == familyID)) { /* found */ + found = TRUE; + *tpm_family_table_entry = &(tpm_family_table->famTableRow[i]); + } + } + if (!found) { + printf("TPM_FamilyTable_GetEntry: Error, familyID %08x not found\n", familyID); + rc = TPM_BADINDEX; + } + return rc; +} + +/* TPM_FamilyTable_GetEnabledEntry() searches all entries for the entry matching the familyID, and + returns the TPM_FAMILY_TABLE_ENTRY associated with the familyID. + + Similar to TPM_FamilyTable_GetEntry() but returns an error if the entry is disabled. + + Returns + 0 for success + TPM_BADINDEX if the familyID is not found + TPM_DISABLED_CMD if the TPM_FAMILY_TABLE_ENTRY -> TPM_FAMFLAG_ENABLED is FALSE +*/ + +TPM_RESULT TPM_FamilyTable_GetEnabledEntry(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, + TPM_FAMILY_TABLE *tpm_family_table, + TPM_FAMILY_ID familyID) +{ + TPM_RESULT rc = 0; + + printf(" TPM_FamilyTable_GetEnabledEntry: familyID %08x\n", familyID); + if (rc == 0) { + rc = TPM_FamilyTable_GetEntry(tpm_family_table_entry, + tpm_family_table, + familyID); + } + if (rc == 0) { + if (!((*tpm_family_table_entry)->flags & TPM_FAMFLAG_ENABLED)) { + printf("TPM_FamilyTable_GetEnabledEntry: Error, family %08x disabled\n", familyID); + rc = TPM_DISABLED_CMD; + } + } + return rc; +} + +/* TPM_FamilyTable_IsSpace() returns success if an entry is available, an error if not. + + If success, 'family_table_entry' holds the first free family table row. +*/ + +TPM_RESULT TPM_FamilyTable_IsSpace(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, /* output */ + TPM_FAMILY_TABLE *tpm_family_table) +{ + size_t i; + TPM_BOOL isSpace; + TPM_RESULT rc = 0; + + + printf(" TPM_FamilyTable_IsSpace:\n"); + for (i = 0, isSpace = FALSE ; i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN; i++) { + *tpm_family_table_entry = &(tpm_family_table->famTableRow[i]); + if (!((*tpm_family_table_entry)->valid)) { + printf(" TPM_FamilyTable_IsSpace: Found space at %lu\n", (unsigned long)i); + isSpace = TRUE; + break; + } + } + if (!isSpace) { + printf(" TPM_FamilyTable_IsSpace: Error, no space found\n"); + rc = TPM_RESOURCES; + } + return rc; +} + +/* TPM_FamilyTable_StoreValid() stores only the valid (occupied) entries + + If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_FamilyTable_StoreValid(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE *tpm_family_table, + TPM_BOOL store_tag) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_FamilyTable_StoreValid: \n"); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_FAMILY_TABLE_ENTRY_MIN) ; i++) { + /* store only the valid rows */ + if (tpm_family_table->famTableRow[i].valid) { + /* store only the publicly visible members */ + printf(" TPM_FamilyTable_StoreValid: Entry %lu is valid\n", (unsigned long)i); + printf(" TPM_FamilyTable_StoreValid: Entry family ID is %08x\n", + tpm_family_table->famTableRow[i].familyID); + rc = TPM_FamilyTableEntry_StorePublic(sbuffer, + &(tpm_family_table->famTableRow[i]), store_tag); + } + } + return rc; +} + +/* + TPM_FAMILY_TABLE_ENTRY +*/ + +/* TPM_FamilyTableEntry_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_FamilyTableEntry_Init(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry) +{ + printf(" TPM_FamilyTableEntry_Init:\n"); + tpm_family_table_entry->familyLabel = 0; + tpm_family_table_entry->familyID = 0; + tpm_family_table_entry->verificationCount = 0; + tpm_family_table_entry->flags = 0; + tpm_family_table_entry->valid = FALSE; + return; +} + +/* TPM_FamilyTableEntry_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_FamilyTableEntry_Init() + After use, call TPM_FamilyTableEntry_Delete() to free memory +*/ + +TPM_RESULT TPM_FamilyTableEntry_Load(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_FamilyTableEntry_Load:\n"); + /* load tag */ + /* the tag is not serialized when storing TPM_PERMANENT_DATA, to save NV space */ + /* load familyLabel */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_family_table_entry->familyLabel), stream, stream_size); + } + /* load familyID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_family_table_entry->familyID), stream, stream_size); + } + /* load verificationCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_family_table_entry->verificationCount), stream, stream_size); + } + /* load flags */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_family_table_entry->flags), stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_family_table_entry->valid), stream, stream_size); + } + if (rc == 0) { + printf(" TPM_FamilyTableEntry_Load: label %02x familyID %08x valid %u\n", + tpm_family_table_entry->familyLabel, + tpm_family_table_entry->familyID, + tpm_family_table_entry->valid); + } + return rc; +} + +/* TPM_FamilyTableEntry_Store() stores all members of the structure + + If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_FamilyTableEntry_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + TPM_BOOL store_tag) +{ + TPM_RESULT rc = 0; + + printf(" TPM_FamilyTableEntry_Store:\n"); + /* store public, visible members */ + if (rc == 0) { + rc = TPM_FamilyTableEntry_StorePublic(sbuffer, tpm_family_table_entry, store_tag); + } + /* store valid */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_family_table_entry->valid), + sizeof(TPM_BOOL)); + } + return rc; +} + +/* TPM_FamilyTableEntry_StorePublic() stores only the public, visible members of the structure + + If store_tag is TRUE, the TPM_FAMILY_TABLE_ENTRY tag is stored. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_FamilyTableEntry_StorePublic(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + TPM_BOOL store_tag) +{ + TPM_RESULT rc = 0; + + printf(" TPM_FamilyTableEntry_StorePublic:\n"); + /* store tag */ + if ((rc == 0) && (store_tag)) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_FAMILY_TABLE_ENTRY); + } + /* store familyLabel */ + if (rc == 0) { + TPM_Sbuffer_Append(sbuffer, &(tpm_family_table_entry->familyLabel), + sizeof(TPM_FAMILY_LABEL)); + } + /* store familyID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_family_table_entry->familyID); + } + /* store verificationCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_family_table_entry->verificationCount); + } + /* store flags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_family_table_entry->flags); + } + return rc; +} + +/* TPM_FamilyTableEntry_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_FamilyTableEntry_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_FamilyTableEntry_Delete(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry) +{ + printf(" TPM_FamilyTableEntry_Delete:\n"); + if (tpm_family_table_entry != NULL) { + TPM_FamilyTableEntry_Init(tpm_family_table_entry); + } + return; +} + +/* + TPM_DELEGATE_TABLE +*/ + +/* TPM_DelegateTable_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegateTable_Init(TPM_DELEGATE_TABLE *tpm_delegate_table) +{ + size_t i; + + printf(" TPM_DelegateTable_Init: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + for (i = 0 ; i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN ; i++) { + TPM_DelegateTableRow_Init(&(tpm_delegate_table->delRow[i])); + } + return; +} + +/* TPM_DelegateTable_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DelegateTable_Init() + After use, call TPM_DelegateTable_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegateTable_Load(TPM_DELEGATE_TABLE *tpm_delegate_table, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_DelegateTable_Load: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) ; i++) { + rc = TPM_DelegateTableRow_Load(&(tpm_delegate_table->delRow[i]), + stream, + stream_size); + } + return rc; +} + +/* TPM_DelegateTable_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateTable_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE *tpm_delegate_table) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_DelegateTable_Store: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) ; i++) { + rc = TPM_DelegateTableRow_Store(sbuffer, &(tpm_delegate_table->delRow[i])); + } + return rc; +} + +/* TPM_DelegateTable_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegateTable_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegateTable_Delete(TPM_DELEGATE_TABLE *tpm_delegate_table) +{ + size_t i; + + printf(" TPM_DelegateTable_Delete: Qty %u\n", TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + if (tpm_delegate_table != NULL) { + for (i = 0 ; i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN ; i++) { + TPM_DelegateTableRow_Delete(&(tpm_delegate_table->delRow[i])); + } + TPM_DelegateTable_Init(tpm_delegate_table); + } + return; +} + +/* TPM_DelegateTable_StoreValid() store only the valid (occupied) entries. Each entry is prepended + with it's index. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateTable_StoreValid(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE *tpm_delegate_table) +{ + TPM_RESULT rc = 0; + uint32_t i; + + printf(" TPM_DelegateTable_StoreValid:\n"); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) ; i++) { + /* store only the valid rows */ + if (tpm_delegate_table->delRow[i].valid) { + /* a. Write the TPM_DELEGATE_INDEX to delegateTable */ + printf(" TPM_DelegateTable_StoreValid: Entry %u is valid\n", i); + printf(" TPM_DelegateTable_StoreValid: Entry family ID is %08x\n", + tpm_delegate_table->delRow[i].pub.familyID); + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, i); + } + /* b. Copy the TPM_DELEGATE_PUBLIC to delegateTable */ + if (rc == 0) { + rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_table->delRow[i].pub)); + } + } + } + return rc; +} + +/* TPM_DelegateTable_GetRow() maps 'rowIndex' to a TPM_DELEGATE_TABLE_ROW in the delegate table. + + The row may not have valid data. + */ + +TPM_RESULT TPM_DelegateTable_GetRow(TPM_DELEGATE_TABLE_ROW **delegateTableRow, + TPM_DELEGATE_TABLE *tpm_delegate_table, + uint32_t rowIndex) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateTable_GetRow: index %u\n", rowIndex); + if (rc == 0) { + if (rowIndex >= TPM_NUM_DELEGATE_TABLE_ENTRY_MIN) { + printf("TPM_DelegateTable_GetRow: index %u out of range\n", rowIndex); + rc = TPM_BADINDEX; + } + } + if (rc == 0) { + *delegateTableRow = &(tpm_delegate_table->delRow[rowIndex]); + } + return rc; +} + +/* TPM_DelegateTable_GetValidRow() maps 'rowIndex' to a TPM_DELEGATE_TABLE_ROW in the delegate + table. + + The row must have valid data. + */ + +TPM_RESULT TPM_DelegateTable_GetValidRow(TPM_DELEGATE_TABLE_ROW **delegateTableRow, + TPM_DELEGATE_TABLE *tpm_delegate_table, + uint32_t rowIndex) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + rc = TPM_DelegateTable_GetRow(delegateTableRow, + tpm_delegate_table, + rowIndex); + } + if (rc == 0) { + *delegateTableRow = &(tpm_delegate_table->delRow[rowIndex]); + if (!(*delegateTableRow)->valid) { + printf("TPM_DelegateTable_GetValidRow: index %u invalid\n", rowIndex); + rc = TPM_BADINDEX; + } + } + return rc; +} + +/* + TPM_DELEGATE_TABLE_ROW +*/ + +/* TPM_DelegateTableRow_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_DelegateTableRow_Init(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row) +{ + printf(" TPM_DelegateTableRow_Init:\n"); + TPM_DelegatePublic_Init(&(tpm_delegate_table_row->pub)); + TPM_Secret_Init(tpm_delegate_table_row->authValue); + tpm_delegate_table_row->valid = FALSE; + return; +} + +/* TPM_DelegateTableRow_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_DelegateTableRow_Init() + After use, call TPM_DelegateTableRow_Delete() to free memory +*/ + +TPM_RESULT TPM_DelegateTableRow_Load(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateTableRow_Load:\n"); + /* check the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_DELEGATE_TABLE_ROW, stream, stream_size); + } + /* load pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Load(&(tpm_delegate_table_row->pub), stream, stream_size); + } + /* load authValue */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_delegate_table_row->authValue, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_delegate_table_row->valid), stream, stream_size); + } + return rc; +} + +/* TPM_DelegateTableRow_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_DelegateTableRow_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row) +{ + TPM_RESULT rc = 0; + + printf(" TPM_DelegateTableRow_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_DELEGATE_TABLE_ROW); + } + /* store pub */ + if (rc == 0) { + rc =TPM_DelegatePublic_Store(sbuffer, &(tpm_delegate_table_row->pub)); + } + /* store authValue */ + if (rc == 0) { + rc =TPM_Secret_Store(sbuffer, tpm_delegate_table_row->authValue); + } + /* store valid */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_delegate_table_row->valid), sizeof(TPM_BOOL)); + } + return rc; +} + +/* TPM_DelegateTableRow_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_DelegateTableRow_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_DelegateTableRow_Delete(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row) +{ + printf(" TPM_DelegateTableRow_Delete:\n"); + if (tpm_delegate_table_row != NULL) { + TPM_DelegatePublic_Delete(&(tpm_delegate_table_row->pub)); + TPM_DelegateTableRow_Init(tpm_delegate_table_row); + } + return; +} + +/* + Processing Functions +*/ + +/* 19.1 TPM_Delegate_Manage rev 115 + + TPM_Delegate_Manage is the fundamental process for managing the Family tables, including + enabling/disabling Delegation for a selected Family. Normally TPM_Delegate_Manage must be + executed at least once (to create Family tables for a particular family) before any other type of + Delegation command in that family can succeed. + + Delegate_Manage is authorized by the TPM Owner if an Owner is installed, because changing a table + is a privileged Owner operation. If no Owner is installed, Delegate_Manage requires no privilege + to execute. This does not disenfranchise an Owner, since there is no Owner, and simplifies + loading of tables during platform manufacture or on first-boot. Burn-out of TPM non-volatile + storage by inappropriate use is mitigated by the TPM's normal limits on NV-writes in the absence + of an Owner. Tables can be locked after loading, to prevent subsequent tampering, and only + unlocked by the Owner, his delegate, or the act of removing the Owner (even if there is no + Owner). + + TPM_Delegate_Manage command is customized by opcode: + + (1) TPM_FAMILY_ENABLE enables/disables use of a family and all the rows of the delegate table + belonging to that family, + + (2) TPM_FAMILY_ADMIN can be used to prevent further management of the Tables until an Owner is + installed, or until the Owner is removed from the TPM. (Note that the Physical Presence command + TPM_ForceClear always enables further management, even if TPM_ForceClear is used when no Owner is + installed.) + + (3) TPM_FAMILY_CREATE creates a new family. + + (4) TPM_FAMILY_INVALIDATE invalidates an existing family. +*/ + +TPM_RESULT TPM_Process_DelegateManage(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_FAMILY_ID familyID; /* The familyID that is to be managed */ + TPM_FAMILY_OPERATION opCode = 0; /* Operation to be performed by this command. */ + TPM_SIZED_BUFFER opData; /* Data necessary to implement opCode */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with + authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA ownerAuth; /* HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_SECRET savedAuth; /* saved copy for response */ + TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */ + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* temp for noOwnerNVWrite, initialize to + silence compiler */ + TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back data */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER retData; /* Returned data */ + + printf("TPM_Process_DelegateManage: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&opData); /* freed @1 */ + TPM_Sbuffer_Init(&retData); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get familyID parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&familyID, &command, ¶mSize); + } + /* get opCode parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: familyID %08x\n", familyID); + returnCode = TPM_Load32(&opCode, &command, ¶mSize); + } + /* get opData parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: opCode %u\n", opCode); + returnCode = TPM_SizedBuffer_Load(&opData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateManage: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. If opCode != TPM_FAMILY_CREATE */ + /* a. Locate familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row, return + TPM_BADINDEX if not found */ + /* b. Set FR, a TPM_FAMILY_TABLE_ENTRY, to TPM_FAMILY_TABLE. famTableRow[familyRow] */ + if ((returnCode == TPM_SUCCESS) && (opCode != TPM_FAMILY_CREATE)) { + printf("TPM_Process_DelegateManage: Not creating, get entry for familyID %08x\n", + familyID); + returnCode = TPM_FamilyTable_GetEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + familyID); + } + /* 2. If tag = TPM_TAG_RQU_AUTH1_COMMAND */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + /* a. Validate the command and parameters using ownerAuth, return TPM_AUTHFAIL on error */ + returnCode = + TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth),/* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + /* make a copy of the HMAC key for the response, since it MAY be invalidated */ + TPM_Secret_Copy(savedAuth, *hmacKey); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + /* b. If the command is delegated (authHandle session type is TPM_PID_DSAP or through + ownerReference delegation) */ + if ((auth_session_data->protocolID == TPM_PID_DSAP) || + (tpm_state->tpm_stclear_data.ownerReference != TPM_KH_OWNER)) { + /* i. If opCode = TPM_FAMILY_CREATE */ + /* (1) The TPM MUST ignore familyID */ + /* ii. Else */ + if (opCode != TPM_FAMILY_CREATE) { + /* get the TPM_DELEGATE_PUBLIC from the DSAP session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic, + auth_session_data); + } + /* (1) Verify that the familyID associated with authHandle matches the familyID + parameter, return TPM_DELEGATE_FAMILY on error */ + if (returnCode == TPM_SUCCESS) { + if (delegatePublic->familyID != familyID) { + printf("TPM_Process_DelegateManage: Error, familyID %08x should be %08x\n", + familyID, delegatePublic->familyID); + returnCode = TPM_DELEGATE_FAMILY; + } + } + } + } + } + /* 3. Else */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) { + /* a. If TPM_PERMANENT_DATA -> ownerAuth is valid, return TPM_AUTHFAIL */ + if (tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_DelegateManage: Error, owner installed but no authorization\n"); + returnCode = TPM_AUTHFAIL ; + } + } + /* b. If opCode != TPM_FAMILY_CREATE and FR -> flags -> TPM_DELEGATE_ADMIN_LOCK is TRUE, return + TPM_DELEGATE_LOCK */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) { + if ((opCode != TPM_FAMILY_CREATE) && (familyRow->flags & TPM_DELEGATE_ADMIN_LOCK)) { + printf("TPM_Process_DelegateManage: Error, row locked\n"); + returnCode = TPM_DELEGATE_LOCK; + } + } + /* c. Validate max NV writes without an owner */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) { + /* i. Set NV1 to TPM_PERMANENT_DATA -> noOwnerNVWrite */ + nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* ii. Increment NV1 by 1 */ + nv1++; + /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */ + if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) { + printf("TPM_Process_DelegateManage: Error, max NV writes %d w/o owner reached\n", + tpm_state->tpm_permanent_data.noOwnerNVWrite); + returnCode = TPM_MAXNVWRITES; + } + if (returnCode == TPM_SUCCESS){ + /* iv. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ + /* NOTE Don't update the noOwnerNVWrite value until determining that the write will be + performed */ + nv1Incremented = TRUE; + } + } + /* 4. The TPM invalidates sessions */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: Invalidate sessions\n"); + /* a. MUST invalidate all DSAP sessions */ + /* b. MUST invalidate all OSAP sessions associated with the delegation table */ + /* d. MAY invalidate any other session */ + TPM_AuthSessions_TerminatexSAP(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions); + /* c. MUST set TPM_STCLEAR_DATA -> ownerReference to TPM_KH_OWNER */ + tpm_state->tpm_stclear_data.ownerReference = TPM_KH_OWNER; + } + /* + 5. If opCode == TPM_FAMILY_CREATE + */ + if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_CREATE)) { + printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_CREATE\n"); + /* a. Validate that sufficient space exists within the TPM to store an additional family and + map F2 to the newly allocated space. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_IsSpace(&familyRow, /* output */ + &(tpm_state->tpm_permanent_data.familyTable)); + } + /* b. Validate that opData is a TPM_FAMILY_LABEL */ + if (returnCode == TPM_SUCCESS) { + /* i. If opDataSize != sizeof(TPM_FAMILY_LABEL) return TPM_BAD_PARAM_SIZE */ + if (opData.size != sizeof(TPM_FAMILY_LABEL)) { + printf("TPM_Process_DelegateManage: Error, invalid opDataSize %u\n", opData.size); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* c. Map F2 to a TPM_FAMILY_TABLE_ENTRY */ + /* NOTE Done by TPM_FamilyTable_IsSpace() */ + /* i. Set F2 -> tag to TPM_TAG_FAMILY_TABLE_ENTRY */ + /* NOTE Done by TPM_FamilyTableEntry_Init() */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set F2 -> familyLabel to opData */ + familyRow->familyLabel = *(opData.buffer); + /* d. Increment TPM_PERMANENT_DATA -> lastFamilyID by 1 */ + tpm_state->tpm_permanent_data.lastFamilyID++; + /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after NVRAM is written */ + writeAllNV = TRUE; + /* e. Set F2 -> familyID = TPM_PERMANENT_DATA -> lastFamilyID */ + familyRow->familyID = tpm_state->tpm_permanent_data.lastFamilyID; + /* f. Set F2 -> verificationCount = 1 */ + familyRow->verificationCount = 1; + /* g. Set F2 -> flags -> TPM_FAMFLAG_ENABLED to FALSE */ + familyRow->flags &= ~TPM_FAMFLAG_ENABLED; + /* h. Set F2 -> flags -> TPM_DELEGATE_ADMIN_LOCK to FALSE */ + familyRow->flags &= ~TPM_DELEGATE_ADMIN_LOCK; + /* i. Set retDataSize = 4 */ + /* j. Set retData = F2 -> familyID */ + printf("TPM_Process_DelegateManage: Created familyID %08x\n", familyRow->familyID); + familyRow->valid = TRUE; + returnCode = TPM_Sbuffer_Append32(&retData, familyRow->familyID); + } + /* k. Return TPM_SUCCESS */ + } + /* 6. If authHandle is of type DSAP then continueAuthSession MUST set to FALSE */ + if ((returnCode == TPM_SUCCESS) && (opCode != TPM_FAMILY_CREATE) && + (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { /* only if auth-1 */ + + if (auth_session_data->protocolID == TPM_PID_DSAP) { + continueAuthSession = FALSE; + } + } + /* 7. If opCode == TPM_FAMILY_ADMIN */ + if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_ADMIN)) { + printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_ADMIN\n"); + /* a. Validate that opDataSize == 1, and that opData is a Boolean value. */ + if (returnCode == TPM_SUCCESS) { + if (opData.size != sizeof(TPM_BOOL)) { + printf("TPM_Process_DelegateManage: Error, invalid opDataSize %u\n", opData.size); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* b. Set (FR -> flags -> TPM_DELEGATE_ADMIN_LOCK) = opData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: TPM_FAMILY_ADMIN opData %02x\n", + opData.buffer[0]); + if (*(TPM_BOOL *)(opData.buffer)) { + familyRow->flags |= TPM_DELEGATE_ADMIN_LOCK; + } + else { + familyRow->flags &= ~TPM_DELEGATE_ADMIN_LOCK; + } + printf("TPM_Process_DelegateManage: new TPM_FAMILY_TABLE_ENTRY.flags %08x\n", + familyRow->flags); + /* c. Set retDataSize = 0 */ + /* NOTE Done by TPM_Sbuffer_Init() */ + /* d. Return TPM_SUCCESS */ + } + if (returnCode == TPM_SUCCESS) { + writeAllNV = TRUE; + } + } + /* 8. else If opflag == TPM_FAMILY_ENABLE */ + if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_ENABLE)) { + printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_ENABLE\n"); + /* a. Validate that opDataSize == 1, and that opData is a Boolean value. */ + if (returnCode == TPM_SUCCESS) { + if (opData.size != sizeof(TPM_BOOL)) { + printf("TPM_Process_DelegateManage: Error, invalid opDataSize %u\n", opData.size); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* b. Set FR -> flags-> TPM_FAMFLAG_ENABLED = opData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateManage: TPM_FAMILY_ENABLE opData %02x\n", + opData.buffer[0]); + if (*(TPM_BOOL *)(opData.buffer)) { + familyRow->flags |= TPM_FAMFLAG_ENABLED; + } + else { + familyRow->flags &= ~TPM_FAMFLAG_ENABLED; + } + printf("TPM_Process_DelegateManage: new TPM_FAMILY_TABLE_ENTRY.flags %08x\n", + familyRow->flags); + /* c. Set retDataSize = 0 */ + /* NOTE Done by TPM_Sbuffer_Init() */ + /* d. Return TPM_SUCCESS */ + } + if (returnCode == TPM_SUCCESS) { + writeAllNV = TRUE; + } + } + /* 9. else If opflag == TPM_FAMILY_INVALIDATE */ + if ((returnCode == TPM_SUCCESS) && (opCode == TPM_FAMILY_INVALIDATE)) { + printf("TPM_Process_DelegateManage: Processing TPM_FAMILY_INVALIDATE\n"); + /* a. Invalidate all data associated with familyRow */ + /* i. All data is all information pointed to by FR */ + /* ii. return TPM_SELFTEST_FAILED on failure */ + TPM_FamilyTableEntry_Delete(familyRow); + /* b.The TPM MAY invalidate delegate rows that contain the same familyID. */ + /* c. Set retDataSize = 0 */ + /* NOTE Done by TPM_Sbuffer_Init() */ + /* d. Return TPM_SUCCESS */ + writeAllNV = TRUE; + } + /* 10. Else return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if ((opCode != TPM_FAMILY_CREATE) && + (opCode != TPM_FAMILY_ADMIN) && + (opCode != TPM_FAMILY_ENABLE) && + (opCode != TPM_FAMILY_INVALIDATE)) { + printf("TPM_Process_DelegateManage: Error, bad opCode %08x\n", opCode); + returnCode = TPM_BAD_PARAMETER; + } + } + /* if writing NV and this is a no owner NV write, update the count with the previously + incremented value */ + if (returnCode == TPM_SUCCESS) { + if (writeAllNV && nv1Incremented) { + printf("TPM_Process_DelegateManage: noOwnerNVWrite %u\n", nv1); + tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1; + } + } + /* write back TPM_PERMANENT_DATA if required */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateManage: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append retDataSize and retData */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &retData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + savedAuth, /* saved HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&opData); /* @1 */ + TPM_Sbuffer_Delete(&retData); /* @2 */ + return rcf; +} + +/* 19.2 TPM_Delegate_CreateKeyDelegation rev 109 + + This command delegates privilege to use a key by creating a blob that can be used by TPM_DSAP. + + There is no check for appropriateness of the key's key usage against the key permission + settings. If the key usage is incorrect, this command succeeds, but the delegated command will + fail. + + These blobs CANNOT be used as input data for TPM_LoadOwnerDelegation because the internal TPM + delegate table can store owner delegations only. + + (TPM_Delegate_CreateOwnerDelegation must be used to delegate Owner privilege.) + + The use restrictions that may be present on the key pointed to by keyHandle are not enforced for + this command. Stated another way CreateKeyDelegation is not a use of the key. + + The publicInfo -> familyID can specify a disabled family row. The family row is checked when the + key delegation is used in a DSAP session, not when it is created. +*/ + +TPM_RESULT TPM_Process_DelegateCreateKeyDelegation(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key. */ + TPM_DELEGATE_PUBLIC publicInfo; /* The public information necessary to fill in the blob */ + TPM_ENCAUTH delAuth; /* The encrypted new AuthData for the blob. The encryption + key is the shared secret from the authorization session + protocol.*/ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the use + of keyHandle. HMAC key: key.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_BOOL parentPCRStatus; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */ + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + TPM_DIGEST a1Auth; + TPM_DELEGATE_SENSITIVE m1DelegateSensitive; + TPM_STORE_BUFFER delegateSensitive_sbuffer; + TPM_DELEGATE_KEY_BLOB p1DelegateKeyBlob; + + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER blobSbuffer; /* The partially encrypted delegation information. + */ + + printf("TPM_Process_DelegateCreateKeyDelegation: Ordinal Entry\n"); + TPM_DelegatePublic_Init(&publicInfo); /* freed @1 */ + TPM_DelegateSensitive_Init(&m1DelegateSensitive); /* freed @2 */ + TPM_Sbuffer_Init(&delegateSensitive_sbuffer); /* freed @3 */ + TPM_DelegateKeyBlob_Init(&p1DelegateKeyBlob); /* freed @4 */ + TPM_Sbuffer_Init(&blobSbuffer); /* freed @5 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get publicInfo parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateKeyDelegation: keyHandle %08x\n", keyHandle); + returnCode = TPM_DelegatePublic_Load(&publicInfo, &command, ¶mSize); + } + /* get delAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(delAuth, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateCreateKeyDelegation: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Verify AuthData for the command and parameters using privAuth */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get keyHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + key, + NULL, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* Validate the authorization */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. Locate publicInfo -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row, + return TPM_BADINDEX if not found */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_GetEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + publicInfo.familyID); + } + /* 3. If the key authentication is in fact a delegation, then the TPM SHALL validate the command + and parameters using Delegation authorisation, then */ + if ((returnCode == TPM_SUCCESS) && (auth_session_data->protocolID == TPM_PID_DSAP)) { + printf("TPM_Process_DelegateCreateKeyDelegation: Authentication is a delegation\n"); + /* get the TPM_DELEGATE_PUBLIC from the DSAP session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic, + auth_session_data); + } + /* a. Validate that authHandle -> familyID equals publicInfo -> familyID return + TPM_DELEGATE_FAMILY on error */ + if (returnCode == TPM_SUCCESS) { + if (publicInfo.familyID != delegatePublic->familyID) { + printf("TPM_Process_DelegateCreateKeyDelegation: Error, " + "familyID %u should be %u\n", + publicInfo.familyID, delegatePublic->familyID); + returnCode = TPM_DELEGATE_FAMILY; + } + } + /* b. If TPM_FAMILY_TABLE.famTableRow[ authHandle -> familyID] -> flags -> + TPM_FAMFLAG_ENABLED is FALSE, return error TPM_DISABLED_CMD. */ + if (returnCode == TPM_SUCCESS) { + if (!(familyRow->flags & TPM_FAMFLAG_ENABLED)) { + printf("TPM_Process_DelegateCreateKeyDelegation: Error, family %u disabled\n", + publicInfo.familyID); + returnCode = TPM_DISABLED_CMD; + } + } + /* c. Verify that the delegation bits in publicInfo do not grant more permissions then + currently delegated. Otherwise return error TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Delegations_CheckPermissionDelegation(&(publicInfo.permissions), + &(delegatePublic->permissions)); + } + } + /* 4. Check that publicInfo -> delegateType is TPM_DEL_KEY_BITS */ + if (returnCode == TPM_SUCCESS) { + if (publicInfo.permissions.delegateType != TPM_DEL_KEY_BITS) { + printf("TPM_Process_DelegateCreateKeyDelegation: Error, " + "delegateType %08x not a key delegation\n", + publicInfo.permissions.delegateType); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 5. Verify that authHandle indicates an OSAP or DSAP session return TPM_INVALID_AUTHHANDLE on + error */ + /* NOTE Done by TPM_AuthSessions_GetData() */ + /* 6. Create a1 by decrypting delAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + delAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 7. Create h1 the SHA-1 of TPM_STORE_PUBKEY structure of the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_DelegateCreateKeyDelegation: Decrypted a1", a1Auth); + returnCode = TPM_SHA1_GenerateStructure(p1DelegateKeyBlob.pubKeyDigest, + &(key->pubKey), + (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store); + } + /* 8. Create M1 a TPM_DELEGATE_SENSITIVE structure */ + /* a. Set M1 -> tag to TPM_TAG_DELEGATE_SENSITIVE */ + /* NOTE Done by TPM_DelegateSensitive_Init() */ + /* b. Set M1 -> authValue to a1 */ + if (returnCode == TPM_SUCCESS) { + TPM_Secret_Copy(m1DelegateSensitive.authValue, a1Auth); + /* c. The TPM MAY add additional information of a sensitive nature relative to the + delegation */ + /* 9. Create M2 the encryption of M1 using TPM_DELEGATE_KEY */ + /* serialize M1 */ + returnCode = TPM_DelegateSensitive_Store(&delegateSensitive_sbuffer, &m1DelegateSensitive); + } + /* encrypt with delegate key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateKeyDelegation: Encrypting TPM_DELEGATE_SENSITIVE\n"); + returnCode = + TPM_SymmetricKeyData_EncryptSbuffer(&(p1DelegateKeyBlob.sensitiveArea), + &delegateSensitive_sbuffer, + tpm_state->tpm_permanent_data.delegateKey); + } + /* 10. Create P1 a TPM_DELEGATE_KEY_BLOB */ + /* a. Set P1 -> tag to TPM_TAG_DELG_KEY_BLOB */ + /* NOTE Done by TPM_DelegateKeyBlob_Init() */ + /* b. Set P1 -> pubKeyDigest to H1 */ + /* NOTE Done by TPM_StorePubkey_GenerateDigest() */ + /* c. Set P1 -> pub to PublicInfo */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegatePublic_Copy(&(p1DelegateKeyBlob.pub), &publicInfo); + } + /* d. Set P1 -> pub -> verificationCount to familyRow -> verificationCount */ + if (returnCode == TPM_SUCCESS) { + p1DelegateKeyBlob.pub.verificationCount = familyRow->verificationCount; + /* e. Set P1 -> integrityDigest to NULL */ + /* NOTE Done by TPM_DelegateKeyBlob_Init() */ + /* f. The TPM sets additionalArea and additionalAreaSize appropriate for this TPM. The + information MAY include symmetric IV, symmetric mode of encryption and other data that + allows the TPM to process the blob in the future. */ + /* g. Set P1 -> sensitiveSize to the size of M2 */ + /* h. Set P1 -> sensitiveArea to M2 */ + /* NOTE Encrypted directly into p1DelegateKeyBlob.sensitiveArea */ + /* 11. Calculate H2 the HMAC of P1 using tpmProof as the secret */ + /* 12. Set P1 -> integrityDigest to H2 */ + /* NOTE It is safe to HMAC directly into TPM_DELEGATE_KEY_BLOB, since the structure + is serialized before the HMAC is performed */ + returnCode = TPM_HMAC_GenerateStructure + (p1DelegateKeyBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &p1DelegateKeyBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store); /* store function */ + } + /* 13. Ignore continueAuthSession on input set continueAuthSession to FALSE on output */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 14. Return P1 as blob */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateKeyBlob_Store(&blobSbuffer, &p1DelegateKeyBlob); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateCreateKeyDelegation: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return blobSize and blob */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &blobSbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_DelegatePublic_Delete(&publicInfo); /* @1 */ + TPM_DelegateSensitive_Delete(&m1DelegateSensitive); /* @2 */ + TPM_Sbuffer_Delete(&delegateSensitive_sbuffer); /* @3 */ + TPM_DelegateKeyBlob_Delete(&p1DelegateKeyBlob); /* @4 */ + TPM_Sbuffer_Delete(&blobSbuffer); /* @5 */ + return rcf; +} + +/* 19.3 TPM_Delegate_CreateOwnerDelegation rev 98 + + 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_Delegate_CreateOwnerDelegation includes the ability to void all existing delegations (by + incrementing the verification count) before creating the new delegation. This ensures that the + new delegation will be the only delegation that can operate at Owner privilege in this + family. This new delegation could be used to enable a security monitor (a local separate entity, + or remote separate entity, or local host entity) to reinitialize a family and perhaps perform + external verification of delegation settings. Normally the ordinals for a delegated security + monitor would include TPM_Delegate_CreateOwnerDelegation (this command) in order to permit the + monitor to create further delegations, and TPM_Delegate_UpdateVerification to reactivate some + previously voided delegations. + + If the verification count is incremented and the new delegation does not delegate any privileges + (to any ordinals) at all, or uses an authorisation value that is then discarded, this family's + delegations are all void and delegation must be managed using actual Owner authorisation. + + (TPM_Delegate_CreateKeyDelegation must be used to delegate privilege to use a key.) +*/ + +TPM_RESULT TPM_Process_DelegateCreateOwnerDelegation(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_BOOL increment; /* Flag dictates whether verificationCount will be + incremented */ + TPM_DELEGATE_PUBLIC publicInfo; /* The public parameters for the blob */ + TPM_ENCAUTH delAuth; /* The encrypted new AuthData for the blob. The encryption + key is the shared secret from the OSAP protocol.*/ + TPM_AUTHHANDLE authHandle; /* The authorization session handle TPM Owner authentication + */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest. HMAC key:ownerAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_SECRET savedAuth; /* saved copy for response */ + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */ + TPM_BOOL writeAllNV = FALSE; + TPM_DIGEST a1Auth; + TPM_DELEGATE_SENSITIVE m1DelegateSensitive; + TPM_STORE_BUFFER delegateSensitive_sbuffer; /* serialization of delegateSensitive */ + TPM_DELEGATE_OWNER_BLOB b1DelegateOwnerBlob; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER blobSbuffer; /* The partially encrypted delegation + information. */ + + printf("TPM_Process_DelegateCreateOwnerDelegation: Ordinal Entry\n"); + TPM_DelegatePublic_Init(&publicInfo); /* freed @1 */ + TPM_DelegateSensitive_Init(&m1DelegateSensitive); /* freed @2 */ + TPM_Sbuffer_Init(&delegateSensitive_sbuffer); /* freed @3 */ + TPM_DelegateOwnerBlob_Init(&b1DelegateOwnerBlob); /* freed @4 */ + TPM_Sbuffer_Init(&blobSbuffer); /* freed @5 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get increment parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&increment, &command, ¶mSize); + } + /* get publicInfo parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: increment %02x\n", increment); + returnCode = TPM_DelegatePublic_Load(&publicInfo, &command, ¶mSize); + } + /* get delAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(delAuth, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Error, " + "command has %u extra bytes\n", paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. The TPM SHALL authenticate the command using TPM Owner authentication. Return TPM_AUTHFAIL + on failure. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_OWNER, + ordinal, + NULL, + NULL, /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + /* make a copy of the HMAC key for the response, since it MAY be invalidated */ + TPM_Secret_Copy(savedAuth, *hmacKey); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Locate publicInfo -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate the + row return TPM_BADINDEX if not found */ + /* a. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_GetEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + publicInfo.familyID); + } + /* 3. If the TPM Owner authentication is in fact a delegation, then the TPM SHALL validate the + command and parameters using Delegation authorisation, then */ + if ((returnCode == TPM_SUCCESS) && (auth_session_data->protocolID == TPM_PID_DSAP)) { + /* get the TPM_DELEGATE_PUBLIC from the DSAP session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic, + auth_session_data); + } + /* a. Validate that authHandle -> familyID equals publicInfo -> familyID return + TPM_DELEGATE_FAMILY */ + if (returnCode == TPM_SUCCESS) { + if (publicInfo.familyID != delegatePublic->familyID) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Error, " + "familyID %u should be %u\n", + publicInfo.familyID, delegatePublic->familyID); + returnCode = TPM_DELEGATE_FAMILY; + } + } + /* b. If FR -> flags -> TPM_FAMFLAG_ENABLED is FALSE, return error TPM_DISABLED_CMD. */ + if (returnCode == TPM_SUCCESS) { + if (!(familyRow->flags & TPM_FAMFLAG_ENABLED)) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Error, family %u disabled\n", + publicInfo.familyID); + returnCode = TPM_DISABLED_CMD; + } + } + /* c. Verify that the delegation bits in publicInfo do not grant more permissions then + currently delegated. Otherwise return error TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Delegations_CheckPermissionDelegation(&(publicInfo.permissions), + &(delegatePublic->permissions)); + } + } + /* 4. Check that publicInfo -> delegateType is TPM_DEL_OWNER_BITS */ + if (returnCode == TPM_SUCCESS) { + if (publicInfo.permissions.delegateType != TPM_DEL_OWNER_BITS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Error, bad delegateType %08x\n", + publicInfo.permissions.delegateType); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 5. Verify that authHandle indicates an OSAP or DSAP session return TPM_INVALID_AUTHHANDLE on + error */ + /* NOTE Done by TPM_AuthSessions_GetData() */ + /* 7. Create a1 by decrypting delAuth according to the ADIP indicated by authHandle */ + /* NOTE 7. moved before 6. because it needs the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + delAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 6. If increment == TRUE */ + if ((returnCode == TPM_SUCCESS) && increment) { + /* a. Increment FR -> verificationCount */ + familyRow->verificationCount++; + writeAllNV = TRUE; + /* b. Set TPM_STCLEAR_DATA -> ownerReference to TPM_KH_OWNER */ + tpm_state->tpm_stclear_data.ownerReference = TPM_KH_OWNER; + /* c. The TPM invalidates sessions */ + /* i. MUST invalidate all DSAP sessions */ + /* ii. MUST invalidate all OSAP sessions associated with the delegation table */ + /* iii. MAY invalidate any other session */ + TPM_AuthSessions_TerminatexSAP(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions); + } + /* 8. Create M1 a TPM_DELEGATE_SENSITIVE structure */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Creating TPM_DELEGATE_SENSITIVE\n"); + /* a. Set M1 -> tag to TPM_TAG_DELEGATE_SENSITIVE */ + /* NOTE Done by TPM_DelegateSensitive_Init() */ + /* b. Set M1 -> authValue to a1 */ + TPM_Secret_Copy(m1DelegateSensitive.authValue, a1Auth); + /* c. Set other M1 fields as determined by the TPM vendor */ + } + /* 9. Create M2 the encryption of M1 using TPM_DELEGATE_KEY */ + /* serialize M1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateSensitive_Store(&delegateSensitive_sbuffer, &m1DelegateSensitive); + } + /* encrypt with delegate key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Encrypting TPM_DELEGATE_SENSITIVE\n"); + returnCode = + TPM_SymmetricKeyData_EncryptSbuffer(&(b1DelegateOwnerBlob.sensitiveArea), + &delegateSensitive_sbuffer, + tpm_state->tpm_permanent_data.delegateKey); + } + /* 10. Create B1 a TPM_DELEGATE_OWNER_BLOB */ + /* a. Set B1 -> tag to TPM_TAG_DELG_OWNER_BLOB */ + /* NOTE Done by TPM_DelegateOwnerBlob_Init() */ + /* b. Set B1 -> pub to publicInfo */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Creating TPM_DELEGATE_OWNER_BLOB\n"); + returnCode = TPM_DelegatePublic_Copy(&(b1DelegateOwnerBlob.pub), &publicInfo); + } + /* c. Set B1 -> sensitiveSize to the size of M2 */ + /* d. Set B1 -> sensitiveArea to M2 */ + /* NOTE Encrypted directly into b1DelegateOwnerBlob */ + /* e. Set B1 -> integrityDigest to NULL */ + /* NOTE Done by TPM_DelegateOwnerBlob_Init() */ + if (returnCode == TPM_SUCCESS) { + /* f. Set B1 pub -> verificationCount to FR -> verificationCount */ + b1DelegateOwnerBlob.pub.verificationCount = familyRow->verificationCount; + /* 11. The TPM sets additionalArea and additionalAreaSize appropriate for this TPM. The + information MAY include symmetric IV, symmetric mode of encryption and other data that + allows the TPM to process the blob in the future. */ + /* 12. Create H1 the HMAC of B1 using tpmProof as the secret */ + /* 13. Set B1 -> integrityDigest to H1 */ + /* NOTE It is safe to HMAC directly into TPM_DELEGATE_OWNER_BLOB, since the structure + is serialized before the HMAC is performed */ + returnCode = TPM_HMAC_GenerateStructure + (b1DelegateOwnerBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &b1DelegateOwnerBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store); /* store function */ + } + /* 14. Ignore continueAuthSession on input set continueAuthSession to FALSE on output */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 15. Return B1 as blob */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateOwnerBlob_Store(&blobSbuffer, &b1DelegateOwnerBlob); + } + /* write back TPM_PERMANENT_DATA if required */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateCreateOwnerDelegation: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return blobSize and blob */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &blobSbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + savedAuth, /* saved HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_DelegatePublic_Delete(&publicInfo); /* @1 */ + TPM_DelegateSensitive_Delete(&m1DelegateSensitive); /* @2 */ + TPM_Sbuffer_Delete(&delegateSensitive_sbuffer); /* @3 */ + TPM_DelegateOwnerBlob_Delete(&b1DelegateOwnerBlob); /* @4 */ + TPM_Sbuffer_Delete(&blobSbuffer); /* @5 */ + return rcf; +} + +/* 19.4 TPM_Delegate_LoadOwnerDelegation rev 109 + + 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. If an Owner is installed, Delegate_LoadOwnerDelegation + requires Owner authorisation, and sensitive information must be encrypted. + + Burn-out of TPM non-volatile storage by inappropriate use is mitigated by the TPM's normal limits + on NV- writes in the absence of an Owner. Tables can be locked after loading using + TPM_Delegate_Manage, to prevent subsequent tampering. + + A management system outside the TPM is expected to manage the delegate table rows stored on the + TPM, and can overwrite any previously stored data. There is no way to explicitly delete a + delegation entry. A new entry can overwrite an invalid entry. + + This command cannot be used to load key delegation blobs into the TPM +*/ + +TPM_RESULT TPM_Process_DelegateLoadOwnerDelegation(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_DELEGATE_INDEX index; /* The index of the delegate row to be written */ + uint32_t blobSize; /* The size of the delegate blob */ + TPM_DELEGATE_OWNER_BLOB d1Blob; /* Delegation information, including encrypted + portions as appropriate */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle TPM Owner + authentication */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with + authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest. HMAC + key:ownerAuth */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_SECRET savedAuth; /* saved copy for response */ + TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */ + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + TPM_DELEGATE_SENSITIVE s1DelegateSensitive; + TPM_DELEGATE_TABLE_ROW *delegateTableRow; + unsigned char *stream; + uint32_t stream_size; + uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* temp for noOwnerNVWrite, initialize to + silence compiler */ + TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back data */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DelegateLoadOwnerDelegation: Ordinal Entry\n"); + TPM_DelegateOwnerBlob_Init(&d1Blob); /* freed @1 */ + TPM_DelegateSensitive_Init(&s1DelegateSensitive); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get index parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&index, &command, ¶mSize); + } + /* get blobSize parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateLoadOwnerDelegation: index %u\n", index); + returnCode = TPM_Load32(&blobSize, &command, ¶mSize); + } + /* get blob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateOwnerBlob_Load(&d1Blob, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Map blob to D1 a TPM_DELEGATE_OWNER_BLOB. */ + /* a. Validate that D1 -> tag == TPM_TAG_DELEGATE_OWNER_BLOB */ + /* Done by TPM_DelegateOwnerBlob_Load() */ + /* 2. Locate D1 -> pub -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row, + return TPM_BADINDEX if not found */ + /* 3. Set FR to TPM_FAMILY_TABLE -> famTableRow[familyRow] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + d1Blob.pub.familyID); + } + /* 4. If TPM Owner is installed */ + if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) { + /* a. Validate the command and parameters using TPM Owner authorization, return + TPM_AUTHFAIL on error */ + if (returnCode == TPM_SUCCESS) { + if (tag != TPM_TAG_RQU_AUTH1_COMMAND) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Error, " + "owner installed but no authorization\n"); + returnCode = TPM_AUTHFAIL; + } + } + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth),/* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + /* make a copy of the HMAC key for the response, since it MAY be invalidated */ + TPM_Secret_Copy(savedAuth, *hmacKey); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* b. If the command is delegated (authHandle session type is TPM_PID_DSAP or through + ownerReference delegation), verify that D1 -> pub -> familyID matches authHandle -> + familyID, on error return TPM_DELEGATE_FAMILY */ + if ((returnCode == TPM_SUCCESS) && + ((auth_session_data->protocolID == TPM_PID_DSAP) || + (tpm_state->tpm_stclear_data.ownerReference != TPM_KH_OWNER))) { + /* get the TPM_DELEGATE_PUBLIC from the DSAP session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic, + auth_session_data); + } + if (returnCode == TPM_SUCCESS) { + if (d1Blob.pub.familyID != delegatePublic->familyID) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Error, " + "familyID %u should be %u\n", + d1Blob.pub.familyID, delegatePublic->familyID); + returnCode = TPM_DELEGATE_FAMILY; + } + } + } + } + /* 5. Else */ + if ((returnCode == TPM_SUCCESS) && !tpm_state->tpm_permanent_data.ownerInstalled) { + /* a. If FR -> flags -> TPM_DELEGATE_ADMIN_LOCK is TRUE return TPM_DELEGATE_LOCK */ + if (returnCode == TPM_SUCCESS) { + if (familyRow->flags & TPM_DELEGATE_ADMIN_LOCK) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Error, row locked\n"); + returnCode = TPM_DELEGATE_LOCK; + } + } + /* b. Validate max NV writes without an owner */ + if (returnCode == TPM_SUCCESS) { + /* i. Set NV1 to PD -> noOwnerNVWrite */ + nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* ii. Increment NV1 by 1 */ + nv1++; + /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */ + if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Error, " + "max NV writes %d w/o owner reached\n", + tpm_state->tpm_permanent_data.noOwnerNVWrite); + returnCode = TPM_MAXNVWRITES; + } + } + /* iv. Set PD -> noOwnerNVWrite to NV1 */ + if (returnCode == TPM_SUCCESS) { + /* NOTE Don't update the noOwnerNVWrite value until determining that the write will be + performed */ + nv1Incremented = TRUE; + } + } + /* 6. If FR -> flags -> TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + /* NOTE Done by TPM_FamilyTable_GetEnabledEntry() */ + /* 7. If TPM Owner is installed, validate the integrity of the blob */ + if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Checking integrityDigest\n"); + /* a. Copy D1 -> integrityDigest to H2 */ + /* b. Set D1 -> integrityDigest to NULL */ + /* c. Create H3 the HMAC of D1 using tpmProof as the secret */ + /* d. Compare H2 to H3, return TPM_AUTHFAIL on mismatch */ + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &d1Blob, /* structure */ + d1Blob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + } + /* 8. If TPM Owner is installed, create S1 a TPM_DELEGATE_SENSITIVE area by decrypting D1 -> + sensitiveArea using TPM_DELEGATE_KEY. */ + if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) { + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Decrypting sensitiveArea\n"); + returnCode = + TPM_DelegateSensitive_DecryptEncData(&s1DelegateSensitive, /* decrypted data */ + &(d1Blob.sensitiveArea), /* encrypted */ + tpm_state->tpm_permanent_data.delegateKey); + } + } + /* 8. Otherwise set S1 = D1 -> sensitiveArea */ + if ((returnCode == TPM_SUCCESS) && !tpm_state->tpm_permanent_data.ownerInstalled) { + stream = d1Blob.sensitiveArea.buffer; + stream_size = d1Blob.sensitiveArea.size; + returnCode = TPM_DelegateSensitive_Load(&s1DelegateSensitive, &stream, &stream_size); + } + /* 9. Validate S1 */ + /* a. Validate that S1 -> tag == TPM_TAG_DELEGATE_SENSITIVE, return TPM_INVALID_STRUCTURE on + error */ + /* NOTE Done by TPM_DelegateSensitive_Load() */ + /* 10. Validate that index is a valid value for delegateTable, return TPM_BADINDEX on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateTable_GetRow(&delegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + index); + } + /* 11. The TPM invalidates sessions */ + if (returnCode == TPM_SUCCESS) { + /* a. MUST invalidate all DSAP sessions */ + /* b. MUST invalidate all OSAP sessions associated with the delegation table */ + /* c. MAY invalidate any other session */ + TPM_AuthSessions_TerminatexSAP(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions); + } + /* 12. Copy data to the delegate table row */ + if (returnCode == TPM_SUCCESS) { + /* a. Copy the TPM_DELEGATE_PUBLIC from D1 -> pub to TPM_DELEGATE_TABLE -> delRow[index] -> + pub. */ + returnCode = TPM_DelegatePublic_Copy(&delegateTableRow->pub, &(d1Blob.pub)); + writeAllNV = TRUE; + } + if (returnCode == TPM_SUCCESS) { + delegateTableRow->valid = TRUE; + /* b. Copy the TPM_SECRET from S1 -> authValue to TPM_DELEGATE_TABLE -> delRow[index] -> + authValue. */ + TPM_Secret_Copy(delegateTableRow->authValue, s1DelegateSensitive.authValue); + /* c. Set TPM_STCLEAR_DATA-> ownerReference to TPM_KH_OWNER */ + tpm_state->tpm_stclear_data.ownerReference = TPM_KH_OWNER; + } + if ((returnCode == TPM_SUCCESS) && tpm_state->tpm_permanent_data.ownerInstalled) { + /* d. If authHandle is of type DSAP then continueAuthSession MUST set to FALSE */ + if (auth_session_data->protocolID == TPM_PID_DSAP) { + continueAuthSession = FALSE; + } + } + /* if writing NV and this is a no owner NV write, update the count with the previously + incremented value */ + if (returnCode == TPM_SUCCESS) { + if (writeAllNV && nv1Incremented) { + printf("TPM_Process_DelegateLoadOwnerDelegation: noOwnerNVWrite %u\n", nv1); + tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1; + } + } + /* write back TPM_PERMANENT_DATA */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateLoadOwnerDelegation: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + savedAuth, /* saved HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_DelegateOwnerBlob_Delete(&d1Blob); /* @1 */ + TPM_DelegateSensitive_Delete(&s1DelegateSensitive); /* @2 */ + return rcf; +} + +/* 19.5 TPM_Delegate_ReadTable rev 87 + + This command is used to read from the TPM the public contents of the family and delegate tables + that are stored on the TPM. Such data is required during external verification of tables. + + There are no restrictions on the execution of this command; anyone can read this information + regardless of the state of the PCRs, regardless of whether they know any specific AuthData value + and regardless of whether or not the enable and admin bits are set one way or the other. +*/ + +TPM_RESULT TPM_Process_DelegateReadTable(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER familySbuffer; /* Array of TPM_FAMILY_TABLE_ENTRY + elements */ + TPM_STORE_BUFFER delegateSbuffer; /* Array of TPM_DELEGATE_INDEX and + TPM_DELEGATE_PUBLIC elements */ + + printf("TPM_Process_DelegateReadTable: Ordinal Entry\n"); + TPM_Sbuffer_Init(&familySbuffer); /* freed @1 */ + TPM_Sbuffer_Init(&delegateSbuffer); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateReadTable: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Set familyTableSize to the number of valid families on the TPM times + sizeof(TPM_FAMILY_TABLE_ELEMENT). */ + /* NOTE Done below by TPM_Sbuffer_AppendAsSizedBuffer() */ + /* 2. Copy the valid entries in the internal family table to the output array familyTable */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_StoreValid(&familySbuffer, + &(tpm_state->tpm_permanent_data.familyTable), + TRUE); /* standard, store the tag */ + } + /* 3. Set delegateTableSize to the number of valid delegate table entries on the TPM times + (sizeof(TPM_DELEGATE_PUBLIC) + 4). */ + /* NOTE Done below by TPM_Sbuffer_AppendAsSizedBuffer() */ + /* 4. For each valid entry */ + /* a. Write the TPM_DELEGATE_INDEX to delegateTable */ + /* b. Copy the TPM_DELEGATE_PUBLIC to delegateTable */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateTable_StoreValid(&delegateSbuffer, + &(tpm_state->tpm_permanent_data.delegateTable)); + } + /* 5. Return TPM_SUCCESS */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateReadTable: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append familyTableSize and familyTable */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &familySbuffer); + } + if (returnCode == TPM_SUCCESS) { + /* append delegateTableSize and delegateTable */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &delegateSbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&familySbuffer); /* @1 */ + TPM_Sbuffer_Delete(&delegateSbuffer); /* @2 */ + return rcf; +} + +/* 19.6 TPM_Delegate_UpdateVerification rev 87 + + 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_Process_DelegateUpdateVerification(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_SIZED_BUFFER inputData; /* TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB or + TPM_DELEGATE_INDEX */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* Authorization HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey = NULL; + unsigned char *stream; /* temp input stream */ + uint32_t stream_size; + TPM_STRUCTURE_TAG d1Tag; /* input structure tag */ + TPM_DELEGATE_INDEX d1DelegateIndex; + TPM_DELEGATE_OWNER_BLOB d1DelegateOwnerBlob; + TPM_DELEGATE_KEY_BLOB d1DelegateKeyBlob; + TPM_DELEGATE_TABLE_ROW *d1DelegateTableRow; + TPM_FAMILY_ID familyID = 0; + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + TPM_DELEGATE_PUBLIC *delegatePublic; /* from DSAP session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER outputDataSbuffer; /* TPM_DELEGATE_KEY_BLOB or + TPM_DELEGATE_OWNER_BLOB */ + + printf("TPM_Process_DelegateUpdateVerification: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inputData); /* freed @1 */ + TPM_DelegateOwnerBlob_Init(&d1DelegateOwnerBlob); /* freed @2 */ + TPM_DelegateKeyBlob_Init(&d1DelegateKeyBlob); /* freed @3 */ + TPM_Sbuffer_Init(&outputDataSbuffer); /* freed @4 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get inputData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inputData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateUpdateVerification: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Verify the TPM Owner, directly or indirectly through delegation, authorizes the command + and parameters, on error return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Determine the type of inputData (TPM_DELEGATE_TABLE_ROW or TPM_DELEGATE_OWNER_BLOB + or TPM_DELEGATE_KEY_BLOB) and map D1 to that structure */ + if (returnCode == TPM_SUCCESS) { + /* use a temporary copy so the original values are not moved */ + stream = inputData.buffer; + stream_size = inputData.size; + /* the inputData is either a table index or a blob */ + if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) { + /* if it's an index, get the index */ + returnCode = TPM_Load32(&d1DelegateIndex, &stream, &stream_size); + } + else { + /* if it's a blob, get the blob structure tag to determine the blob type */ + returnCode = TPM_Load16(&d1Tag, &stream, &stream_size); + } + } + if (returnCode == TPM_SUCCESS) { + /* use a temporary copy so the original values are not moved */ + stream = inputData.buffer; + stream_size = inputData.size; + /* if inputData is a table index */ + if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) { + /* a. Mapping to TPM_DELEGATE_TABLE_ROW requires taking inputData as a tableIndex and + locating the appropriate row in the table */ + returnCode = + TPM_DelegateTable_GetValidRow(&d1DelegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + d1DelegateIndex); + familyID = d1DelegateTableRow->pub.familyID; + } + /* if inputData is a blob */ + else { + switch (d1Tag) { + case TPM_TAG_DELEGATE_OWNER_BLOB: + returnCode = TPM_DelegateOwnerBlob_Load(&d1DelegateOwnerBlob, + &stream, &stream_size); + familyID = d1DelegateOwnerBlob.pub.familyID; + break; + case TPM_TAG_DELG_KEY_BLOB: + returnCode = TPM_DelegateKeyBlob_Load(&d1DelegateKeyBlob, + &stream, &stream_size); + familyID = d1DelegateKeyBlob.pub.familyID; + break; + default: + printf("TPM_Process_DelegateUpdateVerification: Error, invalid tag %04hx\n", d1Tag); + returnCode = TPM_BAD_PARAMETER; + break; + } + } + } + /* 3. If D1 is TPM_DELEGATE_OWNER_BLOB or TPM_DELEGATE_KEY_BLOB Validate the integrity of + D1 */ + if ((returnCode == TPM_SUCCESS) && (inputData.size != sizeof(TPM_DELEGATE_INDEX))) { + /* a. Copy D1 -> integrityDigest to H2 */ + /* b. Set D1 -> integrityDigest to NULL */ + /* c. Create H3 the HMAC of D1 using tpmProof as the secret */ + /* d. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */ + switch (d1Tag) { + case TPM_TAG_DELEGATE_OWNER_BLOB: + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &d1DelegateOwnerBlob, /* structure */ + d1DelegateOwnerBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + break; + case TPM_TAG_DELG_KEY_BLOB: + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &d1DelegateKeyBlob, /* structure */ + d1DelegateKeyBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + break; + /* default error tested above */ + } + } + /* 4. Locate (D1 -> pub -> familyID) in the TPM_FAMILY_TABLE and set familyRow to indicate row, + return TPM_BADINDEX if not found */ + /* 5. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_GetEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + familyID); + } + if ((returnCode == TPM_SUCCESS) && (auth_session_data->protocolID == TPM_PID_DSAP)) { + /* get the TPM_DELEGATE_PUBLIC from the DSAP session */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_GetDelegatePublic(&delegatePublic, + auth_session_data); + } + /* 6. If delegated, verify that family of the delegated Owner-auth is the same as D1: + (authHandle -> familyID) == (D1 -> pub -> familyID); otherwise return error + TPM_DELEGATE_FAMILY */ + if (returnCode == TPM_SUCCESS) { + if (familyID != delegatePublic->familyID) { + printf("TPM_Process_DelegateUpdateVerification: Error, " + "familyID %u should be %u\n", + familyID, delegatePublic->familyID); + returnCode = TPM_DELEGATE_FAMILY; + } + } + /* 7. If delegated, verify that the family of the delegated Owner-auth is enabled: if + (authHandle -> familyID -> flags TPM_FAMFLAG_ENABLED) is FALSE, return + TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + if (!(familyRow->flags & TPM_FAMFLAG_ENABLED)) { + printf("TPM_Process_DelegateUpdateVerification: Error, family %u disabled\n", + familyID); + returnCode = TPM_DISABLED_CMD; + } + } + } + /* 8. Set D1 -> verificationCount to FR -> verificationCount */ + if (returnCode == TPM_SUCCESS) { + if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) { + d1DelegateTableRow->pub.verificationCount = familyRow->verificationCount; + writeAllNV = TRUE; + } + else { + switch (d1Tag) { + case TPM_TAG_DELEGATE_OWNER_BLOB: + d1DelegateOwnerBlob.pub.verificationCount = familyRow->verificationCount; + break; + case TPM_TAG_DELG_KEY_BLOB: + d1DelegateKeyBlob.pub.verificationCount = familyRow->verificationCount; + break; + /* default error tested above */ + } + } + } + /* 9. If D1 is TPM_DELEGATE_OWNER_BLOB or TPM_DELEGATE_KEY_BLOB set the integrity of D1 */ + if ((returnCode == TPM_SUCCESS) && (inputData.size != sizeof(TPM_DELEGATE_INDEX))) { + /* a. Set D1 -> integrityDigest to NULL */ + /* NOTE Done by TPM_HMAC_GenerateStructure() */ + /* b. Create H1 the HMAC of D1 using tpmProof as the secret */ + /* c. Set D1 -> integrityDigest to H1 */ + /* NOTE It is safe to HMAC directly into the blob, since the structure is serialized before + the HMAC is performed */ + switch (d1Tag) { + case TPM_TAG_DELEGATE_OWNER_BLOB: + returnCode = TPM_HMAC_GenerateStructure + (d1DelegateOwnerBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &d1DelegateOwnerBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store); /* store function */ + break; + case TPM_TAG_DELG_KEY_BLOB: + returnCode = TPM_HMAC_GenerateStructure + (d1DelegateKeyBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &d1DelegateKeyBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store); /* store function */ + break; + } + } + /* If updating a delegate row, write back TPM_PERMANENT_DATA */ + if (inputData.size == sizeof(TPM_DELEGATE_INDEX)) { + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* 10. If D1 is a blob recreate the blob and return it */ + else { + if (returnCode == TPM_SUCCESS) { + switch (d1Tag) { + case TPM_TAG_DELEGATE_OWNER_BLOB: + returnCode = TPM_DelegateOwnerBlob_Store(&outputDataSbuffer, + &d1DelegateOwnerBlob); + break; + case TPM_TAG_DELG_KEY_BLOB: + returnCode = TPM_DelegateKeyBlob_Store(&outputDataSbuffer, + &d1DelegateKeyBlob); + break; + /* default error tested above */ + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateUpdateVerification: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return outputSize and outputData */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &outputDataSbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inputData); /* @1 */ + TPM_DelegateOwnerBlob_Delete(&d1DelegateOwnerBlob); /* @2 */ + TPM_DelegateKeyBlob_Delete(&d1DelegateKeyBlob); /* @3 */ + TPM_Sbuffer_Delete(&outputDataSbuffer); /* @4 */ + return rcf; +} + +/* 19.7 TPM_Delegate_VerifyDelegation rev 105 + + VerifyDelegation interprets a delegate blob and returns success or failure, depending on whether + the blob is currently valid. The delegate blob is NOT loaded into the TPM. +*/ + +TPM_RESULT TPM_Process_DelegateVerifyDelegation(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_SIZED_BUFFER delegation; /* TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + unsigned char *stream; /* temp input stream */ + uint32_t stream_size; + TPM_STRUCTURE_TAG d1Tag; /* input structure tag */ + TPM_DELEGATE_OWNER_BLOB d1DelegateOwnerBlob; + TPM_DELEGATE_KEY_BLOB d1DelegateKeyBlob; + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + TPM_FAMILY_ID familyID; + TPM_FAMILY_VERIFICATION verificationCount = 0; + TPM_DELEGATE_SENSITIVE s1DelegateSensitive; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DelegateVerifyDelegation: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&delegation); /* freed @1 */ + TPM_DelegateOwnerBlob_Init(&d1DelegateOwnerBlob); /* freed @2 */ + TPM_DelegateKeyBlob_Init(&d1DelegateKeyBlob); /* freed @3 */ + TPM_DelegateSensitive_Init(&s1DelegateSensitive); /* freed @4 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get delegation parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&delegation, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DelegateVerifyDelegation: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Determine the type of blob */ + if (returnCode == TPM_SUCCESS) { + /* use a temporary copy so the original values are not moved */ + stream = delegation.buffer; + stream_size = delegation.size; + returnCode = TPM_Load16(&d1Tag, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + /* use a temporary copy so the original values are not moved */ + stream = delegation.buffer; + stream_size = delegation.size; + switch (d1Tag) { + /* 1. If delegation -> tag is equal to TPM_TAG_DELEGATE_OWNER_BLOB then */ + case TPM_TAG_DELEGATE_OWNER_BLOB: + /* a. Map D1 a TPM_DELEGATE_BLOB_OWNER to delegation */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateOwnerBlob_Load(&d1DelegateOwnerBlob, + &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + familyID = d1DelegateOwnerBlob.pub.familyID; + verificationCount = d1DelegateOwnerBlob.pub.verificationCount; + } + break; + /* 2. Else if delegation -> tag = TPM_TAG_DELG_KEY_BLOB */ + case TPM_TAG_DELG_KEY_BLOB: + /* a. Map D1 a TPM_DELEGATE_KEY_BLOB to delegation */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateKeyBlob_Load(&d1DelegateKeyBlob, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + familyID = d1DelegateKeyBlob.pub.familyID; + verificationCount = d1DelegateKeyBlob.pub.verificationCount; + } + break; + /* 3. Else return TPM_BAD_PARAMETER */ + default: + printf("TPM_Process_DelegateVerifyDelegation: Error, invalid tag %04hx\n", d1Tag); + returnCode = TPM_BAD_PARAMETER; + break; + } + } + /* 4. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate row, return + TPM_BADINDEX if not found */ + /* 5. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */ + /* 6. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + familyID); + } + /* 7. Validate that D1 -> pub -> verificationCount matches FR -> verificationCount, on mismatch + return TPM_FAMILYCOUNT */ + if (returnCode == TPM_SUCCESS) { + if (verificationCount != familyRow->verificationCount) { + printf("TPM_Process_DelegateVerifyDelegation: Error, " + "verificationCount mismatch %u %u\n", + verificationCount, familyRow->verificationCount); + returnCode = TPM_FAMILYCOUNT; + } + } + /* 8. Validate the integrity of D1 */ + /* a. Copy D1 -> integrityDigest to H2 */ + /* b. Set D1 -> integrityDigest to NULL */ + /* c. Create H3 the HMAC of D1 using tpmProof as the secret */ + /* d. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */ + if (returnCode == TPM_SUCCESS) { + if (d1Tag == TPM_TAG_DELEGATE_OWNER_BLOB) { + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &d1DelegateOwnerBlob, /* structure */ + d1DelegateOwnerBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + } + else { + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &d1DelegateKeyBlob, /* structure */ + d1DelegateKeyBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + } + } + /* 9. Create S1 a TPM_DELEGATE_SENSITIVE area by decrypting D1 -> sensitiveArea using + TPM_DELEGATE_KEY */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DelegateVerifyDelegation: Decrypting sensitiveArea\n"); + if (d1Tag == TPM_TAG_DELEGATE_OWNER_BLOB) { + returnCode = + TPM_DelegateSensitive_DecryptEncData(&s1DelegateSensitive, + &(d1DelegateOwnerBlob.sensitiveArea), + tpm_state->tpm_permanent_data.delegateKey); + } + else { + returnCode = + TPM_DelegateSensitive_DecryptEncData(&s1DelegateSensitive, + &(d1DelegateKeyBlob.sensitiveArea), + tpm_state->tpm_permanent_data.delegateKey); + } + } + /* 10. Validate S1 values */ + /* a. S1 -> tag is TPM_TAG_DELEGATE_SENSITIVE */ + /* NOTE Done by TPM_DelegateSensitive_DecryptEncData() */ + /* b. Return TPM_BAD_PARAMETER on error */ + /* 11. Return TPM_SUCCESS */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DelegateVerifyDelegation: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&delegation); /* @1 */ + TPM_DelegateOwnerBlob_Delete(&d1DelegateOwnerBlob); /* @2 */ + TPM_DelegateKeyBlob_Delete(&d1DelegateKeyBlob); /* @3 */ + TPM_DelegateSensitive_Delete(&s1DelegateSensitive); /* @4 */ + return rcf; +} diff --git a/src/tpm_delegate.h b/src/tpm_delegate.h new file mode 100644 index 00000000..d4f6cb6d --- /dev/null +++ b/src/tpm_delegate.h @@ -0,0 +1,257 @@ +/********************************************************************************/ +/* */ +/* Delegate Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_delegate.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_DELEGATE_H +#define TPM_DELEGATE_H + +#include "tpm_structures.h" + +/* + TPM_DELEGATE_PUBLIC +*/ + +void TPM_DelegatePublic_Init(TPM_DELEGATE_PUBLIC *tpm_delegate_public); +TPM_RESULT TPM_DelegatePublic_Load(TPM_DELEGATE_PUBLIC *tpm_delegate_public, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegatePublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_PUBLIC *tpm_delegate_public); +void TPM_DelegatePublic_Delete(TPM_DELEGATE_PUBLIC *tpm_delegate_public); + +TPM_RESULT TPM_DelegatePublic_Copy(TPM_DELEGATE_PUBLIC *dest, + TPM_DELEGATE_PUBLIC *src); + +/* + TPM_DELEGATE_SENSITIVE +*/ + +void TPM_DelegateSensitive_Init(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive); +TPM_RESULT TPM_DelegateSensitive_Load(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegateSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive); +void TPM_DelegateSensitive_Delete(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive); + +TPM_RESULT TPM_DelegateSensitive_DecryptEncData(TPM_DELEGATE_SENSITIVE *tpm_delegate_sensitive, + TPM_SIZED_BUFFER *sensitiveArea, + TPM_SYMMETRIC_KEY_TOKEN delegateKey); + +/* + TPM_DELEGATIONS +*/ + +void TPM_Delegations_Init(TPM_DELEGATIONS *tpm_delegations); +TPM_RESULT TPM_Delegations_Load(TPM_DELEGATIONS *tpm_delegations, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Delegations_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATIONS *tpm_delegations); +void TPM_Delegations_Delete(TPM_DELEGATIONS *tpm_delegations); + +void TPM_Delegations_Copy(TPM_DELEGATIONS *dest, + TPM_DELEGATIONS *src); +TPM_RESULT TPM_Delegations_CheckPermissionDelegation(TPM_DELEGATIONS *newDelegations, + TPM_DELEGATIONS *currentDelegations); +TPM_RESULT TPM_Delegations_CheckPermission(tpm_state_t *tpm_state, + TPM_DELEGATE_PUBLIC *delegatePublic, + TPM_ENT_TYPE entityType, + TPM_COMMAND_CODE ordinal); +TPM_RESULT TPM_Delegations_CheckOwnerPermission(TPM_DELEGATIONS *tpm_delegations, + TPM_COMMAND_CODE ordinal); +TPM_RESULT TPM_Delegations_CheckKeyPermission(TPM_DELEGATIONS *tpm_delegations, + TPM_COMMAND_CODE ordinal); + +/* + TPM_DELEGATE_OWNER_BLOB +*/ + +void TPM_DelegateOwnerBlob_Init(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob); +TPM_RESULT TPM_DelegateOwnerBlob_Load(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegateOwnerBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob); +void TPM_DelegateOwnerBlob_Delete(TPM_DELEGATE_OWNER_BLOB *tpm_delegate_owner_blob); + +/* + TPM_DELEGATE_KEY_BLOB +*/ + +void TPM_DelegateKeyBlob_Init(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob); +TPM_RESULT TPM_DelegateKeyBlob_Load(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegateKeyBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob); +void TPM_DelegateKeyBlob_Delete(TPM_DELEGATE_KEY_BLOB *tpm_delegate_key_blob); + +/* + TPM_FAMILY_TABLE +*/ + +void TPM_FamilyTable_Init(TPM_FAMILY_TABLE *tpm_family_table); +TPM_RESULT TPM_FamilyTable_Load(TPM_FAMILY_TABLE *tpm_family_table, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_FamilyTable_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE *tpm_family_table, + TPM_BOOL store_tag); +void TPM_FamilyTable_Delete(TPM_FAMILY_TABLE *tpm_family_table); + +TPM_RESULT TPM_FamilyTable_StoreValid(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE *tpm_family_table, + TPM_BOOL store_tag); +TPM_RESULT TPM_FamilyTable_GetEntry(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, + TPM_FAMILY_TABLE *tpm_family_table, + TPM_FAMILY_ID familyID); +TPM_RESULT TPM_FamilyTable_GetEnabledEntry(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, + TPM_FAMILY_TABLE *tpm_family_table, + TPM_FAMILY_ID familyID); +TPM_RESULT TPM_FamilyTable_IsSpace(TPM_FAMILY_TABLE_ENTRY **tpm_family_table_entry, + TPM_FAMILY_TABLE *tpm_family_table); + +/* + TPM_FAMILY_TABLE_ENTRY +*/ + +void TPM_FamilyTableEntry_Init(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry); +TPM_RESULT TPM_FamilyTableEntry_Load(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_FamilyTableEntry_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + TPM_BOOL store_tag); +TPM_RESULT TPM_FamilyTableEntry_StorePublic(TPM_STORE_BUFFER *sbuffer, + const TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry, + TPM_BOOL store_tag); +void TPM_FamilyTableEntry_Delete(TPM_FAMILY_TABLE_ENTRY *tpm_family_table_entry); + +/* + TPM_DELEGATE_TABLE +*/ + +void TPM_DelegateTable_Init(TPM_DELEGATE_TABLE *tpm_delegate_table); +TPM_RESULT TPM_DelegateTable_Load(TPM_DELEGATE_TABLE *tpm_delegate_table, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegateTable_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE *tpm_delegate_table); +void TPM_DelegateTable_Delete(TPM_DELEGATE_TABLE *tpm_delegate_table); + +TPM_RESULT TPM_DelegateTable_StoreValid(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE *tpm_delegate_table); +TPM_RESULT TPM_DelegateTable_GetRow(TPM_DELEGATE_TABLE_ROW **delegateTableRow, + TPM_DELEGATE_TABLE *tpm_delegate_table, + uint32_t rowIndex); +TPM_RESULT TPM_DelegateTable_GetValidRow(TPM_DELEGATE_TABLE_ROW **delegateTableRow, + TPM_DELEGATE_TABLE *tpm_delegate_table, + uint32_t rowIndex); + + +/* + TPM_DELEGATE_TABLE_ROW +*/ + +void TPM_DelegateTableRow_Init(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row); +TPM_RESULT TPM_DelegateTableRow_Load(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_DelegateTableRow_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row); +void TPM_DelegateTableRow_Delete(TPM_DELEGATE_TABLE_ROW *tpm_delegate_table_row); + + + + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_DelegateManage(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_DelegateCreateKeyDelegation(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_DelegateCreateOwnerDelegation(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_DelegateLoadOwnerDelegation(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_DelegateReadTable(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_DelegateUpdateVerification(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_DelegateVerifyDelegation(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +#endif diff --git a/src/tpm_digest.c b/src/tpm_digest.c new file mode 100644 index 00000000..acad1406 --- /dev/null +++ b/src/tpm_digest.c @@ -0,0 +1,161 @@ +/********************************************************************************/ +/* */ +/* Digest Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_digest.c 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_structures.h" + +#include "tpm_digest.h" + +/* TPM_Digest_Init resets a digest structure to zeros */ + +void TPM_Digest_Init(TPM_DIGEST tpm_digest) +{ + printf(" TPM_Digest_Init:\n"); + memset(tpm_digest, 0, TPM_DIGEST_SIZE); + return; +} + +/* TPM_Digest_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_Digest_Load(TPM_DIGEST tpm_digest, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Digest_Load:\n"); + rc = TPM_Loadn(tpm_digest, TPM_DIGEST_SIZE, stream, stream_size); + return rc; +} + +/* TPM_Digest_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + After use, call TPM_Sbuffer_Delete() to free memory +*/ + +TPM_RESULT TPM_Digest_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DIGEST tpm_digest) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Digest_Store:\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_digest, TPM_DIGEST_SIZE); + return rc; +} + +void TPM_Digest_Set(TPM_DIGEST tpm_digest) +{ + printf(" TPM_Digest_Set:\n"); + memset(tpm_digest, 0xff, TPM_DIGEST_SIZE); +} + +void TPM_Digest_Copy(TPM_DIGEST destination, const TPM_DIGEST source) +{ + printf(" TPM_Digest_Copy:\n"); + memcpy(destination, source, TPM_DIGEST_SIZE); + return; +} + +void TPM_Digest_XOR(TPM_DIGEST out, const TPM_DIGEST in1, const TPM_DIGEST in2) +{ + size_t i; + + printf(" TPM_Digest_XOR:\n"); + for (i = 0 ; i < TPM_DIGEST_SIZE ; i++) { + out[i] = in1[i] ^ in2[i]; + } + return; +} + +/* TPM_Digest_Compare() compares two digests, returning 0 if they are equal + */ + +TPM_RESULT TPM_Digest_Compare(const TPM_DIGEST expect, const TPM_DIGEST actual) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Digest_Compare:\n"); + rc = memcmp(expect, actual, TPM_DIGEST_SIZE); + if (rc != 0) { + printf("TPM_Digest_Compare: Error comparing digest\n"); + TPM_PrintFour(" TPM_Digest_Compare: Expect", expect); + TPM_PrintFour(" TPM_Digest_Compare: Actual", actual); + rc = TPM_AUTHFAIL; + } + return rc; +} + +void TPM_Digest_IsZero(TPM_BOOL *isZero, TPM_DIGEST tpm_digest) +{ + size_t i; + + printf(" TPM_Digest_IsZero:\n"); + for (i = 0, *isZero = TRUE ; (i < TPM_DIGEST_SIZE) && *isZero ; i++) { + if (tpm_digest[i] != 0) { + *isZero = FALSE; + } + } + return; +} + +void TPM_Digest_IsMinusOne(TPM_BOOL *isMinusOne, TPM_DIGEST tpm_digest) +{ + size_t i; + + printf(" TPM_Digest_IsMinusOne:\n"); + for (i = 0, *isMinusOne = TRUE ; (i < TPM_DIGEST_SIZE) && *isMinusOne ; i++) { + if (tpm_digest[i] != 0xff) { + *isMinusOne = FALSE; + } + } + return; +} + diff --git a/src/tpm_digest.h b/src/tpm_digest.h new file mode 100644 index 00000000..bbff1c62 --- /dev/null +++ b/src/tpm_digest.h @@ -0,0 +1,62 @@ +/********************************************************************************/ +/* */ +/* Digest Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_digest.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_DIGEST_H +#define TPM_DIGEST_H + +#include "tpm_structures.h" +#include "tpm_store.h" + +void TPM_Digest_Init(TPM_DIGEST tpm_digest); +TPM_RESULT TPM_Digest_Load(TPM_DIGEST tpm_digest, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Digest_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_DIGEST tpm_digest); + +void TPM_Digest_Set(TPM_DIGEST tpm_digest); +void TPM_Digest_Copy(TPM_DIGEST destination, const TPM_DIGEST source); +void TPM_Digest_XOR(TPM_DIGEST out, + const TPM_DIGEST in1, + const TPM_DIGEST in2); +TPM_RESULT TPM_Digest_Compare(const TPM_DIGEST expect, const TPM_DIGEST actual); +void TPM_Digest_IsZero(TPM_BOOL *isZero, TPM_DIGEST tpm_digest); +void TPM_Digest_IsMinusOne(TPM_BOOL *isMinusOne, TPM_DIGEST tpm_digest); + +#endif diff --git a/src/tpm_error.c b/src/tpm_error.c new file mode 100644 index 00000000..b4c47d84 --- /dev/null +++ b/src/tpm_error.c @@ -0,0 +1,43 @@ +/********************************************************************************/ +/* */ +/* Error Response */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_error.c 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_error.h" + diff --git a/src/tpm_global.c b/src/tpm_global.c new file mode 100644 index 00000000..38aba915 --- /dev/null +++ b/src/tpm_global.c @@ -0,0 +1,233 @@ +/********************************************************************************/ +/* */ +/* Global Variables */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_global.c 4621 2011-09-09 20:19:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_init.h" +#include "tpm_key.h" +#include "tpm_nvfile.h" +#include "tpm_nvram.h" +#include "tpm_permanent.h" +#include "tpm_platform.h" +#include "tpm_startup.h" +#include "tpm_structures.h" + + +#include "tpm_global.h" + +/* state for the TPM's */ +tpm_state_t *tpm_instances[TPMS_MAX]; + +/* TPM_Global_Init initializes the tpm_state to default values. + + It does not load any data from or store data to NVRAM +*/ + +TPM_RESULT TPM_Global_Init(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf("TPM_Global_Init: TPMs %lu\n", + (unsigned long)sizeof(tpm_instances)/sizeof(tpm_state_t *)); + /* initialize the TPM_STANY_FLAGS structure */ + if (rc == 0) { + /* set the structure to 0 for security, clean out old secrets */ + memset(tpm_state, 0 , sizeof(tpm_state_t)); + /* the virtual TPM number NOTE: This must be done early as it is used to construct + nn.permall file names */ + tpm_state->tpm_number = TPM_ILLEGAL_INSTANCE_HANDLE; + /* initialize the TPM_PERMANENT_FLAGS structure */ + printf("TPM_Global_Init: Initializing TPM_PERMANENT_FLAGS\n"); + TPM_PermanentFlags_Init(&(tpm_state->tpm_permanent_flags)); + /* initialize the TPM_STCLEAR_FLAGS structure */ + printf("TPM_Global_Init: Initializing TPM_STCLEAR_FLAGS\n"); + TPM_StclearFlags_Init(&(tpm_state->tpm_stclear_flags)); + /* initialize the TPM_STANY_FLAGS structure */ + printf("TPM_Global_Init: Initializing TPM_STANY_FLAGS\n"); + TPM_StanyFlags_Init(&(tpm_state->tpm_stany_flags)); + /* initialize TPM_PERMANENT_DATA structure */ + printf("TPM_Global_Init: Initializing TPM_PERMANENT_DATA\n"); + rc = TPM_PermanentData_Init(&(tpm_state->tpm_permanent_data), TRUE); + } + if (rc == 0) { + /* initialize TPM_STCLEAR_DATA structure */ + printf("TPM_Global_Init: Initializing TPM_STCLEAR_DATA\n"); + TPM_StclearData_Init(&(tpm_state->tpm_stclear_data), + tpm_state->tpm_permanent_data.pcrAttrib, + TRUE); /* initialize the PCR's */ + /* initialize TPM_STANY_DATA structure */ + printf("TPM_Global_Init: Initializing TPM_STANY_DATA\n"); + rc = TPM_StanyData_Init(&(tpm_state->tpm_stany_data)); + } + /* initialize the TPM_KEY_HANDLE_LIST structure */ + if (rc == 0) { + printf("TPM_Global_Init: Initializing TPM_KEY_HANDLE_LIST\n"); + TPM_KeyHandleEntries_Init(tpm_state->tpm_key_handle_entries); + /* initialize the SHA1 thread context */ + tpm_state->sha1_context = NULL; + /* initialize the TIS SHA1 thread context */ + tpm_state->sha1_context_tis = NULL; + tpm_state->transportHandle = 0; + printf("TPM_Global_Init: Initializing TPM_NV_INDEX_ENTRIES\n"); + TPM_NVIndexEntries_Init(&(tpm_state->tpm_nv_index_entries)); + } + /* comes up in limited operation mode */ + /* shutdown is set on a self test failure, before calling TPM_Global_Init() */ + if (rc == 0) { + printf(" TPM_Global_Init: Set testState to %u \n", TPM_TEST_STATE_LIMITED); + tpm_state->testState = TPM_TEST_STATE_LIMITED; + } + else { + printf(" TPM_Global_Init: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return rc; +} + +/* TPM_Global_Load() loads the tpm_state_t global structures for the TPM instance from NVRAM. + + tpm_state->tpm_number must be set by the caller. + + Returns + + 0 on success. + TPM_FAIL on failure to load (fatal), since it should never occur +*/ + +TPM_RESULT TPM_Global_Load(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf("TPM_Global_Load:\n"); + /* TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, owner evict keys, and NV defined space. */ + if (rc == 0) { + rc = TPM_PermanentAll_NVLoad(tpm_state); + } + if (rc == 0) { + rc = TPM_VolatileAll_NVLoad(tpm_state); + } + return rc; +} + +/* TPM_Global_Store() store the tpm_state_t global structure for the TPM instance to NVRAM + + tpm_state->tpm_number must be set by the caller. +*/ + +TPM_RESULT TPM_Global_Store(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Global_Store:\n"); + if (rc == 0) { + rc = TPM_PermanentAll_NVStore(tpm_state, TRUE, 0); + } + if (rc == 0) { + rc = TPM_VolatileAll_NVStore(tpm_state); + } + return rc; +} + +/* TPM_Global_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_Global_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_Global_Delete(tpm_state_t *tpm_state) +{ + printf(" TPM_Global_Delete:\n"); + if (tpm_state != NULL) { + /* TPM_PERMANENT_FLAGS have no allocated memory or secrets */ + /* TPM_STCLEAR_FLAGS have no allocated memory or secrets */ + /* TPM_STANY_FLAGS have no allocated memory or secrets */ + printf(" TPM_Global_Delete: Deleting TPM_PERMANENT_DATA\n"); + TPM_PermanentData_Delete(&(tpm_state->tpm_permanent_data), TRUE); + printf(" TPM_Global_Delete: Deleting TPM_STCLEAR_DATA\n"); + TPM_StclearData_Delete(&(tpm_state->tpm_stclear_data), + tpm_state->tpm_permanent_data.pcrAttrib, + TRUE); /* reset the PCR's */ + printf(" TPM_Global_Delete: Deleting TPM_STANY_DATA\n"); + TPM_StanyData_Delete(&(tpm_state->tpm_stany_data)); + printf(" TPM_Global_Delete: Deleting key handle entries\n"); + TPM_KeyHandleEntries_Delete(tpm_state->tpm_key_handle_entries); + printf(" TPM_Global_Delete: Deleting SHA1 contexts\n"); + TPM_SHA1Delete(&(tpm_state->sha1_context)); + TPM_SHA1Delete(&(tpm_state->sha1_context_tis)); + TPM_NVIndexEntries_Delete(&(tpm_state->tpm_nv_index_entries)); + } + return; +} + + +/* TPM_Global_GetPhysicalPresence() returns 'physicalPresence' TRUE if either TPM_STCLEAR_FLAGS -> + physicalPresence is TRUE or hardware physical presence is indicated. +*/ + +TPM_RESULT TPM_Global_GetPhysicalPresence(TPM_BOOL *physicalPresence, + const tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + /* check for physicalPresence set by the command ordinal */ + *physicalPresence = tpm_state->tpm_stclear_flags.physicalPresence; + printf(" TPM_Global_GetPhysicalPresence: physicalPresence flag is %02x\n", *physicalPresence); + /* if the software flag is true, result is true, no need to check the hardware */ + /* if the TPM_STCLEAR_FLAGS flag is FALSE, check the hardware */ + if (!(*physicalPresence)) { + /* if physicalPresenceHWEnable is FALSE, the hardware signal is disabled */ + if (tpm_state->tpm_permanent_flags.physicalPresenceHWEnable) { + /* If it's TRUE, check the hardware signal */ + rc = TPM_IO_GetPhysicalPresence(physicalPresence, tpm_state->tpm_number); + printf(" TPM_Global_GetPhysicalPresence: physicalPresence signal is %02x\n", + *physicalPresence); + } + } + return rc; +} + diff --git a/src/tpm_global.h b/src/tpm_global.h new file mode 100644 index 00000000..0bc07ebd --- /dev/null +++ b/src/tpm_global.h @@ -0,0 +1,101 @@ +/********************************************************************************/ +/* */ +/* Global Variables */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_global.h 4285 2011-01-17 21:27:05Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_GLOBAL_H +#define TPM_GLOBAL_H + +#include "tpm_nvram_const.h" +#include "tpm_types.h" +#include "tpm_structures.h" + +#define TPM_TEST_STATE_LIMITED 1 /* limited operation mode */ +#define TPM_TEST_STATE_FULL 2 /* full operation mode */ +#define TPM_TEST_STATE_FAILURE 3 /* failure mode */ + +typedef struct tdTPM_STATE +{ + /* the number of the virtual TPM */ + uint32_t tpm_number; + /* 7.1 TPM_PERMANENT_FLAGS */ + TPM_PERMANENT_FLAGS tpm_permanent_flags; + /* 7.2 TPM_STCLEAR_FLAGS */ + TPM_STCLEAR_FLAGS tpm_stclear_flags; + /* 7.3 TPM_STANY_FLAGS */ + TPM_STANY_FLAGS tpm_stany_flags; + /* 7.4 TPM_PERMANENT_DATA */ + TPM_PERMANENT_DATA tpm_permanent_data; + /* 7.5 TPM_STCLEAR_DATA */ + TPM_STCLEAR_DATA tpm_stclear_data; + /* 7.6 TPM_STANY_DATA */ + TPM_STANY_DATA tpm_stany_data; + /* 5.6 TPM_KEY_HANDLE_ENTRY */ + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entries[TPM_KEY_HANDLES]; + /* Context for SHA1 functions */ + void *sha1_context; + void *sha1_context_tis; + TPM_TRANSHANDLE transportHandle; /* non-zero if the context was set up in a transport + session */ + /* self test shutdown */ + uint32_t testState; + /* NVRAM volatile data marker. Cleared at TPM_Startup(ST_Clear), it holds all indexes which + have been read. The index not being present indicates that some volatile fields should be + cleared at first read. */ + TPM_NV_INDEX_ENTRIES tpm_nv_index_entries; + /* NOTE: members added here should be initialized by TPM_Global_Init() and possibly added to + TPM_SaveState_Load() and TPM_SaveState_Store() */ +} tpm_state_t; + +/* state for the TPM */ +extern tpm_state_t *tpm_instances[]; + + +/* + tpm_state_t +*/ + +TPM_RESULT TPM_Global_Init(tpm_state_t *tpm_state); +TPM_RESULT TPM_Global_Load(tpm_state_t *tpm_state); +TPM_RESULT TPM_Global_Store(tpm_state_t *tpm_state); +void TPM_Global_Delete(tpm_state_t *tpm_state); + + +TPM_RESULT TPM_Global_GetPhysicalPresence(TPM_BOOL *physicalPresence, + const tpm_state_t *tpm_state); + +#endif diff --git a/src/tpm_identity.c b/src/tpm_identity.c new file mode 100644 index 00000000..8a1f9711 --- /dev/null +++ b/src/tpm_identity.c @@ -0,0 +1,1439 @@ +/********************************************************************************/ +/* */ +/* TPM Identity Handling */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_identity.c 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_storage.h" +#include "tpm_ver.h" +#include "tpm_identity.h" + +/* + TPM_EK_BLOB +*/ + +/* TPM_EKBlob_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_EKBlob_Init(TPM_EK_BLOB *tpm_ek_blob) +{ + printf(" TPM_EKBlob_Init:\n"); + tpm_ek_blob->ekType = 0; + TPM_SizedBuffer_Init(&(tpm_ek_blob->blob)); + return; +} + +/* TPM_EKBlob_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_EKBlob_Init() + After use, call TPM_EKBlob_Delete() to free memory +*/ + +TPM_RESULT TPM_EKBlob_Load(TPM_EK_BLOB *tpm_ek_blob, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlob_Load:\n"); + /* check the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_EK_BLOB, stream, stream_size); + } + /* load ekType */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_ek_blob->ekType), stream, stream_size); + } + /* load blob */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_ek_blob->blob), stream, stream_size); + } + return rc; +} + +/* TPM_EKBlob_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_EKBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB *tpm_ek_blob) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlob_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_EK_BLOB); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_ek_blob->ekType); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_ek_blob->blob)); + } + return rc; +} + +/* TPM_EKBlob_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_EKBlob_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_EKBlob_Delete(TPM_EK_BLOB *tpm_ek_blob) +{ + printf(" TPM_EKBlob_Delete:\n"); + if (tpm_ek_blob != NULL) { + TPM_SizedBuffer_Delete(&(tpm_ek_blob->blob)); + TPM_EKBlob_Init(tpm_ek_blob); + } + return; +} + +/* + TPM_EK_BLOB_ACTIVATE +*/ + +/* TPM_EKBlobActivate_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_EKBlobActivate_Init(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate) +{ + printf(" TPM_EKBlobActivate_Init:\n"); + TPM_SymmetricKey_Init(&(tpm_ek_blob_activate->sessionKey)); + TPM_Digest_Init(tpm_ek_blob_activate->idDigest); + TPM_PCRInfoShort_Init(&(tpm_ek_blob_activate->pcrInfo)); + return; +} + +/* TPM_EKBlobActivate_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_EKBlobActivate_Init() + After use, call TPM_EKBlobActivate_Delete() to free memory +*/ + +TPM_RESULT TPM_EKBlobActivate_Load(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlobActivate_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_EK_BLOB_ACTIVATE, stream, stream_size); + } + /* load sessionKey */ + if (rc == 0) { + rc = TPM_SymmetricKey_Load(&(tpm_ek_blob_activate->sessionKey), stream, stream_size); + } + /* load idDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_ek_blob_activate->idDigest, stream, stream_size); + } + /* load pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Load(&(tpm_ek_blob_activate->pcrInfo), stream, stream_size, FALSE); + } + return rc; +} + +/* TPM_EKBlobActivate_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_EKBlobActivate_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlobActivate_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_EK_BLOB_ACTIVATE); + } + /* store sessionKey */ + if (rc == 0) { + rc = TPM_SymmetricKey_Store(sbuffer, &(tpm_ek_blob_activate->sessionKey)); + } + /* store idDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_ek_blob_activate->idDigest); + } + /* store pcrInfo */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_ek_blob_activate->pcrInfo), FALSE); + } + return rc; +} + +/* TPM_EKBlobActivate_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_EKBlobActivate_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_EKBlobActivate_Delete(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate) +{ + printf(" TPM_EKBlobActivate_Delete:\n"); + if (tpm_ek_blob_activate != NULL) { + TPM_SymmetricKey_Delete(&(tpm_ek_blob_activate->sessionKey)); + TPM_PCRInfoShort_Delete(&(tpm_ek_blob_activate->pcrInfo)); + TPM_EKBlobActivate_Init(tpm_ek_blob_activate); + } + return; +} + +/* + TPM_EK_BLOB_AUTH +*/ + +/* TPM_EKBlobAuth_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_EKBlobAuth_Init(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth) +{ + printf(" TPM_EKBlobAuth_Init:\n"); + TPM_Secret_Init(tpm_ek_blob_auth->authValue); + return; +} + +/* TPM_EKBlobAuth_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_EKBlobAuth_Init() + After use, call TPM_EKBlobAuth_Delete() to free memory +*/ + +TPM_RESULT TPM_EKBlobAuth_Load(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlobAuth_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_EK_BLOB_AUTH, stream, stream_size); + } + /* load authValue */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_ek_blob_auth->authValue, stream, stream_size); + } + return rc; +} + +/* TPM_EKBlobAuth_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_EKBlobAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB_AUTH *tpm_ek_blob_auth) +{ + TPM_RESULT rc = 0; + + printf(" TPM_EKBlobAuth_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_EK_BLOB_AUTH); + } + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_ek_blob_auth->authValue); + } + return rc; +} + +/* TPM_EKBlobAuth_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_EKBlobAuth_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_EKBlobAuth_Delete(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth) +{ + printf(" TPM_EKBlobAuth_Delete:\n"); + if (tpm_ek_blob_auth != NULL) { + TPM_EKBlobAuth_Init(tpm_ek_blob_auth); + } + return; +} + +/* + TPM_IDENTITY_CONTENTS +*/ + +/* TPM_IdentityContents_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_IdentityContents_Init(TPM_IDENTITY_CONTENTS *tpm_identity_contents) +{ + printf(" TPM_IdentityContents_Init:\n"); + TPM_StructVer_Init(&(tpm_identity_contents->ver)); + tpm_identity_contents->ordinal = TPM_ORD_MakeIdentity; + TPM_Digest_Init(tpm_identity_contents->labelPrivCADigest); + TPM_Pubkey_Init(&(tpm_identity_contents->identityPubKey)); + return; +} + +/* TPM_IdentityContents_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_IdentityContents_Init() + After use, call TPM_IdentityContents_Delete() to free memory + + NOTE: Never called. +*/ + +TPM_RESULT TPM_IdentityContents_Load(TPM_IDENTITY_CONTENTS *tpm_identity_contents, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_IdentityContents_Load:\n"); + /* load ver */ + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_identity_contents->ver), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_identity_contents->ver)); + } + /* load ordinal */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_identity_contents->ordinal), stream, stream_size); + } + /* load labelPrivCADigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_identity_contents->labelPrivCADigest, stream, stream_size); + } + /* load identityPubKey */ + if (rc == 0) { + rc = TPM_Pubkey_Load(&(tpm_identity_contents->identityPubKey), stream, stream_size); + } + return rc; +} + +/* TPM_IdentityContents_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_IdentityContents_Store(TPM_STORE_BUFFER *sbuffer, + TPM_IDENTITY_CONTENTS *tpm_identity_contents) +{ + TPM_RESULT rc = 0; + + printf(" TPM_IdentityContents_Store:\n"); + /* store ver */ + if (rc == 0) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_identity_contents->ver)); + } + /* store ordinal */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_identity_contents->ordinal); + } + /* store labelPrivCADigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_identity_contents->labelPrivCADigest); + } + /* store identityPubKey */ + if (rc == 0) { + rc = TPM_Pubkey_Store(sbuffer, &(tpm_identity_contents->identityPubKey)); + } + return rc; +} + +/* TPM_IdentityContents_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_IdentityContents_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_IdentityContents_Delete(TPM_IDENTITY_CONTENTS *tpm_identity_contents) +{ + printf(" TPM_IdentityContents_Delete:\n"); + if (tpm_identity_contents != NULL) { + TPM_Pubkey_Delete(&(tpm_identity_contents->identityPubKey)); + TPM_IdentityContents_Init(tpm_identity_contents); + } + return; +} + +/* + TPM_ASYM_CA_CONTENTS +*/ + +/* TPM_AsymCaContents_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_AsymCaContents_Init(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents) +{ + printf(" TPM_AsymCaContents_Init:\n"); + TPM_SymmetricKey_Init(&(tpm_asym_ca_contents->sessionKey)); + TPM_Digest_Init(tpm_asym_ca_contents->idDigest); + return; +} + +/* TPM_AsymCaContents_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_AsymCaContents_Init() + After use, call TPM_AsymCaContents_Delete() to free memory +*/ + +TPM_RESULT TPM_AsymCaContents_Load(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AsymCaContents_Load:\n"); + if (rc == 0) { + rc = TPM_SymmetricKey_Load(&(tpm_asym_ca_contents->sessionKey), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Digest_Load(tpm_asym_ca_contents->idDigest, stream, stream_size); + } + return rc; +} + +/* TPM_AsymCaContents_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_AsymCaContents_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AsymCaContents_Store:\n"); + if (rc == 0) { + rc = TPM_SymmetricKey_Store(sbuffer, &(tpm_asym_ca_contents->sessionKey)); + } + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_asym_ca_contents->idDigest); + } + return rc; +} + +/* TPM_AsymCaContents_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_AsymCaContents_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_AsymCaContents_Delete(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents) +{ + printf(" TPM_AsymCaContents_Delete:\n"); + if (tpm_asym_ca_contents != NULL) { + TPM_SymmetricKey_Delete(&(tpm_asym_ca_contents->sessionKey)); + TPM_AsymCaContents_Init(tpm_asym_ca_contents); + } + return; +} + + + + + + +/* + Processing Functions +*/ + +/* 15.1 TPM_MakeIdentity rev 114 + + Generate a new Attestation Identity Key (AIK) + + labelPrivCADigest identifies the privacy CA that the owner expects to be the target CA for the + AIK. The selection is not enforced by the TPM. It is advisory only. It is included because the + TSS cannot be trusted to send the AIK to the correct privacy CA. The privacy CA can use this + parameter to validate that it is the target privacy CA and label intended by the TPM owner at the + time the key was created. The label can be used to indicate an application purpose. + + The public key of the new TPM identity SHALL be identityPubKey. The private key of the new TPM + identity SHALL be tpm_signature_key. + + Properties of the new identity + + TPM_PUBKEY identityPubKey This SHALL be the public key of a previously unused asymmetric key + pair. + + TPM_STORE_ASYMKEY tpm_signature_key This SHALL be the private key that forms a pair with + identityPubKey and SHALL be extant only in a TPM-shielded location. + + This capability also generates a TPM_KEY containing the tpm_signature_key. + + If identityPubKey is stored on a platform it SHALL exist only in storage to which access is + controlled and is available to authorized entities. +*/ + +TPM_RESULT TPM_Process_MakeIdentity(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_ENCAUTH identityAuth; /* Encrypted usage authorization data for the new identity + */ + TPM_CHOSENID_HASH labelPrivCADigest; /* The digest of the identity label and privacy CA + chosen for the new TPM identity. */ + TPM_KEY idKeyParams; /* Structure containing all parameters of new identity + key. pubKey.keyLength & idKeyParams.encData are both 0 + MAY be TPM_KEY12 */ + TPM_AUTHHANDLE srkAuthHandle; /* The authorization handle used for SRK authorization. */ + TPM_NONCE srknonceOdd; /* Nonce generated by system associated with srkAuthHandle + */ + TPM_BOOL continueSrkSession = TRUE; /* Ignored */ + TPM_AUTHDATA srkAuth; /* The authorization digest for the inputs and the SRK. HMAC + key: srk.usageAuth. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner + authorization. Session type MUST be OSAP. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner. HMAC key: + ownerAuth. */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL srkAuthHandleValid = FALSE; + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *srk_auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for dataAuthHandle */ + TPM_SECRET *srkHmacKey; + TPM_SECRET *hmacKey; + TPM_SECRET a1Auth; + TPM_STORE_ASYMKEY *idKeyStoreAsymkey; + TPM_IDENTITY_CONTENTS idContents; + TPM_DIGEST h1Digest; /* digest of TPM_IDENTITY_CONTENTS structure */ + int ver; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY idKey; /* The newly created identity key. MAY be TPM_KEY12 + */ + TPM_SIZED_BUFFER identityBinding; /* Signature of TPM_IDENTITY_CONTENTS using + idKey.private. */ + printf("TPM_Process_MakeIdentity: Ordinal Entry\n"); + TPM_Key_Init(&idKeyParams); /* freed @1 */ + TPM_Key_Init(&idKey); /* freed @2 */ + TPM_SizedBuffer_Init(&identityBinding); /* freed @3 */ + TPM_IdentityContents_Init(&idContents); /* freed @4 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get identityAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(identityAuth, &command, ¶mSize); + } + /* get labelPrivCADigest parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(labelPrivCADigest, &command, ¶mSize); + } + /* get idKeyParams parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&idKeyParams, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag21(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&srkAuthHandle, + &srkAuthHandleValid, + srknonceOdd, + &continueSrkSession, + srkAuth, + &command, ¶mSize); + printf("TPM_Process_MakeIdentity: srkAuthHandle %08x\n", srkAuthHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MakeIdentity: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_MakeIdentity: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + srkAuthHandleValid = FALSE; + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the idKeyParams parameters for the key description */ + /* a. If the algorithm type is RSA the key length MUST be a minimum of 2048 and MUST use the + default exponent. 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 */ + /* d. If TPM_PERMANENT_FLAGS -> FIPS is TRUE then */ + /* i. If authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_CheckProperties(&ver, &idKeyParams, 2048, + tpm_state->tpm_permanent_flags.FIPS); + printf("TPM_Process_MakeIdentity: key parameters v = %d\n", ver); + } + /* 2. Use authHandle to verify that the Owner authorized all TPM_MakeIdentity input + parameters. */ + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_OWNER, + ordinal, + NULL, + NULL, + tpm_state->tpm_permanent_data.ownerAuth); + } + /* Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Auth2data_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 3. Use srkAuthHandle to verify that the SRK owner authorized all TPM_MakeIdentity input + parameters. */ + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData + (&srk_auth_session_data, + &srkHmacKey, + tpm_state, + srkAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + &(tpm_state->tpm_permanent_data.srk), + /* OIAP */ + &(tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->usageAuth), + /* OSAP */ + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest); + } + /* Validate the authorization to use the key pointed to by keyHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *srkHmacKey, /* HMAC key */ + inParamDigest, + srk_auth_session_data, /* authorization session */ + srknonceOdd, /* Nonce generated by system + associated with authHandle */ + continueSrkSession, + srkAuth); /* Authorization digest for input */ + } + /* if there is no SRK authorization, check that the SRK authDataUsage is TPM_AUTH_NEVER */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (tpm_state->tpm_permanent_data.srk.authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_MakeIdentity: Error, SRK authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 4. Verify that idKeyParams -> keyUsage is TPM_KEY_IDENTITY. If it is not, return + TPM_INVALID_KEYUSAGE */ + /* NOTE: TPM_KEY_IDENTITY keys must use TPM_SS_RSASSAPKCS1v15_SHA1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MakeIdentity: Checking key parameters\n"); + if (idKeyParams.keyUsage != TPM_KEY_IDENTITY) { + printf("TPM_Process_MakeIdentity: Error, " + "idKeyParams keyUsage %08x should be TPM_KEY_IDENTITY\n", + idKeyParams.keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Verify that idKeyParams -> keyFlags -> migratable is FALSE. If it is not, return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (idKeyParams.keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_MakeIdentity: Error, " + "idKeyParams keyFlags %08x cannot be migratable\n", + idKeyParams.keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. Create a1 by decrypting identityAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + identityAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 7. Set continueAuthSession and continueSRKSession to FALSE. */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + continueSrkSession = FALSE; + /* 8. Determine the structure version */ + /* a. If idKeyParams -> tag is TPM_TAG_KEY12 */ + /* i. Set V1 to 2 */ + /* ii. Create idKey a TPM_KEY12 structure using idKeyParams as the default values for the + structure */ + /* b. If idKeyParams -> 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 */ + /* NOTE Done by TPM_Key_CheckProperties() */ + /* NOTE The creation determination is done by TPM_Key_GenerateRSA() */ + } + /* 9. Set the digestAtCreation values for pcrInfo */ + /* NOTE Done as the key is generated */ + /* a. For PCR_INFO_LONG include the locality of the current command */ + /* 10. Create an asymmetric key pair (identityPubKey and tpm_signature_key) using a + TPM-protected capability, in accordance with the algorithm specified in idKeyParams */ + if (returnCode == TPM_SUCCESS) { + /* generate the key pair, create the tpm_store_asymkey cache, copy key parameters, create + tpm_pcr_info cache, copies pcr parameters, sets digestAtCreation, sets pubKey, serializes + pcrInfo + + does not set encData */ + printf("TPM_Process_MakeIdentity: Generating key\n"); + returnCode = TPM_Key_GenerateRSA(&idKey, + tpm_state, + &(tpm_state->tpm_permanent_data.srk), /* parent key */ + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + ver, + idKeyParams.keyUsage, + idKeyParams.keyFlags, + idKeyParams.authDataUsage, /* TPM_AUTH_DATA_USAGE */ + &(idKeyParams.algorithmParms), /* TPM_KEY_PARMS */ + idKeyParams.tpm_pcr_info, /* TPM_PCR_INFO */ + idKeyParams.tpm_pcr_info_long);/* TPM_PCR_INFO_LONG */ + + } + /* 11. Ensure that the authorization information in A1 is properly stored in the idKey as + usageAuth. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetStoreAsymkey(&idKeyStoreAsymkey, + &idKey); + } + if (returnCode == TPM_SUCCESS) { + TPM_Secret_Copy(idKeyStoreAsymkey->usageAuth, a1Auth); + /* 12. Attach identityPubKey and tpm_signature_key to idKey */ + /* Note: Done as the key is generated */ + /* 13. Set idKey -> migrationAuth to TPM_PERMANENT_DATA -> tpmProof */ + TPM_Secret_Copy(idKeyStoreAsymkey->migrationAuth, tpm_state->tpm_permanent_data.tpmProof); + /* 14. Ensure that all TPM_PAYLOAD_TYPE structures identity this key as TPM_PT_ASYM */ + /* NOTE Done as the key is generated */ + } + /* 15. Encrypt the private portion of idKey using the SRK as the parent key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MakeIdentity: Encrypting key private part with SRK\n"); + returnCode = TPM_Key_GenerateEncData(&idKey, &(tpm_state->tpm_permanent_data.srk)); + } + /* 16. Create a TPM_IDENTITY_CONTENTS structure named idContents using labelPrivCADigest and the + information from idKey */ + if (returnCode == TPM_SUCCESS) { + TPM_Digest_Copy(idContents.labelPrivCADigest, labelPrivCADigest); + returnCode = TPM_Pubkey_Set(&(idContents.identityPubKey), &idKey); + } + /* 17. Sign idContents using tpm_signature_key and TPM_SS_RSASSAPKCS1v15_SHA1. Store the result + in identityBinding. */ + /* NOTE: TPM_Key_CheckProperties() verified TPM_SS_RSASSAPKCS1v15_SHA1 */ + /* serialize tpm_identity_contents and hash the results*/ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(h1Digest, + &idContents, + (TPM_STORE_FUNCTION_T)TPM_IdentityContents_Store); + } + /* sign the digest */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MakeIdentity: Signing digest of TPM_IDENTITY_CONTENTS\n"); + returnCode = TPM_RSASignToSizedBuffer(&identityBinding, h1Digest, TPM_DIGEST_SIZE, &idKey); + } +#if 0 /* NOTE Debug code to reverse the signature */ + if (returnCode == TPM_SUCCESS) { + unsigned char *message = NULL; + unsigned char *narr = NULL; + uint32_t nbytes; + unsigned char *earr = NULL; + uint32_t ebytes; + if (returnCode == 0) { + returnCode = TPM_Malloc(&message, identityBinding.size); /* freed @10 */ + } + if (returnCode == 0) { + returnCode = TPM_Key_GetPublicKey(&nbytes, &narr, &idKey); + } + if (returnCode == 0) { + returnCode = TPM_Key_GetExponent(&ebytes, &earr, &idKey); + } + if (returnCode == 0) { + returnCode = TPM_RSAPublicEncryptRaw(message, /* output */ + identityBinding.size, + identityBinding.buffer, /* input */ + identityBinding.size, + narr, /* public modulus */ + nbytes, + earr, /* public exponent */ + ebytes); + } + free(message); /* @10 */ + } +#endif + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_MakeIdentity: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return idKey */ + returnCode = TPM_Key_Store(response, &idKey); + } + if (returnCode == TPM_SUCCESS) { + /* return identityBinding */ + returnCode = TPM_SizedBuffer_Store(response, &identityBinding); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *srkHmacKey, /* owner HMAC key */ + srk_auth_session_data, + outParamDigest, + srknonceOdd, + continueSrkSession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueSrkSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueSrkSession) && + srkAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, srkAuthHandle); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_Key_Delete(&idKeyParams); /* freed @1 */ + TPM_Key_Delete(&idKey); /* freed @2 */ + TPM_SizedBuffer_Delete(&identityBinding); /* freed @3 */ + TPM_IdentityContents_Delete(&idContents); /* freed @4 */ + return rcf; +} + +/* 15.2 TPM_ActivateIdentity rev 107 + + 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. + + The command TPM_ActivateIdentity activates a TPM identity created using the command + TPM_MakeIdentity. + + The command assumes the availability of the private key associated with the identity. The command + will verify the association between the keys during the process. + + The command will decrypt the input blob and extract the session key and verify the connection + between the public and private keys. The input blob can be in 1.1 or 1.2 format. +*/ + +TPM_RESULT TPM_Process_ActivateIdentity(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE idKeyHandle; /* handle of identity key to be activated */ + TPM_SIZED_BUFFER blob; /* The encrypted ASYM_CA_CONTENTS or TPM_EK_BLOB */ + TPM_AUTHHANDLE idKeyAuthHandle; /* The authorization handle used for ID key + authorization. */ + TPM_NONCE idKeynonceOdd; /* Nonce generated by system associated with idKeyAuthHandle + */ + TPM_BOOL continueIdKeySession = TRUE; /* Continue usage flag for idKeyAuthHandle. */ + TPM_AUTHDATA idKeyAuth; /* The authorization digest for the inputs and ID key. HMAC + key: idKey.usageAuth. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and + owner. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL idKeyAuthHandleValid = FALSE; + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *id_key_auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for dataAuthHandle */ + TPM_SECRET *idKeyHmacKey; + TPM_SECRET *hmacKey; + TPM_KEY *idKey; /* Identity key to be activated */ + TPM_SECRET *idKeyUsageAuth; + TPM_BOOL idPCRStatus; + TPM_DIGEST h1Digest; /* digest of public key in idKey */ + unsigned char *b1Blob = NULL; /* decrypted blob */ + uint32_t b1BlobLength = 0; /* actual valid data */ + TPM_STRUCTURE_TAG hTag; /* b1 tag in host byte order */ + int vers = 0; /* version of blob */ + unsigned char *stream; + uint32_t stream_size; + TPM_EK_BLOB b1EkBlob; + TPM_ASYM_CA_CONTENTS b1AsymCaContents; + TPM_SYMMETRIC_KEY *k1 = NULL; + TPM_EK_BLOB_ACTIVATE a1; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SYMMETRIC_KEY symmetricKey; /* The decrypted symmetric key. */ + + printf("TPM_Process_ActivateIdentity: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&blob); /* freed @1 */ + TPM_SymmetricKey_Init(&symmetricKey); /* freed @2 */ + TPM_AsymCaContents_Init(&b1AsymCaContents); /* freed @4 */ + TPM_EKBlob_Init(&b1EkBlob); /* freed @5 */ + TPM_EKBlobActivate_Init(&a1); /* freed @6 */ + /* + get inputs + */ + /* get idKey parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&idKeyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get blob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&blob, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag21(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&idKeyAuthHandle, + &idKeyAuthHandleValid, + idKeynonceOdd, + &continueIdKeySession, + idKeyAuth, + &command, ¶mSize); + printf("TPM_Process_ActivateIdentity: idKeyAuthHandle %08x\n", idKeyAuthHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ActivateIdentity: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ActivateIdentity: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + idKeyAuthHandleValid = FALSE; + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Using the authHandle field, validate the owner's authorization to execute the command and + all of the incoming parameters. */ + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + /* Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Using the idKeyAuthHandle, validate the authorization to execute command and all of the + incoming parameters */ + /* get the idKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&idKey, &idPCRStatus, tpm_state, idKeyHandle, + FALSE, /* not r/o, using to authenticate */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get keyHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&idKeyUsageAuth, idKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&id_key_auth_session_data, + &idKeyHmacKey, + tpm_state, + idKeyAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + idKey, + idKeyUsageAuth, /* OIAP */ + idKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* Validate the authorization to use the key pointed to by keyHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Auth2data_Check(tpm_state, + *idKeyHmacKey, /* HMAC key */ + inParamDigest, + id_key_auth_session_data, /* authorization session */ + idKeynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueIdKeySession, + idKeyAuth); /* Authorization digest for input */ + } + /* if there is no idKey authorization, check that the idKey -> authDataUsage is TPM_AUTH_NEVER + */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (idKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_ActivateIdentity: Error, ID key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 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 (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ActivateIdentity: Checking for identity key\n"); + if (idKey->keyUsage != TPM_KEY_IDENTITY) { + printf("TPM_Process_ActivateIdentity: Error, keyUsage %04hx must be TPM_KEY_IDENTITY\n", + idKey->keyUsage); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 4. Create H1 the digest of a TPM_PUBKEY derived from idKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GeneratePubkeyDigest(h1Digest, idKey); + } + /* 5. Decrypt blob creating B1 using PRIVEK as the decryption key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ActivateIdentity: Decrypting blob with EK\n"); + returnCode = TPM_RSAPrivateDecryptMalloc(&b1Blob, /* decrypted data */ + &b1BlobLength, /* actual size of b1 data */ + blob.buffer, + blob.size, + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* 6. Determine the type and version of B1 */ + if (returnCode == TPM_SUCCESS) { + stream = b1Blob; /* b1 must be preserved for the free */ + stream_size = b1BlobLength; + /* convert possible tag to uint16_t */ + hTag = ntohs(*(TPM_STRUCTURE_TAG *)b1Blob); + /* a. If B1 -> tag is TPM_TAG_EK_BLOB then */ + if (hTag == TPM_TAG_EK_BLOB) { + /* i. B1 is a TPM_EK_BLOB */ + printf("TPM_Process_ActivateIdentity: b1 is TPM_EK_BLOB\n"); + vers = 2; + returnCode = TPM_EKBlob_Load(&b1EkBlob, &stream, &stream_size); + } + /* b. Else */ + 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 */ + printf("TPM_Process_ActivateIdentity: b1 is TPM_ASYM_CA_CONTENTS\n"); + vers = 1; + returnCode = TPM_AsymCaContents_Load(&b1AsymCaContents, &stream, &stream_size); + } + } + /* 7. If B1 is a version 1.1 TPM_ASYM_CA_CONTENTS then */ + if ((returnCode == TPM_SUCCESS) && (vers == 1)) { + /* a. Compare H1 to B1 -> idDigest on mismatch return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(h1Digest, b1AsymCaContents.idDigest); + if (returnCode != 0) { + printf("TPM_Process_ActivateIdentity: Error " + "comparing TPM_ASYM_CA_CONTENTS idDigest\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. Set K1 to B1 -> sessionKey */ + if (returnCode == TPM_SUCCESS) { + k1 = &(b1AsymCaContents.sessionKey); + } + } + /* 8. If B1 is a TPM_EK_BLOB then */ + if ((returnCode == TPM_SUCCESS) && (vers == 2)) { + /* a. Validate that B1 -> ekType is TPM_EK_TYPE_ACTIVATE, return TPM_BAD_TYPE if not. */ + if (returnCode == TPM_SUCCESS) { + if (b1EkBlob.ekType != TPM_EK_TYPE_ACTIVATE) { + printf("TPM_Process_ActivateIdentity: Error, " + "TPM_EK_BLOB not ekType TPM_EK_TYPE_ACTIVATE\n"); + returnCode = TPM_BAD_TYPE; + } + } + /* b. Assign A1 as a TPM_EK_BLOB_ACTIVATE structure from B1 -> blob */ + if (returnCode == TPM_SUCCESS) { + stream = b1EkBlob.blob.buffer; + stream_size = b1EkBlob.blob.size; + returnCode = TPM_EKBlobActivate_Load(&a1, &stream, &stream_size); + } + /* c. Compare H1 to A1 -> idDigest on mismatch return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(h1Digest, a1.idDigest); + if (returnCode != 0) { + printf("TPM_Process_ActivateIdentity: Error " + "comparing TPM_EK_TYPE_ACTIVATE idDigest\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* d. If A1 -> pcrSelection is not NULL */ + /* i. Compute a composite hash C1 using the PCR selection A1 -> pcrSelection */ + /* ii. Compare C1 to A1 -> pcrInfo -> digestAtRelease and return TPM_WRONGPCRVAL on a + mismatch */ + /* e. If A1 -> pcrInfo specifies a locality ensure that the appropriate locality has been + asserted, return TPM_BAD_LOCALITY on error */ + if (returnCode == TPM_SUCCESS) { + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_PCRInfoShort_CheckDigest(&(a1.pcrInfo), + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* f. Set K1 to A1 -> symmetricKey */ + if (returnCode == TPM_SUCCESS) { + k1 = &(a1.sessionKey); + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ActivateIdentity: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 9. Return K1 */ + returnCode = TPM_SymmetricKey_Store(response, k1); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *idKeyHmacKey, /* owner HMAC key */ + id_key_auth_session_data, + outParamDigest, + idKeynonceOdd, + continueIdKeySession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueIdKeySession) && + idKeyAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, idKeyAuthHandle); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + + + /* + cleanup + */ + TPM_SizedBuffer_Delete(&blob); /* @1 */ + TPM_SymmetricKey_Delete(&symmetricKey); /* @2 */ + free(b1Blob); /* @3 */ + TPM_AsymCaContents_Delete(&b1AsymCaContents); /* @4 */ + TPM_EKBlob_Delete(&b1EkBlob); /* @5 */ + TPM_EKBlobActivate_Delete(&a1); /* @6 */ + return rcf; +} diff --git a/src/tpm_identity.h b/src/tpm_identity.h new file mode 100644 index 00000000..629f5106 --- /dev/null +++ b/src/tpm_identity.h @@ -0,0 +1,129 @@ +/********************************************************************************/ +/* */ +/* TPM Identity Handling */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_identity.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_IDENTITY_H +#define TPM_IDENTITY_H + +#include "tpm_global.h" + +/* + TPM_EK_BLOB +*/ + +void TPM_EKBlob_Init(TPM_EK_BLOB *tpm_ek_blob); +TPM_RESULT TPM_EKBlob_Load(TPM_EK_BLOB *tpm_ek_blob, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_EKBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB *tpm_ek_blob); +void TPM_EKBlob_Delete(TPM_EK_BLOB *tpm_ek_blob); + +/* + TPM_EK_BLOB_ACTIVATE +*/ + +void TPM_EKBlobActivate_Init(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate); +TPM_RESULT TPM_EKBlobActivate_Load(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_EKBlobActivate_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate); +void TPM_EKBlobActivate_Delete(TPM_EK_BLOB_ACTIVATE *tpm_ek_blob_activate); + +/* + TPM_EK_BLOB_AUTH +*/ + +void TPM_EKBlobAuth_Init(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth); +TPM_RESULT TPM_EKBlobAuth_Load(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_EKBlobAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_EK_BLOB_AUTH *tpm_ek_blob_auth); +void TPM_EKBlobAuth_Delete(TPM_EK_BLOB_AUTH *tpm_ek_blob_auth); + + + +/* + TPM_IDENTITY_CONTENTS +*/ + +void TPM_IdentityContents_Init(TPM_IDENTITY_CONTENTS *tpm_identity_contents); +TPM_RESULT TPM_IdentityContents_Load(TPM_IDENTITY_CONTENTS *tpm_identity_contents, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_IdentityContents_Store(TPM_STORE_BUFFER *sbuffer, + TPM_IDENTITY_CONTENTS *tpm_identity_contents); +void TPM_IdentityContents_Delete(TPM_IDENTITY_CONTENTS *tpm_identity_contents); + +/* + TPM_ASYM_CA_CONTENTS +*/ + +void TPM_AsymCaContents_Init(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents); +TPM_RESULT TPM_AsymCaContents_Load(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_AsymCaContents_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents); +void TPM_AsymCaContents_Delete(TPM_ASYM_CA_CONTENTS *tpm_asym_ca_contents); + + +/* + Processing Functions +*/ + + +TPM_RESULT TPM_Process_MakeIdentity(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ActivateIdentity(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + +#endif diff --git a/src/tpm_init.c b/src/tpm_init.c new file mode 100644 index 00000000..d94ad4e3 --- /dev/null +++ b/src/tpm_init.c @@ -0,0 +1,1134 @@ +/********************************************************************************/ +/* */ +/* TPM Initialization */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_init.c 4623 2011-09-28 15:15:09Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_admin.h" +#include "tpm_cryptoh.h" +#include "tpm_crypto.h" +#include "tpm_daa.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_nvfile.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_permanent.h" +#include "tpm_platform.h" +#include "tpm_session.h" +#include "tpm_startup.h" +#include "tpm_structures.h" +#include "tpm_ticks.h" +#include "tpm_transport.h" + + +#include "tpm_init.h" + +/* local prototypes */ + +static TPM_RESULT TPM_CheckTypes(void); + + +/* TPM_Init transitions the TPM from a power-off state to one where the TPM begins an initialization + process. TPM_Init could be the result of power being applied to the platform or a hard reset. + TPM_Init sets an internal flag to indicate that the TPM is undergoing initialization. The TPM + must complete initialization before it is operational. The completion of initialization requires + the receipt of the TPM_Startup command. + + This is different from the debug function TPM_Process_Init(), which initializes a TPM. + + The call tree for initialization is as follows: + + main() + TPM_MainInit() + TPM_IO_Init() - initializes the TPM I/O interface + TPM_Crypto_Init() - initializes cryptographic libraries + TPM_NVRAM_Init() - get NVRAM path once + TPM_LimitedSelfTest() - as per the specification + TPM_Global_Init() - initializes the TPM state + + Returns: 0 on success + + non-zero on a fatal error where the TPM should not continue. These are fatal errors + where the TPM just exits. It can't even enter shutdown. + + A self test error may cause one or all TPM's to enter shutdown, but is not fatal. +*/ + +TPM_RESULT TPM_MainInit(void) +{ + TPM_RESULT rc = 0; /* results for common code, fatal errors */ + uint32_t i; + TPM_RESULT testRc = 0; /* temporary place to hold common self tests failure before the tpm + state is created */ + tpm_state_t *tpm_state; /* TPM instance state */ + + tpm_state = NULL; /* freed @1 */ + /* preliminary check that platform specific sizes are correct */ + if (rc == 0) { + rc = TPM_CheckTypes(); + } + /* initialize the TPM to host interface */ + if (rc == 0) { + printf("TPM_MainInit: Initialize the TPM to host interface\n"); + rc = TPM_IO_Init(); + } + /* initialize cryptographic functions */ + if (rc == 0) { + printf("TPM_MainInit: Initialize the TPM crypto support\n"); + rc = TPM_Crypto_Init(); + } + /* initialize NVRAM static variables. This must be called before the global TPM state is + loaded */ + if (rc == 0) { + printf("TPM_MainInit: Initialize the TPM NVRAM\n"); + rc = TPM_NVRAM_Init(); + } + /* run the initial subset of self tests once */ + if (rc == 0) { + printf("TPM_MainInit: Run common limited self tests\n"); + /* an error is a fatal error, causes a shutdown of the TPM */ + testRc = TPM_LimitedSelfTestCommon(); + } + /* initialize the global structure for the TPM */ + for (i = 0 ; (rc == 0) && (i < TPMS_MAX) ; i++) { + printf("TPM_MainInit: Initializing global TPM %lu\n", (unsigned long)i); + /* Need to malloc and init a TPM state if this is the first time through or if the + state was saved in the array. Otherwise, the malloc'ed structure from the previous + time through the loop can be reused. */ + if ((rc == 0) && (tpm_state == NULL)) { + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&tpm_state, sizeof(tpm_state_t)); + } + /* initialize the global instance state */ + if (rc == 0) { + rc = TPM_Global_Init(tpm_state); /* freed @2 */ + } + } + if (rc == 0) { + /* record the TPM number in the state */ + tpm_state->tpm_number = i; + /* If the instance exists in NVRAM, it it initialized and saved in the tpm_instances[] + array. Restores TPM_PERMANENT_FLAGS and TPM_PERMANENT_DATA to in-memory + structures. */ + /* Returns TPM_RETRY on non-existent file */ + rc = TPM_PermanentAll_NVLoad(tpm_state); + } + /* If there was no state for TPM 0 (instance 0 does not exist), initialize state for the + first time using TPM_Global_Init() above. It is created and set to default values. */ + if ((rc == TPM_RETRY) && (i == 0)) { + /* save the state for TPM 0 (first time through) */ + rc = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } +#ifdef TPM_VOLATILE_LOAD + /* if volatile state exists at startup, load it. This is used for fail-over restart. */ + if (rc == 0) { + rc = TPM_VolatileAll_NVLoad(tpm_state); + } +#endif /* TPM_VOLATILE_LOAD */ + /* if permanent state was loaded successfully (or stored successfully for TPM 0 the first + time) */ + if (rc == 0) { + printf("TPM_MainInit: Creating global TPM instance %lu\n", (unsigned long)i); + /* set the testState for the TPM based on the common selftest result */ + if (testRc != 0) { + /* a. When the TPM detects a failure during any self-test, it SHOULD delete values + preserved by TPM_SaveState. */ + TPM_SaveState_NVDelete(tpm_state, + FALSE); /* ignore error if the state does not exist */ + printf(" TPM_MainInit: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + /* save state in array */ + tpm_instances[i] = tpm_state; + tpm_state = NULL; /* flag that the malloc'ed structure was used. It should not be + freed, and a new instance is needed the next time through the + loop */ + } + /* If there was the non-fatal error TPM_RETRY, the instance does not exist. If instance > 0 + does not exist, the array entry is set to NULL. Continue */ + else if (rc == TPM_RETRY) { + printf("TPM_MainInit: Not Creating global TPM %lu\n", (unsigned long)i); + tpm_instances[i] = NULL; /* flag that the instance does not exist */ + rc = 0; /* Instance does not exist, not fatal error */ + } + } + /* run individual self test on a TPM */ + for (i = 0 ; + (rc == 0) && (i < TPMS_MAX) && (tpm_instances[i] != NULL) && + (tpm_instances[i]->testState != TPM_TEST_STATE_FAILURE) ; /* don't continue if already + error */ + i++) { + printf("TPM_MainInit: Run limited self tests on TPM %lu\n", (unsigned long)i); + testRc = TPM_LimitedSelfTestTPM(tpm_instances[i]); + if (testRc != 0) { + /* a. When the TPM detects a failure during any self-test, it SHOULD delete values + preserved by TPM_SaveState. */ + TPM_SaveState_NVDelete(tpm_state, + FALSE); /* ignore error if the state does not exist */ + } + } + /* the _Delete(), free() clean up if the last created instance was not required */ + TPM_Global_Delete(tpm_state); /* @2 */ + free(tpm_state); /* @1 */ + return rc; +} + +/* TPM_CheckTypes() checks that the assumed TPM types are correct for the platform + */ + +static TPM_RESULT TPM_CheckTypes(void) +{ + TPM_RESULT rc = 0; /* fatal errors */ + + /* These should be removed at compile time */ + if (rc == 0) { + if (sizeof(uint16_t) != 2) { + printf("TPM_CheckTypes: Error (fatal), uint16_t size %lu not supported\n", + (unsigned long)sizeof(uint16_t)); + rc = TPM_FAIL; + } + } + if (rc == 0) { + if (sizeof(uint32_t) != 4) { + printf("TPM_CheckTypes: Error (fatal), uint32_t size %lu not supported\n", + (unsigned long)sizeof(uint32_t)); + rc = TPM_FAIL; + } + } + if (rc == 0) { + if ((sizeof(time_t) != 4) && /* for 32-bit machines */ + (sizeof(time_t) != 8)) { /* for 64-bit machines */ + printf("TPM_CheckTypes: Error (fatal), time_t size %lu not supported\n", + (unsigned long)sizeof(time_t)); + rc = TPM_FAIL; + } + } + return rc; +} + +/* + TPM_STANY_FLAGS +*/ + +/* TPM_StanyFlags_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StanyFlags_Init(TPM_STANY_FLAGS *tpm_stany_flags) +{ + printf(" TPM_StanyFlags_Init:\n"); + tpm_stany_flags->postInitialise = TRUE; + tpm_stany_flags->localityModifier = 0; + tpm_stany_flags->transportExclusive = 0; + tpm_stany_flags->TOSPresent = FALSE; + /* NOTE added */ + tpm_stany_flags->stateSaved = FALSE; + return; +} + +/* TPM_StanyFlags_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StanyFlags_Init() +*/ + +TPM_RESULT TPM_StanyFlags_Load(TPM_STANY_FLAGS *tpm_stany_flags, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StanyFlags_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_STANY_FLAGS, stream, stream_size); + } + /* load postInitialise*/ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stany_flags->postInitialise), stream, stream_size); + } + /* load localityModifier */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stany_flags->localityModifier), stream, stream_size); + } + /* load transportExclusive */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stany_flags->transportExclusive), stream, stream_size); + } + /* load TOSPresent */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stany_flags->TOSPresent), stream, stream_size); + } + /* load stateSaved */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stany_flags->stateSaved), stream, stream_size); + } + return rc; +} + +/* TPM_StanyFlags_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StanyFlags_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STANY_FLAGS *tpm_stany_flags) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StanyFlags_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STANY_FLAGS); + } + /* store postInitialise*/ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stany_flags->postInitialise), sizeof(TPM_BOOL)); + } + /* store localityModifier */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stany_flags->localityModifier); + } + /* store transportExclusive */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stany_flags->transportExclusive); + } + /* store TOSPresent */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stany_flags->TOSPresent), sizeof(TPM_BOOL)); + } + /* store stateSaved */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stany_flags->stateSaved), sizeof(TPM_BOOL)); + } + return rc; +} + +/* + TPM_STCLEAR_FLAGS +*/ + +/* TPM_StclearFlags_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StclearFlags_Init(TPM_STCLEAR_FLAGS *tpm_stclear_flags) +{ + printf(" TPM_StclearFlags_Init:\n"); + /* tpm_stclear_flags->deactivated; no default state */ + tpm_stclear_flags->disableForceClear = FALSE; + tpm_stclear_flags->physicalPresence = FALSE; + tpm_stclear_flags->physicalPresenceLock = FALSE; + tpm_stclear_flags->bGlobalLock = FALSE; + return; +} + +/* TPM_StclearFlags_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StclearFlags_Init() +*/ + +TPM_RESULT TPM_StclearFlags_Load(TPM_STCLEAR_FLAGS *tpm_stclear_flags, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StclearFlags_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_STCLEAR_FLAGS, stream, stream_size); + } + /* load deactivated */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_flags->deactivated), stream, stream_size); + } + /* load disableForceClear */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_flags->disableForceClear), stream, stream_size); + } + /* load physicalPresence */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_flags->physicalPresence), stream, stream_size); + } + /* load physicalPresenceLock */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_flags->physicalPresenceLock), stream, stream_size); + } + /* load bGlobalLock */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_flags->bGlobalLock), stream, stream_size); + } + return rc; +} + +/* TPM_StclearFlags_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StclearFlags_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STCLEAR_FLAGS *tpm_stclear_flags) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StclearFlags_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STCLEAR_FLAGS); + } + /* store deactivated */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_flags->deactivated), + sizeof(TPM_BOOL)); + } + /* store disableForceClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_flags->disableForceClear), + sizeof(TPM_BOOL)); + } + /* store physicalPresence */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_flags->physicalPresence), + sizeof(TPM_BOOL)); + } + /* store physicalPresenceLock */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_flags->physicalPresenceLock), + sizeof(TPM_BOOL)); + } + /* store bGlobalLock */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_flags->bGlobalLock), + sizeof(TPM_BOOL)); + } + return rc; +} + +/* TPM_StclearFlags_StoreBitmap() serializes TPM_STCLEAR_FLAGS structure into a bit map + + */ + +TPM_RESULT TPM_StclearFlags_StoreBitmap(uint32_t *tpm_bitmap, + const TPM_STCLEAR_FLAGS *tpm_stclear_flags) +{ + TPM_RESULT rc = 0; + uint32_t pos = 0; /* position in bitmap */ + + printf(" TPM_StclearFlags_StoreBitmap:\n"); + *tpm_bitmap = 0; + /* store deactivated */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_stclear_flags->deactivated, &pos); + } + /* store disableForceClear */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_stclear_flags->disableForceClear, &pos); + } + /* store physicalPresence */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_stclear_flags->physicalPresence, &pos); + } + /* store physicalPresenceLock */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_stclear_flags->physicalPresenceLock, &pos); + } + /* store bGlobalLock */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_stclear_flags->bGlobalLock, &pos); + } + return rc; +} + +/* + TPM_STANY_DATA +*/ + +/* TPM_StanyData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 +*/ + +TPM_RESULT TPM_StanyData_Init(TPM_STANY_DATA *tpm_stany_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StanyData_Init:\n"); + if (rc == 0) { + /* The tpm_stany_data->currentTicks holds the time of day at initialization. Both nonce + generation and current time of day can return an error */ + TPM_CurrentTicks_Init(&(tpm_stany_data->currentTicks)); + rc = TPM_CurrentTicks_Start(&(tpm_stany_data->currentTicks)); + } + return rc; +} + +/* TPM_StanyData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StanyData_Init() + After use, call TPM_StanyData_Delete() to free memory +*/ + +TPM_RESULT TPM_StanyData_Load(TPM_STANY_DATA *tpm_stany_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StanyData_Load:\n"); + tpm_stany_data = tpm_stany_data; + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_STANY_DATA, stream, stream_size); + } + /* load currentTicks */ + if (rc == 0) { + rc = TPM_CurrentTicks_LoadAll(&(tpm_stany_data->currentTicks), stream, stream_size); + } + return rc; +} + +/* TPM_StanyData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StanyData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STANY_DATA *tpm_stany_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StanyData_Store:\n"); + tpm_stany_data = tpm_stany_data; + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STANY_DATA); + } + /* store currentTicks*/ + if (rc == 0) { + rc = TPM_CurrentTicks_StoreAll(sbuffer, &(tpm_stany_data->currentTicks)); + } + return rc; +} + +/* TPM_StanyData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + set members back to default values + The object itself is not freed +*/ + +void TPM_StanyData_Delete(TPM_STANY_DATA *tpm_stany_data) +{ + printf(" TPM_StanyData_Delete:\n"); + /* nothing to free */ + tpm_stany_data = tpm_stany_data; + return; +} + +/* + TPM_STCLEAR_DATA +*/ + +/* TPM_StclearData_Init() + + If pcrInit is TRUE, resets the PCR's + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StclearData_Init(TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib, + TPM_BOOL pcrInit) +{ + printf(" TPM_StclearData_Init:\n"); + TPM_Nonce_Init(tpm_stclear_data->contextNonceKey); + tpm_stclear_data->countID = TPM_COUNT_ID_NULL; /* NULL value - unselected counter */ + tpm_stclear_data->ownerReference = TPM_KH_OWNER; + tpm_stclear_data->disableResetLock = FALSE; + /* initialize PCR's */ + if (pcrInit) { + printf("TPM_StclearData_Init: Initializing PCR's\n"); + TPM_PCRs_Init(tpm_stclear_data->PCRS, pcrAttrib); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + tpm_stclear_data->deferredPhysicalPresence = 0; +#endif + tpm_stclear_data->authFailCount = 0; + tpm_stclear_data->authFailTime = 0; + /* initialize authorization, transport, DAA sessions, and saved sessions */ + TPM_StclearData_SessionInit(tpm_stclear_data); + TPM_Digest_Init(tpm_stclear_data->auditDigest); + TPM_Sbuffer_Init(&(tpm_stclear_data->ordinalResponse)); + return; +} + +/* TPM_StclearData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StclearData_Init() + After use, call TPM_StclearData_Delete() to free memory +*/ + +TPM_RESULT TPM_StclearData_Load(TPM_STCLEAR_DATA *tpm_stclear_data, + unsigned char **stream, + uint32_t *stream_size, + TPM_PCR_ATTRIBUTES *pcrAttrib) +{ + TPM_RESULT rc = 0; + TPM_STRUCTURE_TAG tag; + + printf(" TPM_StclearData_Load:\n"); + /* get tag */ + if (rc == 0) { + rc = TPM_Load16(&tag, stream, stream_size); + } + /* check tag */ + if (rc == 0) { + printf(" TPM_StclearData_Load: stream version %04hx\n", tag); + switch (tag) { + case TPM_TAG_STCLEAR_DATA: + case TPM_TAG_STCLEAR_DATA_V2: + break; + default: + printf("TPM_StclearData_Load: Error (fatal), version %04x unsupported\n", tag); + rc = TPM_FAIL; + break; + } + } + /* load contextNonceKey */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_stclear_data->contextNonceKey, stream, stream_size); + } + /* load countID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->countID), stream, stream_size); + } + /* load ownerReference */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->ownerReference), stream, stream_size); + } + /* load disableResetLock */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_stclear_data->disableResetLock), stream, stream_size); + } + /* load PCR's */ + if (rc == 0) { + rc = TPM_PCRs_Load(tpm_stclear_data->PCRS, pcrAttrib, stream, stream_size); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + /* load deferredPhysicalPresence */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->deferredPhysicalPresence), stream, stream_size); + } +#endif + /* load authFailCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->authFailCount), stream, stream_size); + } + /* load authFailTime */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->authFailTime), stream, stream_size); + } + /* load authorization sessions */ + if (rc == 0) { + rc = TPM_AuthSessions_Load(tpm_stclear_data->authSessions, stream, stream_size); + } + /* load transport sessions */ + if (rc == 0) { + rc = TPM_TransportSessions_Load(tpm_stclear_data->transSessions, stream, stream_size); + } + /* load DAA sessions */ + if (rc == 0) { + rc = TPM_DaaSessions_Load(tpm_stclear_data->daaSessions, stream, stream_size); + } + /* load contextNonceSession */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_stclear_data->contextNonceSession, stream, stream_size); + } + /* load contextCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_stclear_data->contextCount), stream, stream_size); + } + /* load contextList */ + if (rc == 0) { + rc = TPM_ContextList_Load(tpm_stclear_data->contextList, stream, stream_size); + } + /* load auditDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_stclear_data->auditDigest, stream, stream_size); + TPM_PrintFour(" TPM_StclearData_Load: auditDigest", tpm_stclear_data->auditDigest); + } + /* no need to store and load ordinalResponse */ + if (tag == TPM_TAG_STCLEAR_DATA) { + /* but it's there for some versions */ + if (rc == 0) { + TPM_STORE_BUFFER ordinalResponse; + TPM_Sbuffer_Init(&ordinalResponse); + rc = TPM_Sbuffer_Load(&ordinalResponse, stream, stream_size); + TPM_Sbuffer_Delete(&ordinalResponse); + } + if (rc == 0) { + uint32_t responseCount; + rc = TPM_Load32(&responseCount, stream, stream_size); + } + } + return rc; +} + +/* TPM_StclearData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StclearData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StclearData_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STCLEAR_DATA_V2); + } + /* store contextNonceKey */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_stclear_data->contextNonceKey); + } + /* store countID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->countID); + } + /* store ownerReference */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->ownerReference); + } + /* store disableResetLock */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_stclear_data->disableResetLock), + sizeof(TPM_BOOL)); + } + /* store PCR's */ + if (rc == 0) { + rc = TPM_PCRs_Store(sbuffer, tpm_stclear_data->PCRS, pcrAttrib); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + /* store deferredPhysicalPresence */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->deferredPhysicalPresence); + } +#endif + /* store authFailCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->authFailCount); + } + /* store authFailTime */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->authFailTime); + } + /* store authorization sessions */ + if (rc == 0) { + rc = TPM_AuthSessions_Store(sbuffer, tpm_stclear_data->authSessions); + } + /* store transport sessions */ + if (rc == 0) { + rc = TPM_TransportSessions_Store(sbuffer, tpm_stclear_data->transSessions); + } + /* store DAA sessions */ + if (rc == 0) { + rc = TPM_DaaSessions_Store(sbuffer, tpm_stclear_data->daaSessions); + } + /* store contextNonceSession */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_stclear_data->contextNonceSession); + } + /* store contextCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_stclear_data->contextCount); + } + /* store contextList */ + if (rc == 0) { + rc = TPM_ContextList_Store(sbuffer, tpm_stclear_data->contextList); + } + /* store auditDigest */ + if (rc == 0) { + TPM_PrintFour(" TPM_StclearData_Store: auditDigest", tpm_stclear_data->auditDigest); + rc = TPM_Digest_Store(sbuffer, tpm_stclear_data->auditDigest); + } + /* no need to store and load ordinalResponse */ + return rc; +} + +/* TPM_StclearData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_StclearData_Init to set members back to default values + The object itself is not freed +*/ + +/* TPM_StclearData_Delete() frees any memory associated with TPM_STCLEAR_DATA, and then + reinitializes the structure. + + If pcrInit is TRUE, the PCR's are initialized. +*/ + +void TPM_StclearData_Delete(TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib, + TPM_BOOL pcrInit) +{ + printf(" TPM_StclearData_Delete:\n"); + if (tpm_stclear_data != NULL) { + TPM_StclearData_SessionDelete(tpm_stclear_data);/* authorization, transport, and DAA + sessions */ + TPM_Sbuffer_Delete(&(tpm_stclear_data->ordinalResponse)); + TPM_StclearData_Init(tpm_stclear_data, pcrAttrib, pcrInit); + } + return; +} + +/* TPM_StclearData_SessionInit() initializes the structure members associated with authorization, + transport, and DAA sessions. + + It must be called whenever the sessions are invalidated. +*/ + +void TPM_StclearData_SessionInit(TPM_STCLEAR_DATA *tpm_stclear_data) +{ + printf(" TPM_StclearData_SessionInit:\n"); + /* active sessions */ + TPM_AuthSessions_Init(tpm_stclear_data->authSessions); + TPM_TransportSessions_Init(tpm_stclear_data->transSessions); + TPM_DaaSessions_Init(tpm_stclear_data->daaSessions); + /* saved sessions */ + TPM_Nonce_Init(tpm_stclear_data->contextNonceSession); + tpm_stclear_data->contextCount = 0; + TPM_ContextList_Init(tpm_stclear_data->contextList); + return; +} + +/* TPM_StclearData_SessionDelete() deletes the structure members associated with authorization, + transport, and DAA sessions. + + It must be called whenever the sessions are invalidated. +*/ + +void TPM_StclearData_SessionDelete(TPM_STCLEAR_DATA *tpm_stclear_data) +{ + printf(" TPM_StclearData_SessionDelete:\n"); + /* active and saved authorization sessions, the authSessions table and the 3 contextList + entries */ + TPM_StclearData_AuthSessionDelete(tpm_stclear_data); + /* loaded transport sessions */ + TPM_TransportSessions_Delete(tpm_stclear_data->transSessions); + /* loaded DAA sessions */ + TPM_DaaSessions_Delete(tpm_stclear_data->daaSessions); + return; +} + +/* TPM_StclearData_AuthSessionDelete() deletes the structure members associated with authorization + sessions. It clears the authSessions table and the 3 contextList members. + + It must be called whenever the sessions are invalidated. +*/ + +void TPM_StclearData_AuthSessionDelete(TPM_STCLEAR_DATA *tpm_stclear_data) +{ + printf(" TPM_StclearData_AuthSessionDelete:\n"); + /* active sessions */ + TPM_AuthSessions_Delete(tpm_stclear_data->authSessions); + /* saved sessions */ + TPM_Nonce_Init(tpm_stclear_data->contextNonceSession); + tpm_stclear_data->contextCount = 0; + TPM_ContextList_Init(tpm_stclear_data->contextList); + return; +} + +/* + TPM_InitCmd() executes the actions of the TPM_Init 'ordinal' +*/ + +TPM_RESULT TPM_InitCmd(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + uint32_t tpm_number; + + printf(" TPM_Init:\n"); + /* Release all resources for the TPM and reinitialize */ + if (rc == TPM_SUCCESS) { + tpm_number = tpm_state->tpm_number; /* save the TPM value */ + TPM_Global_Delete(tpm_state); /* delete all the state */ + rc = TPM_Global_Init(tpm_state); /* re-allocate the state */ + } + /* Reload non-volatile memory */ + if (rc == TPM_SUCCESS) { + tpm_state->tpm_number = tpm_number; /* restore the TPM number */ + /* Returns TPM_RETRY on non-existent file */ + rc = TPM_PermanentAll_NVLoad(tpm_state); /* reload the state */ + if (rc == TPM_RETRY) { + printf("TPM_Init: Error (fatal), non-existent instance\n"); + rc = TPM_FAIL; + } + } + return rc; +} + +/* + TPM_Handle_GenerateHandle() is a utility function that returns an unused handle. + + It's really not an initialization function, but as the handle arrays are typically in + TPM_STCLEAR_DATA, it's a reasonable home. + + If 'tpm_handle' is non-zero, it is the first value tried. If 'keepHandle' is TRUE, it is the only + value tried. + + If 'tpm_handle' is zero, a random value is assigned. If 'keepHandle' is TRUE, an error returned, + as zero is an illegal handle value. + + If 'isKeyHandle' is TRUE, special checking is performed to avoid reserved values. + + 'getEntryFunction' is a function callback to check whether the handle has already been assigned to + an entry in the appropriate handle list. +*/ + +TPM_RESULT TPM_Handle_GenerateHandle(TPM_HANDLE *tpm_handle, + void *tpm_handle_entries, + TPM_BOOL keepHandle, + TPM_BOOL isKeyHandle, + TPM_GETENTRY_FUNCTION_T getEntryFunction) +{ + TPM_RESULT rc = 0; + TPM_RESULT getRc = 0; + unsigned int timeout; /* collision timeout */ + void *used_handle_entry; /* place holder for discarded entry */ + TPM_BOOL done; + + printf(" TPM_Handle_GenerateHandle: handle %08x, keepHandle %u\n", + *tpm_handle, keepHandle); + /* if the input value must be used */ + if (keepHandle) { + /* 0 is illegal and cannot be kept */ + if (rc == 0) { + if (*tpm_handle == 0) { + printf("TPM_Handle_GenerateHandle: Error, cannot keep handle 0\n"); + rc = TPM_BAD_HANDLE; + } + } + /* key handles beginning with 0x40 are reserved special values */ + if (rc == 0) { + if (isKeyHandle) { + if ((*tpm_handle & 0xff000000) == 0x40000000) { + printf("TPM_Handle_GenerateHandle: Error, cannot keep reserved key handle\n"); + rc = TPM_BAD_HANDLE; + } + } + } + /* check if the handle is already used */ + if (rc == 0) { + getRc = getEntryFunction(&used_handle_entry, /* discarded entry */ + tpm_handle_entries, /* handle array */ + *tpm_handle); /* search for handle */ + /* success mean the handle has already been assigned */ + if (getRc == 0) { + printf("TPM_Handle_GenerateHandle: Error handle already in use\n"); + rc = TPM_BAD_HANDLE; + } + } + } + /* input value is recommended but not required */ + else { + /* implement a crude timeout in case the random number generator fails and there are too + many collisions */ + for (done = FALSE, timeout = 0 ; (rc == 0) && !done && (timeout < 1000) ; timeout++) { + /* If no handle has been assigned, try a random value. If a handle has been assigned, + try it first */ + if (rc == 0) { + if (*tpm_handle == 0) { + rc = TPM_Random((BYTE *)tpm_handle, sizeof(uint32_t)); + } + } + /* if the random value is 0, reject it immediately */ + if (rc == 0) { + if (*tpm_handle == 0) { + printf(" TPM_Handle_GenerateHandle: Random value 0 rejected\n"); + continue; + } + } + /* if the value is a reserved key handle, reject it immediately */ + if (rc == 0) { + if (isKeyHandle) { + if ((*tpm_handle & 0xff000000) == 0x40000000) { + printf(" TPM_Handle_GenerateHandle: Random value %08x rejected\n", + *tpm_handle); + *tpm_handle = 0; /* ignore the assigned value */ + continue; + } + } + } + /* test if the handle has already been used */ + if (rc == 0) { + getRc = getEntryFunction(&used_handle_entry, /* discarded entry */ + tpm_handle_entries, /* handle array */ + *tpm_handle); /* search for handle */ + if (getRc != 0) { /* not found, done */ + printf(" TPM_Handle_GenerateHandle: Assigned Handle %08x\n", + *tpm_handle); + done = TRUE; + } + else { /* found, try again */ + *tpm_handle = 0; /* ignore the assigned value */ + printf(" TPM_Handle_GenerateHandle: Handle %08x already used\n", + *tpm_handle); + } + } + } + if (!done) { + printf("TPM_Handle_GenerateHandle: Error (fatal), random number generator failed\n"); + rc = TPM_FAIL; + } + } + return rc; +} + +/* + Processing Functions +*/ + +/* TPM_Init + + This ordinal should not be implemented, since it allows software to imitate a reboot. That would + be a major security hole, since the PCR's are reset. + + It is only here for regression tests. +*/ + +TPM_RESULT TPM_Process_Init(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + printf("TPM_Process_Init: Ordinal Entry\n"); + ordinal = ordinal; /* not used */ + command = command; /* not used */ + transportInternal = transportInternal; /* not used */ + /* check state */ + /* NOTE: Allow at any time. */ + /* + get inputs + */ + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Init: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { +#ifdef TPM_TEST + returnCode = TPM_InitCmd(tpm_state); +#else + tpm_state = tpm_state; /* to quiet the compiler */ + printf("TPM_Process_Init: Error, bad ordinal\n"); + returnCode = TPM_BAD_ORDINAL; +#endif + } + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_Init: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + return rcf; +} + diff --git a/src/tpm_init.h b/src/tpm_init.h new file mode 100644 index 00000000..276e5379 --- /dev/null +++ b/src/tpm_init.h @@ -0,0 +1,136 @@ +/********************************************************************************/ +/* */ +/* TPM Initialization */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_init.h 4403 2011-02-08 18:28:22Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_INIT_H +#define TPM_INIT_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_structures.h" + +/* Power up initialization */ +TPM_RESULT TPM_MainInit(void); + +/* + TPM_STANY_FLAGS +*/ + +void TPM_StanyFlags_Init(TPM_STANY_FLAGS *tpm_stany_flags); + +TPM_RESULT TPM_StanyFlags_Load(TPM_STANY_FLAGS *tpm_stany_flags, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_StanyFlags_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STANY_FLAGS *tpm_stany_flags); + +/* + TPM_STCLEAR_FLAGS +*/ + +void TPM_StclearFlags_Init(TPM_STCLEAR_FLAGS *tpm_stclear_flags); +TPM_RESULT TPM_StclearFlags_Load(TPM_STCLEAR_FLAGS *tpm_stclear_flags, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_StclearFlags_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STCLEAR_FLAGS *tpm_stclear_flags); +TPM_RESULT TPM_StclearFlags_StoreBitmap(uint32_t *tpm_bitmap, + const TPM_STCLEAR_FLAGS *tpm_stclear_flags); +/* + TPM_STANY_DATA +*/ + +TPM_RESULT TPM_StanyData_Init(TPM_STANY_DATA *tpm_stany_data); +TPM_RESULT TPM_StanyData_Load(TPM_STANY_DATA *tpm_stany_data, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_StanyData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STANY_DATA *tpm_stany_data); +void TPM_StanyData_Delete(TPM_STANY_DATA *tpm_stany_data); + +/* + TPM_STCLEAR_DATA +*/ + +void TPM_StclearData_Init(TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib, + TPM_BOOL pcrInit); +TPM_RESULT TPM_StclearData_Load(TPM_STCLEAR_DATA *tpm_stclear_data, + unsigned char **stream, + uint32_t *stream_size, + TPM_PCR_ATTRIBUTES *pcrAttrib); +TPM_RESULT TPM_StclearData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib); +void TPM_StclearData_Delete(TPM_STCLEAR_DATA *tpm_stclear_data, + TPM_PCR_ATTRIBUTES *pcrAttrib, + TPM_BOOL pcrInit); + +void TPM_StclearData_SessionInit(TPM_STCLEAR_DATA *tpm_stclear_data); +void TPM_StclearData_SessionDelete(TPM_STCLEAR_DATA *tpm_stclear_data); +void TPM_StclearData_AuthSessionDelete(TPM_STCLEAR_DATA *tpm_stclear_data); + +/* Actions */ + +TPM_RESULT TPM_InitCmd(tpm_state_t *tpm_state); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_Init(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +/* generic function prototype for a handle array getEntry callback function */ + +typedef TPM_RESULT (*TPM_GETENTRY_FUNCTION_T )(void **entry, + void *entries, + TPM_HANDLE handle); + +TPM_RESULT TPM_Handle_GenerateHandle(TPM_HANDLE *tpm_handle, + void *tpm_handle_entries, + TPM_BOOL keepHandle, + TPM_BOOL isKeyHandle, + TPM_GETENTRY_FUNCTION_T getEntryFunction); + +#endif diff --git a/src/tpm_io.h b/src/tpm_io.h new file mode 100644 index 00000000..055b0baa --- /dev/null +++ b/src/tpm_io.h @@ -0,0 +1,71 @@ +/********************************************************************************/ +/* */ +/* TPM Host IO */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_io.h 4211 2010-11-22 21:07:24Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_IO_H +#define TPM_IO_H + +#include "tpm_types.h" + +/* non-portable structure to pass around IO file descriptor */ + +typedef struct TPM_CONNECTION_FD { +#ifdef TPM_POSIX + int fd; /* for socket, just an int */ +#endif +} TPM_CONNECTION_FD; + + +TPM_RESULT TPM_IO_IsNotifyAvailable(TPM_BOOL *isAvailable); +TPM_RESULT TPM_IO_Connect(TPM_CONNECTION_FD *connection_fd, + void *mainLoopArgs); +TPM_RESULT TPM_IO_Read(TPM_CONNECTION_FD *connection_fd, + unsigned char *buffer, + uint32_t *paramSize, + size_t buffer_size, + void *mainLoopArgs); +TPM_RESULT TPM_IO_Write(TPM_CONNECTION_FD *connection_fd, + const unsigned char *buffer, + size_t buffer_length); +TPM_RESULT TPM_IO_Disconnect(TPM_CONNECTION_FD *connection_fd); + +/* function for notifying listener(s) about PCRExtend events */ +TPM_RESULT TPM_IO_ClientSendNotification(const void *buf, size_t count); + + +#endif diff --git a/src/tpm_key.c b/src/tpm_key.c new file mode 100644 index 00000000..d0fa359d --- /dev/null +++ b/src/tpm_key.c @@ -0,0 +1,5526 @@ +/********************************************************************************/ +/* */ +/* Key Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_key.c 4655 2011-12-21 21:03:15Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_commands.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_io.h" +#include "tpm_load.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_nvfile.h" +#include "tpm_nvram.h" +#include "tpm_owner.h" +#include "tpm_pcr.h" +#include "tpm_sizedbuffer.h" +#include "tpm_store.h" +#include "tpm_structures.h" +#include "tpm_startup.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_ver.h" + +#include "tpm_key.h" + +/* The default RSA exponent */ +unsigned char tpm_default_rsa_exponent[] = {0x01, 0x00, 0x01}; + +/* local prototypes */ + +static TPM_RESULT TPM_Key_CheckTag(TPM_KEY12 *tpm_key12); + +/* + TPM_KEY, TPM_KEY12 + + These functions generally handle either a TPM_KEY or TPM_KEY12. Where structure members differ, + the function checks the version or tag and adapts the processing to the structure type. This + handling is opaque to the caller. +*/ + + +/* TPM_Key_Init initializes a key structure. The default is TPM_KEY. Typically, a TPM_Key_Set() or + TPM_Key_Load() will adjust to TPM_KEY or TPM_KEY12 */ + +void TPM_Key_Init(TPM_KEY *tpm_key) +{ + printf(" TPM_Key_Init:\n"); + TPM_StructVer_Init(&(tpm_key->ver)); + tpm_key->keyUsage = TPM_KEY_UNINITIALIZED; + tpm_key->keyFlags = 0; + tpm_key->authDataUsage = 0; + TPM_KeyParms_Init(&(tpm_key->algorithmParms)); + TPM_SizedBuffer_Init(&(tpm_key->pcrInfo)); + TPM_SizedBuffer_Init(&(tpm_key->pubKey)); + TPM_SizedBuffer_Init(&(tpm_key->encData)); + tpm_key->tpm_pcr_info = NULL; + tpm_key->tpm_pcr_info_long = NULL; + tpm_key->tpm_store_asymkey = NULL; + tpm_key->tpm_migrate_asymkey = NULL; + return; +} + +/* TPM_Key_InitTag12() alters the tag and fill from TPM_KEY to TPM_KEY12 */ + +void TPM_Key_InitTag12(TPM_KEY *tpm_key) +{ + printf(" TPM_Key_InitTag12:\n"); + ((TPM_KEY12 *)tpm_key)->tag = TPM_TAG_KEY12; + ((TPM_KEY12 *)tpm_key)->fill = 0x0000; + return; +} + +/* TPM_Key_Set() sets a TPM_KEY structure to the specified values. + + The tpm_pcr_info digestAtCreation is calculated. + + It serializes the tpm_pcr_info or tpm_pcr_info_long cache to pcrInfo. One or the other may be + specified, but not both. The tag/version is set correctly. + + If the parent_key is NULL, encData is set to the clear text serialization of the + tpm_store_asymkey member. + + If parent_key is not NULL, encData is not set yet, since further processing may be done before + encryption. + + Must call TPM_Key_Delete() to free + */ + +TPM_RESULT TPM_Key_Set(TPM_KEY *tpm_key, /* output created key */ + tpm_state_t *tpm_state, + TPM_KEY *parent_key, /* NULL for root keys */ + TPM_DIGEST *tpm_pcrs, /* points to the TPM PCR array */ + int ver, /* TPM_KEY or TPM_KEY12 */ + TPM_KEY_USAGE keyUsage, /* input */ + TPM_KEY_FLAGS keyFlags, /* input */ + TPM_AUTH_DATA_USAGE authDataUsage, /* input */ + TPM_KEY_PARMS *tpm_key_parms, /* input */ + TPM_PCR_INFO *tpm_pcr_info, /* must copy */ + TPM_PCR_INFO_LONG *tpm_pcr_info_long, /* must copy */ + uint32_t keyLength, /* public key length in bytes */ + BYTE* publicKey, /* public key byte array */ + TPM_STORE_ASYMKEY *tpm_store_asymkey, /* cache TPM_STORE_ASYMKEY */ + TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) /* cache TPM_MIGRATE_ASYMKEY */ +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + + printf(" TPM_Key_Set:\n"); + TPM_Sbuffer_Init(&sbuffer); + /* version must be TPM_KEY or TPM_KEY12 */ + if (rc == 0) { + if ((ver != 1) && (ver != 2)) { + printf("TPM_Key_Set: Error (fatal), " + "TPM_KEY version %d is not 1 or 2\n", ver); + rc = TPM_FAIL; /* should never occur */ + } + } + /* either tpm_pcr_info != NULL for TPM_KEY or tpm_pcr_info_long != NULL for TPM_KEY12, but not + both */ + if (rc == 0) { + if ((ver == 1) && (tpm_pcr_info_long != NULL)) { + printf("TPM_Key_Set: Error (fatal), " + "TPM_KEY and TPM_PCR_INFO_LONG both specified\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + if ((ver == 2) && (tpm_pcr_info != NULL)) { + printf("TPM_Key_Set: Error (fatal), " + "TPM_KEY12 and TPM_PCR_INFO both specified\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + TPM_Key_Init(tpm_key); + if (ver == 2) { + TPM_Key_InitTag12(tpm_key); /* change tag to TPM_KEY12 */ + } + tpm_key->keyUsage = keyUsage; + tpm_key->keyFlags = keyFlags; + tpm_key->authDataUsage = authDataUsage; + rc = TPM_KeyParms_Copy(&(tpm_key->algorithmParms), /* freed by caller */ + tpm_key_parms); + } + /* The pcrInfo serialization is deferred, since PCR data is be altered after the initial + 'set'. */ + if (rc == 0) { + /* generate the TPM_PCR_INFO member cache, directly copying from the tpm_pcr_info */ + if (tpm_pcr_info != NULL) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromInfo(&(tpm_key->tpm_pcr_info), tpm_pcr_info); + } + /* generate the TPM_PCR_INFO_LONG member cache, directly copying from the + tpm_pcr_info_long */ + else if (tpm_pcr_info_long != NULL) { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_CreateFromInfoLong(&(tpm_key->tpm_pcr_info_long), + tpm_pcr_info_long); + } + } + if (rc == 0) { + /* if there are PCR's specified, set the digestAtCreation */ + if (tpm_pcr_info != NULL) { + rc = TPM_PCRInfo_SetDigestAtCreation(tpm_key->tpm_pcr_info, tpm_pcrs); + } + /* if there are PCR's specified, set the localityAtCreation, digestAtCreation */ + else if (tpm_pcr_info_long != NULL) { /* TPM_KEY12 */ + if (rc == 0) { + rc = TPM_Locality_Set(&(tpm_key->tpm_pcr_info_long->localityAtCreation), + tpm_state->tpm_stany_flags.localityModifier); + } + if (rc == 0) { + rc = TPM_PCRInfoLong_SetDigestAtCreation(tpm_key->tpm_pcr_info_long, tpm_pcrs); + } + } + } + /* set TPM_SIZED_BUFFER pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Set(&(tpm_key->pubKey), + keyLength, /* in bytes */ + publicKey); + } + if (rc == 0) { + if (tpm_store_asymkey == NULL) { + printf("TPM_Key_Set: Error (fatal), No TPM_STORE_ASYMKEY supplied\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* sanity check, currently no need to set TPM_MIGRATE_ASYMKEY */ + if (rc == 0) { + if (tpm_migrate_asymkey != NULL) { + printf("TPM_Key_Set: Error (fatal), TPM_MIGRATE_ASYMKEY supplied\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + /* root key, no parent, just serialize the TPM_STORE_ASYMKEY structure */ + if (parent_key == NULL) { + if (rc == 0) { + rc = TPM_StoreAsymkey_Store(&sbuffer, FALSE, tpm_store_asymkey); /* freed @1 */ + } + if (rc == 0) { + rc = TPM_SizedBuffer_SetFromStore(&(tpm_key->encData), &sbuffer); + } + } + } + if (rc == 0) { + tpm_key->tpm_store_asymkey = tpm_store_asymkey; /* cache TPM_STORE_ASYMKEY */ + tpm_key->tpm_migrate_asymkey = tpm_migrate_asymkey; /* cache TPM_MIGRATE_ASYMKEY */ + } + /* Generate the TPM_STORE_ASYMKEY -> pubDataDigest. Serializes pcrInfo as a side effect. */ + if (rc == 0) { + rc = TPM_Key_GeneratePubDataDigest(tpm_key); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_Key_Copy() copies the source TPM_KEY to the destination. + + The destination should be initialized before the call. +*/ + +TPM_RESULT TPM_Key_Copy(TPM_KEY *tpm_key_dest, + TPM_KEY *tpm_key_src, + TPM_BOOL copyEncData) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + TPM_StructVer_Copy(&(tpm_key_dest->ver), &(tpm_key_src->ver)); /* works for TPM_KEY12 + also */ + tpm_key_dest->keyUsage = tpm_key_src->keyUsage; + tpm_key_dest->keyFlags = tpm_key_src->keyFlags; + tpm_key_dest->authDataUsage = tpm_key_src->authDataUsage; + rc = TPM_KeyParms_Copy(&(tpm_key_dest->algorithmParms), &(tpm_key_src->algorithmParms)); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Copy(&(tpm_key_dest->pcrInfo), &(tpm_key_src->pcrInfo)); + } + /* copy TPM_PCR_INFO cache */ + if (rc == 0) { + if (tpm_key_src->tpm_pcr_info != NULL) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromInfo(&(tpm_key_dest->tpm_pcr_info), + tpm_key_src->tpm_pcr_info); + } + else if (tpm_key_src->tpm_pcr_info_long != NULL) { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_CreateFromInfoLong(&(tpm_key_dest->tpm_pcr_info_long), + tpm_key_src->tpm_pcr_info_long); + } + } + /* copy pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Copy(&(tpm_key_dest->pubKey), &(tpm_key_src->pubKey)); + } + /* copy encData */ + if (rc == 0) { + if (copyEncData) { + rc = TPM_SizedBuffer_Copy(&(tpm_key_dest->encData), &(tpm_key_src->encData)); + } + } + return rc; +} + +/* TPM_Key_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + The TPM_PCR_INFO or TPM_PCR_INFO_LONG cache is set from the deserialized pcrInfo stream. + + After use, call TPM_Key_Delete() to free memory +*/ + + +TPM_RESULT TPM_Key_Load(TPM_KEY *tpm_key, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_Load:\n"); + /* load public data, and create PCR cache */ + if (rc == 0) { + rc = TPM_Key_LoadPubData(tpm_key, FALSE, stream, stream_size); + } + /* load encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_key->encData), stream, stream_size); + } + return rc; +} + +/* TPM_Key_LoadClear() load a serialized key where the TPM_STORE_ASYMKEY structure is serialized in + clear text. + + The TPM_PCR_INFO or TPM_PCR_INFO_LONG cache is set from the deserialized pcrInfo stream. + + This function is used to load internal keys (e.g. EK, SRK, owner evict keys) or keys saved as + part of a save state. +*/ + +TPM_RESULT TPM_Key_LoadClear(TPM_KEY *tpm_key, /* result */ + TPM_BOOL isEK, /* key being loaded is EK */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + uint32_t storeAsymkeySize; + + printf(" TPM_Key_LoadClear:\n"); + /* load public data */ + if (rc == 0) { + rc = TPM_Key_LoadPubData(tpm_key, isEK, stream, stream_size); + } + /* load TPM_STORE_ASYMKEY size */ + if (rc == 0) { + rc = TPM_Load32(&storeAsymkeySize, stream, stream_size); + } + /* The size might be 0 for an uninitialized internal key. That case is not an error. */ + if ((rc == 0) && (storeAsymkeySize > 0)) { + rc = TPM_Key_LoadStoreAsymKey(tpm_key, isEK, stream, stream_size); + } + return rc; +} + +/* TPM_Key_LoadPubData() deserializes a TPM_KEY or TPM_KEY12 structure, excluding encData, to + 'tpm_key'. + + The TPM_PCR_INFO or TPM_PCR_INFO_LONG cache is set from the deserialized pcrInfo stream. + If the pcrInfo stream is empty, the caches remain NULL. + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_Key_Delete() to free memory +*/ + +TPM_RESULT TPM_Key_LoadPubData(TPM_KEY *tpm_key, /* result */ + TPM_BOOL isEK, /* key being loaded is EK */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_LoadPubData:\n"); + /* peek at the first byte */ + if (rc == 0) { + /* TPM_KEY[0] is major (non zero) */ + if ((*stream)[0] != 0) { + /* load ver */ + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_key->ver), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_key->ver)); + } + } + else { + /* TPM_KEY12 is tag (zero) */ + /* load tag */ + if (rc == 0) { + rc = TPM_Load16(&(((TPM_KEY12 *)tpm_key)->tag), stream, stream_size); + } + /* load fill */ + if (rc == 0) { + rc = TPM_Load16(&(((TPM_KEY12 *)tpm_key)->fill), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Key_CheckTag((TPM_KEY12 *)tpm_key); + } + } + } + /* load keyUsage */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_key->keyUsage), stream, stream_size); + } + /* load keyFlags */ + if (rc == 0) { + rc = TPM_KeyFlags_Load(&(tpm_key->keyFlags), stream, stream_size); + } + /* load authDataUsage */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_key->authDataUsage), stream, stream_size); + } + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_key->algorithmParms), stream, stream_size); + } + /* load PCRInfo */ + if ((rc == 0) && !isEK) { + rc = TPM_SizedBuffer_Load(&(tpm_key->pcrInfo), stream, stream_size); + } + /* set TPM_PCR_INFO tpm_pcr_info cache from PCRInfo stream. If the stream is empty, a NULL is + returned. + */ + if ((rc == 0) && !isEK) { + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromBuffer(&(tpm_key->tpm_pcr_info), + &(tpm_key->pcrInfo)); + } + else { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_CreateFromBuffer(&(tpm_key->tpm_pcr_info_long), + &(tpm_key->pcrInfo)); + } + } + /* load pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_key->pubKey), stream, stream_size); + } + return rc; +} + +/* TPM_Key_StorePubData() serializes a TPM_KEY or TPM_KEY12 structure, excluding encData, appending + results to 'sbuffer'. + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_StorePubData(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_StorePubData:\n"); + + if (rc == 0) { + /* store ver */ + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_StructVer_Store(sbuffer, &(tpm_key->ver)); + } + else { /* TPM_KEY12 */ + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_KEY12); + } + /* store fill */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, 0x0000); + } + } + } + /* store keyUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_key->keyUsage); + } + /* store keyFlags */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key->keyFlags); + } + /* store authDataUsage */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_key->authDataUsage), sizeof(TPM_AUTH_DATA_USAGE)); + } + /* store algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_key->algorithmParms)); + } + /* store pcrInfo */ + if ((rc == 0) && !isEK) { + /* copy cache to pcrInfo */ + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_SizedBuffer_SetStructure(&(tpm_key->pcrInfo), + tpm_key->tpm_pcr_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfo_Store); + } + else { /* TPM_KEY12 */ + rc = TPM_SizedBuffer_SetStructure(&(tpm_key->pcrInfo), + tpm_key->tpm_pcr_info_long, + (TPM_STORE_FUNCTION_T)TPM_PCRInfoLong_Store); + } + } + /* copy pcrInfo to sbuffer */ + if ((rc == 0) && !isEK) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key->pcrInfo)); + } + /* store pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key->pubKey)); + } + return rc; +} + +/* TPM_Key_Store() serializes a TPM_KEY structure, appending results to 'sbuffer' + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_Store(TPM_STORE_BUFFER *sbuffer, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_Store:\n"); + /* store the pubData */ + if (rc == 0) { + rc = TPM_Key_StorePubData(sbuffer, FALSE, tpm_key); + } + /* store encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key->encData)); + } + return rc; +} + +/* TPM_Key_StoreClear() serializes a TPM_KEY structure, appending results to 'sbuffer' + + TPM_Key_StoreClear() serializes the tpm_store_asymkey member as cleartext. It is used for keys + such as the SRK, which never leave the TPM. It is also used for saving state, where the entire + blob is encrypted. + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_StoreClear(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, /* key being stored is EK */ + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER asymSbuffer; + const unsigned char *asymBuffer; + uint32_t asymLength; + + printf(" TPM_Key_StoreClear:\n"); + TPM_Sbuffer_Init(&asymSbuffer); /* freed @1 */ + /* store the pubData */ + if (rc == 0) { + rc = TPM_Key_StorePubData(sbuffer, isEK, tpm_key); + } + /* store TPM_STORE_ASYMKEY cache as cleartext */ + if (rc == 0) { + /* if the TPM_STORE_ASYMKEY cache exists */ + if (tpm_key->tpm_store_asymkey != NULL) { + /* , serialize it */ + if (rc == 0) { + rc = TPM_StoreAsymkey_Store(&asymSbuffer, isEK, tpm_key->tpm_store_asymkey); + } + /* get the result */ + TPM_Sbuffer_Get(&asymSbuffer, &asymBuffer, &asymLength); + /* store the result as a sized buffer */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, asymLength); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, asymBuffer, asymLength); + } + } + /* If there is no TPM_STORE_ASYMKEY cache, mark it empty. This can occur for an internal + key that has not been created yet. */ + else { + rc = TPM_Sbuffer_Append32(sbuffer, 0); + } + } + TPM_Sbuffer_Delete(&asymSbuffer); /* @1 */ + return rc; +} + +/* TPM_KEY_StorePubkey() gets (as a stream) the TPM_PUBKEY derived from a TPM_KEY + + There is no need to actually assemble the structure, since only the serialization of its two + members are needed. + + The stream is returned as a TPM_STORE_BUFFER (that must be initialized and deleted by the + caller), and it's components (buffer and size). +*/ + +TPM_RESULT TPM_Key_StorePubkey(TPM_STORE_BUFFER *pubkeyStream, /* output */ + const unsigned char **pubkeyStreamBuffer, /* output */ + uint32_t *pubkeyStreamLength, /* output */ + TPM_KEY *tpm_key) /* input */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_StorePubkey:\n"); + /* the first part is a TPM_KEY_PARMS */ + if (rc == 0) { + rc = TPM_KeyParms_Store(pubkeyStream, &(tpm_key->algorithmParms)); + } + /* the second part is the TPM_SIZED_BUFFER pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(pubkeyStream, &(tpm_key->pubKey)); + } + /* retrieve the resulting pubkey stream */ + if (rc == 0) { + TPM_Sbuffer_Get(pubkeyStream, + pubkeyStreamBuffer, + pubkeyStreamLength); + } + return rc; +} + +/* TPM_Key_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_Key_Init to set members back to default values + The TPM_KEY itself is not freed + + The key is not freed because it might be a local variable rather than a malloc'ed pointer. +*/ + +void TPM_Key_Delete(TPM_KEY *tpm_key) +{ + if (tpm_key != NULL) { + printf(" TPM_Key_Delete:\n"); + TPM_KeyParms_Delete(&(tpm_key->algorithmParms)); + /* pcrInfo */ + TPM_SizedBuffer_Delete(&(tpm_key->pcrInfo)); + /* pcr caches */ + TPM_PCRInfo_Delete(tpm_key->tpm_pcr_info); + free(tpm_key->tpm_pcr_info); + TPM_PCRInfoLong_Delete(tpm_key->tpm_pcr_info_long); + free(tpm_key->tpm_pcr_info_long); + + TPM_SizedBuffer_Delete(&(tpm_key->pubKey)); + TPM_SizedBuffer_Delete(&(tpm_key->encData)); + TPM_StoreAsymkey_Delete(tpm_key->tpm_store_asymkey); + free(tpm_key->tpm_store_asymkey); + TPM_MigrateAsymkey_Delete(tpm_key->tpm_migrate_asymkey); + free(tpm_key->tpm_migrate_asymkey); + TPM_Key_Init(tpm_key); + } + return; +} + +/* TPM_Key_CheckStruct() verifies that the 'tpm_key' has either a TPM_KEY -> ver of a TPM_KEY12 tag + and fill +*/ + +TPM_RESULT TPM_Key_CheckStruct(int *ver, TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + /* The key can be either a TPM_KEY or TPM_KEY12 */ + if (*(unsigned char *)tpm_key == 0x01) { + *ver = 1; + rc = TPM_StructVer_CheckVer(&(tpm_key->ver)); /* check for TPM_KEY */ + if (rc == 0) { /* if found TPM_KEY */ + printf(" TPM_Key_CheckStruct: TPM_KEY version %u.%u\n", + tpm_key->ver.major, tpm_key->ver.minor); + } + } + else { /* else check for TPM_KEY12 */ + *ver = 2; + rc = TPM_Key_CheckTag((TPM_KEY12 *)tpm_key); + if (rc == 0) { + printf(" TPM_Key_CheckStruct: TPM_KEY12\n"); + } + else { /* not TPM_KEY or TPM_KEY12 */ + printf("TPM_Key_CheckStruct: Error checking structure, bytes 0:3 %02x %02x %02x %02x\n", + tpm_key->ver.major, tpm_key->ver.minor, + tpm_key->ver.revMajor, tpm_key->ver.revMinor); + rc = TPM_BAD_KEY_PROPERTY; + } + } + return rc; +} + +/* TPM_Key_CheckTag() checks that the TPM_KEY12 tag is correct + */ + +static TPM_RESULT TPM_Key_CheckTag(TPM_KEY12 *tpm_key12) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if (tpm_key12->tag != TPM_TAG_KEY12) { + printf("TPM_Key_CheckTag: Error, TPM_KEY12 tag %04x should be TPM_TAG_KEY12\n", + tpm_key12->tag); + rc = TPM_BAD_KEY_PROPERTY; + } + } + if (rc == 0) { + if (tpm_key12->fill != 0x0000) { + printf("TPM_Key_CheckTag: Error, TPM_KEY12 fill %04x should be 0x0000\n", + tpm_key12->fill); + rc = TPM_BAD_KEY_PROPERTY; + } + } + return rc; +} + +/* TPM_Key_CheckProperties() checks that the TPM can generate a key of the type requested in + 'tpm_key'. + + if keyLength is non-zero, checks that the tpm_key specifies the correct key length. If keyLength + is 0, any tpm_key key length is accepted. + + Returns TPM_BAD_KEY_PROPERTY on error. + */ + +TPM_RESULT TPM_Key_CheckProperties(int *ver, + TPM_KEY *tpm_key, + uint32_t keyLength, /* in bits */ + TPM_BOOL FIPS) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_CheckProperties:\n"); + /* check the version */ + if (rc == 0) { + rc = TPM_Key_CheckStruct(ver, tpm_key); + } + /* if FIPS */ + if ((rc == 0) && FIPS) { + /* b. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS */ + if (tpm_key->authDataUsage == TPM_AUTH_NEVER) { + printf("TPM_Key_CheckProperties: Error, FIPS authDataUsage TPM_AUTH_NEVER\n"); + rc = TPM_NOTFIPS; + } + } + /* most of the work is done by TPM_KeyParms_CheckProperties() */ + if (rc == 0) { + printf(" TPM_Key_CheckProperties: authDataUsage %02x\n", tpm_key->authDataUsage); + rc = TPM_KeyParms_CheckProperties(&(tpm_key->algorithmParms), + tpm_key->keyUsage, + keyLength, /* in bits */ + FIPS); + } + return rc; +} + +/* TPM_Key_LoadStoreAsymKey() deserializes a stream to a TPM_STORE_ASYMKEY structure and stores it + in the TPM_KEY cache. + + Call this function when a key is loaded, either from the host (stream is decrypted encData) or + from permanent data or saved state (stream was clear text). +*/ + +TPM_RESULT TPM_Key_LoadStoreAsymKey(TPM_KEY *tpm_key, + TPM_BOOL isEK, + unsigned char **stream, /* decrypted encData (clear text) */ + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + /* This function should never be called when the TPM_STORE_ASYMKEY structure has already been + loaded. This indicates an internal error. */ + printf(" TPM_Key_LoadStoreAsymKey:\n"); + if (rc == 0) { + if (tpm_key->tpm_store_asymkey != NULL) { + printf("TPM_Key_LoadStoreAsymKey: Error (fatal), TPM_STORE_ASYMKEY already loaded\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* If the stream size is 0, there is an internal error. */ + if (rc == 0) { + if (*stream_size == 0) { + printf("TPM_Key_LoadStoreAsymKey: Error (fatal), stream size is 0\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + /* allocate memory for the structure */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_key->tpm_store_asymkey), + sizeof(TPM_STORE_ASYMKEY)); + } + if (rc == 0) { + TPM_StoreAsymkey_Init(tpm_key->tpm_store_asymkey); + rc = TPM_StoreAsymkey_Load(tpm_key->tpm_store_asymkey, isEK, + stream, stream_size, + &(tpm_key->algorithmParms), &(tpm_key->pubKey)); + TPM_PrintFour(" TPM_Key_LoadStoreAsymKey: usageAuth", + tpm_key->tpm_store_asymkey->usageAuth); + } + return rc; +} + +/* TPM_Key_GetStoreAsymkey() gets the TPM_STORE_ASYMKEY from a TPM_KEY cache. + */ + +TPM_RESULT TPM_Key_GetStoreAsymkey(TPM_STORE_ASYMKEY **tpm_store_asymkey, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetStoreAsymkey:\n"); + if (rc == 0) { + /* return the cached structure */ + *tpm_store_asymkey = tpm_key->tpm_store_asymkey; + if (tpm_key->tpm_store_asymkey == NULL) { + printf("TPM_Key_GetStoreAsymkey: Error (fatal), no cache\n"); + rc = TPM_FAIL; /* indicate no cache */ + } + } + return rc; +} + +/* TPM_Key_GetMigrateAsymkey() gets the TPM_MIGRATE_ASYMKEY from a TPM_KEY cache. + */ + +TPM_RESULT TPM_Key_GetMigrateAsymkey(TPM_MIGRATE_ASYMKEY **tpm_migrate_asymkey, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetMigrateAsymkey:\n"); + if (rc == 0) { + /* return the cached structure */ + *tpm_migrate_asymkey = tpm_key->tpm_migrate_asymkey; + if (tpm_key->tpm_migrate_asymkey == NULL) { + printf("TPM_Key_GetMigrateAsymkey: Error (fatal), no cache\n"); + rc = TPM_FAIL; /* indicate no cache */ + } + } + return rc; +} + +/* TPM_Key_GetUsageAuth() gets the usageAuth from the TPM_STORE_ASYMKEY or TPM_MIGRATE_ASYMKEY + contained in a TPM_KEY +*/ + +TPM_RESULT TPM_Key_GetUsageAuth(TPM_SECRET **usageAuth, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey; + + printf(" TPM_Key_GetUsageAuth:\n"); + /* check that the TPM_KEY_USAGE indicates a valid key */ + if (rc == 0) { + if ((tpm_key == NULL) || + (tpm_key->keyUsage == TPM_KEY_UNINITIALIZED)) { + printf("TPM_Key_GetUsageAuth: Error, key not initialized\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* get the TPM_STORE_ASYMKEY object */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + + /* found a TPM_STORE_ASYMKEY */ + if (rc == 0) { + *usageAuth = &(tpm_store_asymkey->usageAuth); + } + /* get the TPM_MIGRATE_ASYMKEY object */ + else { + rc = TPM_Key_GetMigrateAsymkey(&tpm_migrate_asymkey, tpm_key); + /* found a TPM_MIGRATE_ASYMKEY */ + if (rc == 0) { + *usageAuth = &(tpm_migrate_asymkey->usageAuth); + } + } + } + if (rc != 0) { + printf("TPM_Key_GetUsageAuth: Error (fatal), " + "could not get TPM_STORE_ASYMKEY or TPM_MIGRATE_ASYMKEY\n"); + rc = TPM_FAIL; /* should never occur */ + } + /* get the usageAuth element */ + if (rc == 0) { + TPM_PrintFour(" TPM_Key_GetUsageAuth: Auth", **usageAuth); + } + return rc; +} + +/* TPM_Key_GetPublicKey() gets the public key from the TPM_STORE_PUBKEY contained in a TPM_KEY + */ + +TPM_RESULT TPM_Key_GetPublicKey(uint32_t *nbytes, + unsigned char **narr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetPublicKey:\n"); + if (rc == 0) { + *nbytes = tpm_key->pubKey.size; + *narr = tpm_key->pubKey.buffer; + } + return rc; +} + +/* TPM_Key_GetPrimeFactorP() gets the prime factor p from the TPM_STORE_ASYMKEY contained in a + TPM_KEY +*/ + +TPM_RESULT TPM_Key_GetPrimeFactorP(uint32_t *pbytes, + unsigned char **parr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GetPrimeFactorP:\n"); + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + *pbytes = tpm_store_asymkey->privKey.p_key.size; + *parr = tpm_store_asymkey->privKey.p_key.buffer; + } + return rc; +} + +/* TPM_Key_GetPrivateKey() gets the private key from the TPM_STORE_ASYMKEY contained in a TPM_KEY + */ + +TPM_RESULT TPM_Key_GetPrivateKey(uint32_t *dbytes, + unsigned char **darr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GetPrivateKey:\n"); + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + *dbytes = tpm_store_asymkey->privKey.d_key.size; + *darr = tpm_store_asymkey->privKey.d_key.buffer; + } + return rc; +} + +/* TPM_Key_GetExponent() gets the exponent key from the TPM_RSA_KEY_PARMS contained in a TPM_KEY + */ + +TPM_RESULT TPM_Key_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetExponent:\n"); + if (rc == 0) { + rc = TPM_KeyParms_GetExponent(ebytes, earr, &(tpm_key->algorithmParms)); + } + return rc; +} + +/* TPM_Key_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit mask. + + 'start_pcr' indicates the starting byte index into pcrSelect[] +*/ + +TPM_RESULT TPM_Key_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_KEY *tpm_key, + size_t start_index) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetPCRUsage: Start %lu\n", (unsigned long)start_index); + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_PCRInfo_GetPCRUsage(pcrUsage, tpm_key->tpm_pcr_info, start_index); + } + else { /* TPM_KEY12 */ + rc = TPM_PCRInfoLong_GetPCRUsage(pcrUsage, tpm_key->tpm_pcr_info_long, start_index); + } + return rc; +} + +/* TPM_Key_GetLocalityAtRelease() the localityAtRelease for a TPM_PCR_INFO_LONG. + For a TPM_PCR_INFO is returns TPM_LOC_ALL (all localities). +*/ + +TPM_RESULT TPM_Key_GetLocalityAtRelease(TPM_LOCALITY_SELECTION *localityAtRelease, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GetLocalityAtRelease:\n"); + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + /* locality not used for TPM_PCR_INFO */ + *localityAtRelease = TPM_LOC_ALL; + } + /* TPM_KEY12 */ + else if (tpm_key->tpm_pcr_info_long == NULL) { + /* locality not used if TPM_PCR_INFO_LONG was not specified */ + *localityAtRelease = TPM_LOC_ALL; + } + else { + *localityAtRelease = tpm_key->tpm_pcr_info_long->localityAtRelease; + } + return rc; +} + +/* TPM_Key_GenerateRSA() generates a TPM_KEY using TPM_KEY_PARMS. The tag/version is set correctly. + + The TPM_STORE_ASYMKEY member cache is set. pcrInfo is set as a serialized tpm_pcr_info or + tpm_pcr_info_long. + + For exported keys, encData is not set yet. It later becomes the encryption of TPM_STORE_ASYMKEY. + + For internal 'root' keys (endorsement key, srk), encData is stored as clear text. + + It returns the TPM_KEY object. + + Call tree: + local - sets tpm_store_asymkey->privkey + TPM_Key_Set - sets keyUsage, keyFlags, authDataUsage, algorithmParms + tpm_pcr_info cache, digestAtCreation, pubKey, + TPM_Key_GeneratePubDataDigest - pubDataDigest + TPM_Key_Store + TPM_Key_StorePubData - serializes tpm_pcr_info cache +*/ + +TPM_RESULT TPM_Key_GenerateRSA(TPM_KEY *tpm_key, /* output created key */ + tpm_state_t *tpm_state, + TPM_KEY *parent_key, /* NULL for root keys */ + TPM_DIGEST *tpm_pcrs, /* PCR array from state */ + int ver, /* TPM_KEY or TPM_KEY12 */ + TPM_KEY_USAGE keyUsage, /* input */ + TPM_KEY_FLAGS keyFlags, /* input */ + TPM_AUTH_DATA_USAGE authDataUsage, /* input */ + TPM_KEY_PARMS *tpm_key_parms, /* input */ + TPM_PCR_INFO *tpm_pcr_info, /* input */ + TPM_PCR_INFO_LONG *tpm_pcr_info_long) /* input */ +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; + unsigned char *earr; /* public exponent */ + uint32_t ebytes; + + /* generated RSA key */ + unsigned char *n = NULL; /* public key */ + unsigned char *p = NULL; /* prime factor */ + unsigned char *q = NULL; /* prime factor */ + unsigned char *d = NULL; /* private key */ + + printf(" TPM_Key_GenerateRSA:\n"); + /* extract the TPM_RSA_KEY_PARMS from TPM_KEY_PARMS */ + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, tpm_key_parms); + } + /* get the public exponent, with conversion */ + if (rc == 0) { + rc = TPM_RSAKeyParms_GetExponent(&ebytes, &earr, tpm_rsa_key_parms); + } + /* allocate storage for TPM_STORE_ASYMKEY. The structure is not freed. It is cached in the + TPM_KEY->TPM_STORE_ASYMKEY member and freed when they are deleted. */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_key->tpm_store_asymkey), + sizeof(TPM_STORE_ASYMKEY)); + } + if (rc == 0) { + TPM_StoreAsymkey_Init(tpm_key->tpm_store_asymkey); + } + /* generate the key pair */ + if (rc == 0) { + rc = TPM_RSAGenerateKeyPair(&n, /* public key (modulus) freed @3 */ + &p, /* private prime factor freed @4 */ + &q, /* private prime factor freed @5 */ + &d, /* private key (private exponent) freed @6 */ + tpm_rsa_key_parms->keyLength, /* key size in bits */ + earr, /* public exponent */ + ebytes); + } + /* construct the TPM_STORE_ASYMKEY member */ + if (rc == 0) { + TPM_PrintFour(" TPM_Key_GenerateRSA: Public key n", n); + TPM_PrintAll(" TPM_Key_GenerateRSA: Exponent", earr, ebytes); + TPM_PrintFour(" TPM_Key_GenerateRSA: Private prime p", p); + TPM_PrintFour(" TPM_Key_GenerateRSA: Private prime q", q); + TPM_PrintFour(" TPM_Key_GenerateRSA: Private key d", d); + /* add the private primes and key to the TPM_STORE_ASYMKEY object */ + rc = TPM_SizedBuffer_Set(&(tpm_key->tpm_store_asymkey->privKey.d_key), + tpm_rsa_key_parms->keyLength/CHAR_BIT, + d); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set(&(tpm_key->tpm_store_asymkey->privKey.p_key), + tpm_rsa_key_parms->keyLength/(CHAR_BIT * 2), + p); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set(&(tpm_key->tpm_store_asymkey->privKey.q_key), + tpm_rsa_key_parms->keyLength/(CHAR_BIT * 2), + q); + } + if (rc == 0) { + rc = TPM_Key_Set(tpm_key, + tpm_state, + parent_key, + tpm_pcrs, + ver, /* TPM_KEY or TPM_KEY12 */ + keyUsage, /* TPM_KEY_USAGE */ + keyFlags, /* TPM_KEY_FLAGS */ + authDataUsage, /* TPM_AUTH_DATA_USAGE */ + tpm_key_parms, /* TPM_KEY_PARMS */ + tpm_pcr_info, /* TPM_PCR_INFO */ + tpm_pcr_info_long, /* TPM_PCR_INFO_LONG */ + tpm_rsa_key_parms->keyLength/CHAR_BIT, /* TPM_STORE_PUBKEY.keyLength */ + n, /* TPM_STORE_PUBKEY.key (public key) */ + /* FIXME redundant */ + tpm_key->tpm_store_asymkey, /* cache the TPM_STORE_ASYMKEY structure */ + NULL); /* TPM_MIGRATE_ASYMKEY */ + } + free(n); /* @3 */ + free(p); /* @4 */ + free(q); /* @5 */ + free(d); /* @6 */ + return rc; +} + +/* TPM_Key_GeneratePubkeyDigest() serializes a TPM_PUBKEY derived from the TPM_KEY and calculates + its digest. +*/ + +TPM_RESULT TPM_Key_GeneratePubkeyDigest(TPM_DIGEST tpm_digest, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER pubkeyStream; /* from tpm_key */ + const unsigned char *pubkeyStreamBuffer; + uint32_t pubkeyStreamLength; + + printf(" TPM_Key_GeneratePubkeyDigest:\n"); + TPM_Sbuffer_Init(&pubkeyStream); /* freed @1 */ + /* serialize a TPM_PUBKEY derived from the TPM_KEY */ + if (rc == 0) { + rc = TPM_Key_StorePubkey(&pubkeyStream, /* output */ + &pubkeyStreamBuffer, /* output */ + &pubkeyStreamLength, /* output */ + tpm_key); /* input */ + } + if (rc == 0) { + rc = TPM_SHA1(tpm_digest, + pubkeyStreamLength, pubkeyStreamBuffer, + 0, NULL); + } + TPM_Sbuffer_Delete(&pubkeyStream); /* @1 */ + return rc; + +} + +/* TPM_Key_ComparePubkey() serializes and hashes the TPM_PUBKEY derived from a TPM_KEY and a + TPM_PUBKEY and compares the results +*/ + +TPM_RESULT TPM_Key_ComparePubkey(TPM_KEY *tpm_key, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + TPM_DIGEST key_digest; + TPM_DIGEST pubkey_digest; + + if (rc == 0) { + rc = TPM_Key_GeneratePubkeyDigest(key_digest, tpm_key); + } + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(pubkey_digest, tpm_pubkey, + (TPM_STORE_FUNCTION_T)TPM_Pubkey_Store); + } + if (rc == 0) { + rc = TPM_Digest_Compare(key_digest, pubkey_digest); + } + return rc; +} + +/* TPM_Key_GeneratePubDataDigest() generates and stores a TPM_STORE_ASYMKEY -> pubDataDigest + + As a side effect, it serializes the tpm_pcr_info cache to pcrInfo. +*/ + +TPM_RESULT TPM_Key_GeneratePubDataDigest(TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_KEY serialization */ + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GeneratePubDataDigest:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_KEY excluding the encData fields */ + if (rc == 0) { + rc = TPM_Key_StorePubData(&sbuffer, FALSE, tpm_key); + } + /* get the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + /* hash the serialized buffer to tpm_digest */ + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_store_asymkey->pubDataDigest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_Key_CheckPubDataDigest() generates a TPM_STORE_ASYMKEY -> pubDataDigest and compares it to + the stored value. + + Returns: Error id + */ + +TPM_RESULT TPM_Key_CheckPubDataDigest(TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_KEY serialization */ + TPM_STORE_ASYMKEY *tpm_store_asymkey; + TPM_DIGEST tpm_digest; /* calculated pubDataDigest */ + + printf(" TPM_Key_CheckPubDataDigest:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_KEY excluding the encData fields */ + if (rc == 0) { + rc = TPM_Key_StorePubData(&sbuffer, FALSE, tpm_key); + } + /* get the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + if (rc == 0) { + rc = TPM_Digest_Compare(tpm_store_asymkey->pubDataDigest, tpm_digest); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_Key_GenerateEncData() generates an TPM_KEY -> encData structure member by serializing the + cached TPM_KEY -> TPM_STORE_ASYMKEY member and encrypting the result using the parent_key public + key. +*/ + +TPM_RESULT TPM_Key_GenerateEncData(TPM_KEY *tpm_key, + TPM_KEY *parent_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_ASYMKEY *tpm_store_asymkey; + + printf(" TPM_Key_GenerateEncData;\n"); + /* get the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + rc = TPM_Key_GetStoreAsymkey(&tpm_store_asymkey, tpm_key); + } + if (rc == 0) { + rc = TPM_StoreAsymkey_GenerateEncData(&(tpm_key->encData), + tpm_store_asymkey, + parent_key); + } + return rc; +} + + +/* TPM_Key_DecryptEncData() decrypts the TPM_KEY -> encData using the parent private key. The + result is deserialized and stored in the TPM_KEY -> TPM_STORE_ASYMKEY cache. + +*/ + +TPM_RESULT TPM_Key_DecryptEncData(TPM_KEY *tpm_key, /* result */ + TPM_KEY *parent_key) /* parent for decrypting encData */ +{ + TPM_RESULT rc = 0; + unsigned char *decryptData = NULL; /* freed @1 */ + uint32_t decryptDataLength = 0; /* actual valid data */ + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_Key_DecryptEncData\n"); + /* allocate space for the decrypted data */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptMalloc(&decryptData, /* decrypted data */ + &decryptDataLength, /* actual size of decrypted + data */ + tpm_key->encData.buffer, /* encrypted data */ + tpm_key->encData.size, /* encrypted data size */ + parent_key); + } + /* load the TPM_STORE_ASYMKEY cache from the 'encData' member stream */ + if (rc == 0) { + stream = decryptData; + stream_size = decryptDataLength; + rc = TPM_Key_LoadStoreAsymKey(tpm_key, FALSE, &stream, &stream_size); + } + free(decryptData); /* @1 */ + return rc; +} + +/* TPM_Key_GeneratePCRDigest() generates a digest based on the current PCR state and the PCR's + specified with the key. + + The key can be either TPM_KEY or TPM_KEY12. + + This function assumes that TPM_Key_GetPCRUsage() has determined that PCR's are in use, so + a NULL PCR cache will return an error here. + + See Part 1 25.1 +*/ + +TPM_RESULT TPM_Key_CheckPCRDigest(TPM_KEY *tpm_key, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Key_GeneratePCRDigest:\n"); + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + /* i. Calculate H1 a TPM_COMPOSITE_HASH of the PCR selected by LK -> pcrInfo -> + releasePCRSelection */ + /* ii. Compare H1 to LK -> pcrInfo -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if (rc == 0) { + rc = TPM_PCRInfo_CheckDigest(tpm_key->tpm_pcr_info, + tpm_state->tpm_stclear_data.PCRS); /* array of PCR's */ + } + } + else { /* TPM_KEY12 */ + /* i. Calculate H1 a TPM_COMPOSITE_HASH of the PCR selected by LK -> pcrInfo -> + releasePCRSelection */ + /* ii. Compare H1 to LK -> pcrInfo -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if (rc == 0) { + rc = TPM_PCRInfoLong_CheckDigest(tpm_key->tpm_pcr_info_long, + tpm_state->tpm_stclear_data.PCRS, /* array of PCR's */ + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* 4. Allow use of the key */ + if (rc != 0) { + printf("TPM_Key_CheckPCRDigest: Error, wrong digestAtRelease value\n"); + rc = TPM_WRONGPCRVAL; + } + return rc; +} + +/* TPM_Key_CheckRestrictDelegate() checks the restrictDelegate data against the TPM_KEY properties. + It determines how the TPM responds to delegated requests to use a certified migration key. + + Called from TPM_AuthSessions_GetData() if it's a DSAP session using a key entity.. + + TPM_PERMANENT_DATA -> restrictDelegate is used as follows: + + 1. If the session type is TPM_PID_DSAP and TPM_KEY -> keyFlags -> migrateAuthority is TRUE + a. If + TPM_KEY_USAGE is TPM_KEY_SIGNING and restrictDelegate -> TPM_CMK_DELEGATE_SIGNING is TRUE, or + TPM_KEY_USAGE is TPM_KEY_STORAGE and restrictDelegate -> TPM_CMK_DELEGATE_STORAGE is TRUE, or + TPM_KEY_USAGE is TPM_KEY_BIND and restrictDelegate -> TPM_CMK_DELEGATE_BIND is TRUE, or + TPM_KEY_USAGE is TPM_KEY_LEGACY and restrictDelegate -> TPM_CMK_DELEGATE_LEGACY is TRUE, or + TPM_KEY_USAGE is TPM_KEY_MIGRATE and restrictDelegate -> TPM_CMK_DELEGATE_MIGRATE is TRUE + then the key can be used. + b. Else return TPM_INVALID_KEYUSAGE. + +*/ + +TPM_RESULT TPM_Key_CheckRestrictDelegate(TPM_KEY *tpm_key, + TPM_CMK_DELEGATE restrictDelegate) +{ + TPM_RESULT rc = 0; + + printf("TPM_Key_CheckRestrictDelegate:\n"); + if (rc == 0) { + if (tpm_key == NULL) { + printf("TPM_Key_CheckRestrictDelegate: Error (fatal), key NULL\n"); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + /* if it's a certified migration key */ + if (rc == 0) { + if (tpm_key->keyFlags & TPM_MIGRATEAUTHORITY) { + if (!( + ((restrictDelegate & TPM_CMK_DELEGATE_SIGNING) && + (tpm_key->keyUsage == TPM_KEY_SIGNING)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_STORAGE) && + (tpm_key->keyUsage == TPM_KEY_STORAGE)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_BIND) && + (tpm_key->keyUsage == TPM_KEY_BIND)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_LEGACY) && + (tpm_key->keyUsage == TPM_KEY_LEGACY)) || + + ((restrictDelegate & TPM_CMK_DELEGATE_MIGRATE) && + (tpm_key->keyUsage == TPM_KEY_MIGRATE)) + )) { + printf("TPM_Key_CheckRestrictDelegate: Error, " + "invalid keyUsage %04hx restrictDelegate %08x\n", + tpm_key->keyUsage, restrictDelegate); + rc = TPM_INVALID_KEYUSAGE; + } + } + } + return rc; +} + +/* + TPM_KEY_FLAGS +*/ + +/* TPM_KeyFlags_Load() deserializes a TPM_KEY_FLAGS value and checks for a legal value. + */ + +TPM_RESULT TPM_KeyFlags_Load(TPM_KEY_FLAGS *tpm_key_flags, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + /* load keyFlags */ + if (rc == 0) { + rc = TPM_Load32(tpm_key_flags, stream, stream_size); + } + /* check TPM_KEY_FLAGS validity, look for extra bits set */ + if (rc == 0) { + if (*tpm_key_flags & ~TPM_KEY_FLAGS_MASK) { + printf("TPM_KeyFlags_Load: Error, illegal keyFlags value %08x\n", + *tpm_key_flags); + rc = TPM_BAD_KEY_PROPERTY; + } + } + return rc; +} + +/* + TPM_KEY_PARMS +*/ + +void TPM_KeyParms_Init(TPM_KEY_PARMS *tpm_key_parms) +{ + printf(" TPM_KeyParms_Init:\n"); + tpm_key_parms->algorithmID = 0; + tpm_key_parms->encScheme = TPM_ES_NONE; + tpm_key_parms->sigScheme = TPM_SS_NONE; + TPM_SizedBuffer_Init(&(tpm_key_parms->parms)); + tpm_key_parms->tpm_rsa_key_parms = NULL; + return; +} + +/* TPM_KeyParms_SetRSA() is a 'Set' version specific to RSA keys */ + +TPM_RESULT TPM_KeyParms_SetRSA(TPM_KEY_PARMS *tpm_key_parms, + TPM_ALGORITHM_ID algorithmID, + TPM_ENC_SCHEME encScheme, + TPM_SIG_SCHEME sigScheme, + uint32_t keyLength, /* in bits */ + TPM_SIZED_BUFFER *exponent) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_SetRSA:\n"); + /* copy the TPM_KEY_PARMS members */ + if (rc == 0) { + tpm_key_parms->algorithmID = algorithmID; + tpm_key_parms->encScheme = encScheme; + tpm_key_parms->sigScheme = sigScheme; + /* construct the TPM_RSA_KEY_PARMS cache member object */ + rc = TPM_RSAKeyParms_New(&tpm_key_parms->tpm_rsa_key_parms); + } + if (rc == 0) { + /* copy the TPM_RSA_KEY_PARMS members */ + tpm_key_parms->tpm_rsa_key_parms->keyLength = keyLength; + tpm_key_parms->tpm_rsa_key_parms->numPrimes = 2; + rc = TPM_SizedBuffer_Copy(&(tpm_key_parms->tpm_rsa_key_parms->exponent), exponent); + } + /* serialize the TPM_RSA_KEY_PARMS object back to TPM_KEY_PARMS */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_key_parms->parms), + tpm_key_parms->tpm_rsa_key_parms, + (TPM_STORE_FUNCTION_T)TPM_RSAKeyParms_Store); + } + return rc; +} + + +/* TPM_KeyParms_Copy() copies the source to the destination. + + If the algorithmID is TPM_ALG_RSA, the tpm_rsa_key_parms cache is allocated and copied. + + Must be freed by TPM_KeyParms_Delete() after use +*/ + +TPM_RESULT TPM_KeyParms_Copy(TPM_KEY_PARMS *tpm_key_parms_dest, + TPM_KEY_PARMS *tpm_key_parms_src) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_Copy:\n"); + if (rc == 0) { + tpm_key_parms_dest->algorithmID = tpm_key_parms_src->algorithmID; + tpm_key_parms_dest->encScheme = tpm_key_parms_src->encScheme; + tpm_key_parms_dest->sigScheme = tpm_key_parms_src->sigScheme; + rc = TPM_SizedBuffer_Copy(&(tpm_key_parms_dest->parms), + &(tpm_key_parms_src->parms)); + } + /* if there is a destination TPM_RSA_KEY_PARMS cache */ + if ((rc == 0) && (tpm_key_parms_dest->algorithmID == TPM_ALG_RSA)) { + /* construct the TPM_RSA_KEY_PARMS cache member object */ + if (rc == 0) { + rc = TPM_RSAKeyParms_New(&(tpm_key_parms_dest->tpm_rsa_key_parms)); + } + /* copy the TPM_RSA_KEY_PARMS member */ + if (rc == 0) { + rc = TPM_RSAKeyParms_Copy(tpm_key_parms_dest->tpm_rsa_key_parms, + tpm_key_parms_src->tpm_rsa_key_parms); + } + } + return rc; +} + +/* TPM_KeyParms_Load deserializes a stream to a TPM_KEY_PARMS structure. + + Must be freed by TPM_KeyParms_Delete() after use +*/ + +TPM_RESULT TPM_KeyParms_Load(TPM_KEY_PARMS *tpm_key_parms, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + unsigned char *parms_stream; + uint32_t parms_stream_size; + + printf(" TPM_KeyParms_Load:\n"); + /* load algorithmID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_key_parms->algorithmID), stream, stream_size); + } + /* load encScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_key_parms->encScheme), stream, stream_size); + } + /* load sigScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_key_parms->sigScheme), stream, stream_size); + } + /* load parmSize and parms */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_key_parms->parms), stream, stream_size); + } + if (rc == 0) { + switch (tpm_key_parms->algorithmID) { + /* Allow load of uninitialized structures */ + case 0: + break; + + case TPM_ALG_RSA: + /* load the TPM_RSA_KEY_PARMS cache if the algorithmID indicates an RSA key */ + if (rc == 0) { + rc = TPM_RSAKeyParms_New(&(tpm_key_parms->tpm_rsa_key_parms)); + } + /* deserialize the parms stream, but don't move the pointer */ + if (rc == 0) { + parms_stream = tpm_key_parms->parms.buffer; + parms_stream_size = tpm_key_parms->parms.size; + rc = TPM_RSAKeyParms_Load(tpm_key_parms->tpm_rsa_key_parms, + &parms_stream, &parms_stream_size); + } + break; + + /* NOTE Only handles TPM_RSA_KEY_PARMS, could handle TPM_SYMMETRIC_KEY_PARMS */ + case TPM_ALG_AES128: + case TPM_ALG_AES192: + case TPM_ALG_AES256: + default: + printf("TPM_KeyParms_Load: Cannot handle algorithmID %08x\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + } + return rc; +} + +TPM_RESULT TPM_KeyParms_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_KEY_PARMS *tpm_key_parms) +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; + + printf(" TPM_KeyParms_GetExponent:\n"); + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, tpm_key_parms); + } + if (rc == 0) { + rc = TPM_RSAKeyParms_GetExponent(ebytes, earr, tpm_rsa_key_parms); + } + return rc; +} + + +/* TPM_KeyParms_Store serializes a TPM_KEY_PARMS structure, appending results to 'sbuffer' +*/ + +TPM_RESULT TPM_KeyParms_Store(TPM_STORE_BUFFER *sbuffer, + TPM_KEY_PARMS *tpm_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_Store:\n"); + /* store algorithmID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_parms->algorithmID); + } + /* store encScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_key_parms->encScheme); + } + /* store sigScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_key_parms->sigScheme); + } + /* copy cache to parms */ + if (rc == 0) { + switch (tpm_key_parms->algorithmID) { + /* Allow store of uninitialized structures */ + case 0: + break; + case TPM_ALG_RSA: + rc = TPM_SizedBuffer_SetStructure(&(tpm_key_parms->parms), + tpm_key_parms->tpm_rsa_key_parms, + (TPM_STORE_FUNCTION_T)TPM_RSAKeyParms_Store); + break; + /* NOTE Only handles TPM_RSA_KEY_PARMS, could handle TPM_SYMMETRIC_KEY_PARMS */ + case TPM_ALG_AES128: + case TPM_ALG_AES192: + case TPM_ALG_AES256: + default: + printf("TPM_KeyParms_Store: Cannot handle algorithmID %08x\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + } + /* store parms */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_key_parms->parms)); + } + return rc; +} + +/* TPM_KeyParms_Delete frees any member allocated memory */ + +void TPM_KeyParms_Delete(TPM_KEY_PARMS *tpm_key_parms) +{ + printf(" TPM_KeyParms_Delete:\n"); + if (tpm_key_parms != NULL) { + TPM_SizedBuffer_Delete(&(tpm_key_parms->parms)); + TPM_RSAKeyParms_Delete(tpm_key_parms->tpm_rsa_key_parms); + free(tpm_key_parms->tpm_rsa_key_parms); + TPM_KeyParms_Init(tpm_key_parms); + } + return; +} + +/* TPM_KeyParms_GetRSAKeyParms() gets the TPM_RSA_KEY_PARMS from a TPM_KEY_PARMS cache. + + Returns an error if the cache is NULL, since the cache should always be set when the + TPM_KEY_PARMS indicates an RSA key. +*/ + +TPM_RESULT TPM_KeyParms_GetRSAKeyParms(TPM_RSA_KEY_PARMS **tpm_rsa_key_parms, + TPM_KEY_PARMS *tpm_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyParms_GetRSAKeyParms:\n"); + /* algorithmID must be RSA */ + if (rc == 0) { + if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { + printf("TPM_KeyParms_GetRSAKeyParms: Error, incorrect algorithmID %08x\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* if the TPM_RSA_KEY_PARMS structure has not been cached, deserialize it */ + if (rc == 0) { + if (tpm_key_parms->tpm_rsa_key_parms == NULL) { + printf("TPM_KeyParms_GetRSAKeyParms: Error (fatal), cache is NULL\n"); + /* This should never occur. The cache is loaded when the TPM_KEY_PARMS is loaded. */ + rc = TPM_FAIL; + } + } + /* return the cached structure */ + if (rc == 0) { + *tpm_rsa_key_parms = tpm_key_parms->tpm_rsa_key_parms; + } + return rc; +} + +/* TPM_KeyParms_CheckProperties() checks that the TPM can generate a key of the type requested in + 'tpm_key_parms' + + if' keyLength' is non-zero, checks that the tpm_key specifies the correct key length. If + keyLength is 0, any tpm_key key length is accepted. +*/ + +TPM_RESULT TPM_KeyParms_CheckProperties(TPM_KEY_PARMS *tpm_key_parms, + TPM_KEY_USAGE tpm_key_usage, + uint32_t keyLength, /* in bits */ + TPM_BOOL FIPS) +{ + TPM_RESULT rc = 0; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; /* used if algorithmID indicates RSA */ + + printf(" TPM_KeyParms_CheckProperties: keyUsage %04hx\n", tpm_key_usage); + printf(" TPM_KeyParms_CheckProperties: sigScheme %04hx\n", tpm_key_parms->sigScheme); + printf(" TPM_KeyParms_CheckProperties: encScheme %04hx\n", tpm_key_parms->encScheme); + if (rc == 0) { + /* the code currently only supports RSA */ + if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { + printf("TPM_KeyParms_CheckProperties: Error, algorithmID not TPM_ALG_RSA\n"); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* get the TPM_RSA_KEY_PARMS structure from the TPM_KEY_PARMS structure */ + /* NOTE: for now only support RSA keys */ + if (rc == 0) { + rc = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, tpm_key_parms); + } + /* check key length if specified as input parameter */ + if ((rc == 0) && (keyLength != 0)) { + if (tpm_rsa_key_parms->keyLength != keyLength) { /* in bits */ + printf("TPM_KeyParms_CheckProperties: Error, Bad keyLength should be %u, was %u\n", + keyLength, tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + } + if (rc == 0) { + if (tpm_rsa_key_parms->keyLength > TPM_RSA_KEY_LENGTH_MAX) { /* in bits */ + printf("TPM_KeyParms_CheckProperties: Error, Bad keyLength max %u, was %u\n", + TPM_RSA_KEY_LENGTH_MAX, tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + + } + /* kgold - Support only 2 primes */ + if (rc == 0) { + if (tpm_rsa_key_parms->numPrimes != 2) { + printf("TPM_KeyParms_CheckProperties: Error, numPrimes %u should be 2\n", + tpm_rsa_key_parms->numPrimes); + rc = TPM_BAD_KEY_PROPERTY; + } + } + /* if FIPS */ + if ((rc == 0) && FIPS) { + /* a. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS */ + if (tpm_rsa_key_parms->keyLength < 1024) { + printf("TPM_KeyParms_CheckProperties: Error, Invalid FIPS key length %u\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_NOTFIPS; + } + /* c. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return TPM_NOTFIPS */ + else if (tpm_key_usage == TPM_KEY_LEGACY) { + printf("TPM_KeyParms_CheckProperties: Error, FIPS authDataUsage TPM_AUTH_NEVER\n"); + rc = TPM_NOTFIPS; + } + } + /* From Part 2 5.7.1 Mandatory Key Usage Schemes and TPM_CreateWrapKey, TPM_LoadKey */ + if (rc == 0) { + switch (tpm_key_usage) { + case TPM_KEY_UNINITIALIZED: + printf("TPM_KeyParms_CheckProperties: Error, keyUsage TPM_KEY_UNINITIALIZED\n"); + rc = TPM_BAD_KEY_PROPERTY; + break; + case TPM_KEY_SIGNING: + if (tpm_key_parms->encScheme != TPM_ES_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Signing encScheme %04hx is not TPM_ES_NONE\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } +#ifdef TPM_V12 + else if ((tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_DER) && + (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { +#else /* TPM 1.1 */ + else if (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + +#endif + printf("TPM_KeyParms_CheckProperties: Error, " + "Signing sigScheme %04hx is not DER, SHA1, INFO\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_STORAGE: + if (tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage encScheme %04hx is not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { /*constant condition*/ + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage algorithmID %08x is not TPM_ALG_RSA\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + /* interoperable TPM only supports 2048 */ + else if (tpm_rsa_key_parms->keyLength < 2048) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Storage keyLength %d is less than 2048\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + else { + rc = TPM_KeyParams_CheckDefaultExponent(&(tpm_rsa_key_parms->exponent)); + } + break; + case TPM_KEY_IDENTITY: + if (tpm_key_parms->encScheme != TPM_ES_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity encScheme %04hx is not TPM_ES_NONE\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity sigScheme %04hx is not %04x\n", + tpm_key_parms->sigScheme, TPM_SS_RSASSAPKCS1v15_SHA1); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { /*constant condition*/ + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity algorithmID %08x is not TPM_ALG_RSA\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + /* interoperable TPM only supports 2048 */ + else if (tpm_rsa_key_parms->keyLength < 2048) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Identity keyLength %d is less than 2048\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + else { + rc = TPM_KeyParams_CheckDefaultExponent(&(tpm_rsa_key_parms->exponent)); + } + break; + case TPM_KEY_AUTHCHANGE: + if (tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Authchange encScheme %04hx is not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Authchange sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_rsa_key_parms->keyLength < 512) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Authchange keyLength %d is less than 512\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_BIND: + if ((tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) && + (tpm_key_parms->encScheme != TPM_ES_RSAESPKCSv15)) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Bind encScheme %04hx is not %04x or %04x\n", + tpm_key_parms->encScheme, + TPM_ES_RSAESOAEP_SHA1_MGF1, TPM_ES_RSAESPKCSv15); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Bind sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_LEGACY: + if ((tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) && + (tpm_key_parms->encScheme != TPM_ES_RSAESPKCSv15)) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Legacy encScheme %04hx is not %04x or %04x\n", + tpm_key_parms->encScheme, + TPM_ES_RSAESOAEP_SHA1_MGF1, TPM_ES_RSAESPKCSv15); + rc = TPM_BAD_KEY_PROPERTY; + } + else if ((tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (tpm_key_parms->sigScheme != TPM_SS_RSASSAPKCS1v15_DER)) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Legacy sigScheme %04hx is not %04x or %04x\n", + tpm_key_parms->sigScheme, + TPM_SS_RSASSAPKCS1v15_SHA1, TPM_SS_RSASSAPKCS1v15_DER); + rc = TPM_BAD_KEY_PROPERTY; + } + break; + case TPM_KEY_MIGRATE: + if (tpm_key_parms->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate encScheme %04hx is not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + tpm_key_parms->encScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->sigScheme != TPM_SS_NONE) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate sigScheme %04hx is not TPM_SS_NONE\n", + tpm_key_parms->sigScheme); + rc = TPM_BAD_KEY_PROPERTY; + } + else if (tpm_key_parms->algorithmID != TPM_ALG_RSA) { /*constant condition*/ + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate algorithmID %08x is not TPM_ALG_RSA\n", + tpm_key_parms->algorithmID); + rc = TPM_BAD_KEY_PROPERTY; + } + /* interoperable TPM only supports 2048 */ + else if (tpm_rsa_key_parms->keyLength < 2048) { + printf("TPM_KeyParms_CheckProperties: Error, " + "Migrate keyLength %d is less than 2048\n", + tpm_rsa_key_parms->keyLength); + rc = TPM_BAD_KEY_PROPERTY; + } + else { + rc = TPM_KeyParams_CheckDefaultExponent(&(tpm_rsa_key_parms->exponent)); + } + break; + default: + printf("TPM_KeyParms_CheckProperties: Error, Unknown keyUsage %04hx\n", tpm_key_usage); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + } + return rc; +} + +TPM_RESULT TPM_KeyParams_CheckDefaultExponent(TPM_SIZED_BUFFER *exponent) +{ + TPM_RESULT rc = 0; + uint32_t i; + + if ((rc == 0) && (exponent->size != 0)) { /* 0 is the default */ + printf(" TPM_KeyParams_CheckDefaultExponent: exponent size %u\n", exponent->size); + if (rc == 0) { + if (exponent->size < 3) { + printf("TPM_KeyParams_CheckDefaultExponent: Error, exponent size is %u\n", + exponent->size); + rc = TPM_BAD_KEY_PROPERTY; + } + } + if (rc == 0) { + for (i = 3 ; i < exponent->size ; i++) { + if (exponent->buffer[i] != 0) { + printf("TPM_KeyParams_CheckDefaultExponent: Error, exponent[%u] is %02x\n", + i, exponent->buffer[i]); + rc = TPM_BAD_KEY_PROPERTY; + } + } + } + if (rc == 0) { + if ((exponent->buffer[0] != tpm_default_rsa_exponent[0]) || + (exponent->buffer[1] != tpm_default_rsa_exponent[1]) || + (exponent->buffer[2] != tpm_default_rsa_exponent[2])) { + printf("TPM_KeyParams_CheckDefaultExponent: Error, exponent is %02x %02x %02x\n", + exponent->buffer[2], exponent->buffer[1], exponent->buffer[0]); + rc = TPM_BAD_KEY_PROPERTY; + } + } + } + return rc; +} + +/* + TPM_STORE_ASYMKEY +*/ + +void TPM_StoreAsymkey_Init(TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + printf(" TPM_StoreAsymkey_Init:\n"); + tpm_store_asymkey->payload = TPM_PT_ASYM; + TPM_Secret_Init(tpm_store_asymkey->usageAuth); + TPM_Secret_Init(tpm_store_asymkey->migrationAuth); + TPM_Digest_Init(tpm_store_asymkey->pubDataDigest); + TPM_StorePrivkey_Init(&(tpm_store_asymkey->privKey)); + return; +} + +/* TPM_StoreAsymkey_Load() deserializes the TPM_STORE_ASYMKEY structure. + + The serialized structure contains the private factor p. Normally, 'tpm_key_parms' and + tpm_store_pubkey are not NULL and the private key d is derived from p and the public key n and + exponent e. + + In some cases, a TPM_STORE_ASYMKEY is being manipulated without the rest of the TPM_KEY + structure. When 'tpm_key' is NULL, p is left intact, and the resulting structure cannot be used + as a private key. +*/ + +TPM_RESULT TPM_StoreAsymkey_Load(TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size, + TPM_KEY_PARMS *tpm_key_parms, + TPM_SIZED_BUFFER *pubKey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoreAsymkey_Load:\n"); + /* load payload */ + if ((rc == 0) && !isEK) { + rc = TPM_Load8(&(tpm_store_asymkey->payload), stream, stream_size); + } + /* check payload value to ease debugging */ + if ((rc == 0) && !isEK) { + if ( + /* normal key */ + (tpm_store_asymkey->payload != TPM_PT_ASYM) && + /* TPM_CMK_CreateKey payload */ + (tpm_store_asymkey->payload != TPM_PT_MIGRATE_RESTRICTED) && + /* TPM_CMK_ConvertMigration payload */ + (tpm_store_asymkey->payload != TPM_PT_MIGRATE_EXTERNAL) + ) { + printf("TPM_StoreAsymkey_Load: Error, invalid payload %02x\n", + tpm_store_asymkey->payload); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load usageAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Load(tpm_store_asymkey->usageAuth, stream, stream_size); + } + /* load migrationAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Load(tpm_store_asymkey->migrationAuth, stream, stream_size); + } + /* load pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_store_asymkey->pubDataDigest, stream, stream_size); + } + /* load privKey - actually prime factor p */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load((&(tpm_store_asymkey->privKey.p_key)), + stream, stream_size); + } + /* convert prime factor p to the private key */ + if ((rc == 0) && (tpm_key_parms != NULL) && (pubKey != NULL)) { + rc = TPM_StorePrivkey_Convert(tpm_store_asymkey, + tpm_key_parms, pubKey); + } + return rc; +} + +#if 0 +static TPM_RESULT TPM_StoreAsymkey_LoadTest(TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + int irc; + + /* actual */ + unsigned char *narr; + unsigned char *earr; + unsigned char *parr; + unsigned char *qarr; + unsigned char *darr; + + uint32_t nbytes; + uint32_t ebytes; + uint32_t pbytes; + uint32_t qbytes; + uint32_t dbytes; + + /* computed */ + unsigned char *q1arr = NULL; + unsigned char *d1arr = NULL; + + uint32_t q1bytes; + uint32_t d1bytes; + + printf(" TPM_StoreAsymkey_LoadTest:\n"); + /* actual data */ + if (rc == 0) { + narr = tpm_key->pubKey.key; + darr = tpm_key->tpm_store_asymkey->privKey.d_key; + parr = tpm_key->tpm_store_asymkey->privKey.p_key; + qarr = tpm_key->tpm_store_asymkey->privKey.q_key; + + nbytes = tpm_key->pubKey.keyLength; + dbytes = tpm_key->tpm_store_asymkey->privKey.d_keyLength; + pbytes = tpm_key->tpm_store_asymkey->privKey.p_keyLength; + qbytes = tpm_key->tpm_store_asymkey->privKey.q_keyLength; + + rc = TPM_Key_GetPublicKey(&nbytes, &narr, tpm_key); + } + if (rc == 0) { + rc = TPM_Key_GetExponent(&ebytes, &earr, tpm_key); + } + if (rc == 0) { + rc = TPM_Key_GetPrimeFactorP(&pbytes, &parr, tpm_key); + } + /* computed data */ + if (rc == 0) { + rc = TPM_RSAGetPrivateKey(&q1bytes, &q1arr, /* freed @1 */ + &d1bytes, &d1arr, /* freed @2 */ + nbytes, narr, + ebytes, earr, + pbytes, parr); + } + /* compare q */ + if (rc == 0) { + if (qbytes != q1bytes) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), qbytes %u q1bytes %u\n", + qbytes, q1bytes); + rc = TPM_FAIL; + } + } + if (rc == 0) { + irc = memcmp(qarr, q1arr, qbytes); + if (irc != 0) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), qarr mismatch\n"); + rc = TPM_FAIL; + } + } + /* compare d */ + if (rc == 0) { + if (dbytes != d1bytes) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), dbytes %u d1bytes %u\n", + dbytes, d1bytes); + rc = TPM_FAIL; + } + } + if (rc == 0) { + irc = memcmp(darr, d1arr, dbytes); + if (irc != 0) { + printf("TPM_StoreAsymkey_LoadTest: Error (fatal), darr mismatch\n"); + rc = TPM_FAIL; + } + } + free(q1arr); /* @1 */ + free(d1arr); /* @2 */ + return rc; +} +#endif + +TPM_RESULT TPM_StoreAsymkey_Store(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + const TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoreAsymkey_Store:\n"); + /* store payload */ + if ((rc == 0) && !isEK) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_store_asymkey->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + /* store usageAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Store(sbuffer, tpm_store_asymkey->usageAuth); + } + /* store migrationAuth */ + if ((rc == 0) && !isEK) { + rc = TPM_Secret_Store(sbuffer, tpm_store_asymkey->migrationAuth); + } + /* store pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_store_asymkey->pubDataDigest); + } + /* store privKey */ + if (rc == 0) { + rc = TPM_StorePrivkey_Store(sbuffer, &(tpm_store_asymkey->privKey)); + } + return rc; +} + +void TPM_StoreAsymkey_Delete(TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + printf(" TPM_StoreAsymkey_Delete:\n"); + if (tpm_store_asymkey != NULL) { + TPM_Secret_Delete(tpm_store_asymkey->usageAuth); + TPM_Secret_Delete(tpm_store_asymkey->migrationAuth); + TPM_StorePrivkey_Delete(&(tpm_store_asymkey->privKey)); + TPM_StoreAsymkey_Init(tpm_store_asymkey); + } + return; +} + +TPM_RESULT TPM_StoreAsymkey_GenerateEncData(TPM_SIZED_BUFFER *encData, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_KEY *parent_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_STORE_ASYMKEY serialization */ + + printf(" TPM_StoreAsymkey_GenerateEncData;\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_STORE_ASYMKEY member */ + if (rc == 0) { + rc = TPM_StoreAsymkey_Store(&sbuffer, FALSE, tpm_store_asymkey); + } + if (rc == 0) { + rc = TPM_RSAPublicEncryptSbuffer_Key(encData, &sbuffer, parent_key); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_StoreAsymkey_GetPrimeFactorP() gets the prime factor p from the TPM_STORE_ASYMKEY +*/ + +TPM_RESULT TPM_StoreAsymkey_GetPrimeFactorP(uint32_t *pbytes, + unsigned char **parr, + TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoreAsymkey_GetPrimeFactorP:\n"); + if (rc == 0) { + *pbytes = tpm_store_asymkey->privKey.p_key.size; + *parr = tpm_store_asymkey->privKey.p_key.buffer; + TPM_PrintFour(" TPM_StoreAsymkey_GetPrimeFactorP:", *parr); + } + return rc; +} + +/* TPM_StoreAsymkey_GetO1Size() calculates the destination o1 size for a TPM_STORE_ASYMKEY + + Used for creating a migration blob, TPM_STORE_ASYMKEY -> TPM_MIGRATE_ASYMKEY. + */ + +void TPM_StoreAsymkey_GetO1Size(uint32_t *o1_size, + TPM_STORE_ASYMKEY *tpm_store_asymkey) +{ + *o1_size = tpm_store_asymkey->privKey.p_key.size + /* private key */ + sizeof(uint32_t) - /* private key length */ + TPM_DIGEST_SIZE + /* - k1 -> k2 TPM_MIGRATE_ASYMKEY -> partPrivKey */ + sizeof(uint32_t) + /* TPM_MIGRATE_ASYMKEY -> partPrivKeyLen */ + sizeof(TPM_PAYLOAD_TYPE) + /* TPM_MIGRATE_ASYMKEY -> payload */ + TPM_SECRET_SIZE + /* TPM_MIGRATE_ASYMKEY -> usageAuth */ + TPM_DIGEST_SIZE + /* TPM_MIGRATE_ASYMKEY -> pubDataDigest */ + TPM_DIGEST_SIZE + /* OAEP pHash */ + TPM_DIGEST_SIZE + /* OAEP seed */ + 1; /* OAEP 0x01 byte */ + printf(" TPM_StoreAsymkey_GetO1Size: key size %u o1 size %u\n", + tpm_store_asymkey->privKey.p_key.size, *o1_size); +} + +/* TPM_StoreAsymkey_CheckO1Size() verifies the destination o1_size against the source k1k2 array + length + + This is a currently just a sanity check on the TPM_StoreAsymkey_GetO1Size() function. +*/ + +TPM_RESULT TPM_StoreAsymkey_CheckO1Size(uint32_t o1_size, + uint32_t k1k2_length) +{ + TPM_RESULT rc = 0; + + /* sanity check the TPM_MIGRATE_ASYMKEY size against the requested o1 size */ + /* K1 K2 are the length and value of the private key, 4 + 128 bytes for a 2048-bit key */ + if (o1_size < + (k1k2_length - TPM_DIGEST_SIZE + /* k1 k2, the first 20 bytes are used as the OAEP seed */ + sizeof(TPM_PAYLOAD_TYPE) + /* TPM_MIGRATE_ASYMKEY -> payload */ + TPM_SECRET_SIZE + /* TPM_MIGRATE_ASYMKEY -> usageAuth */ + TPM_DIGEST_SIZE + /* TPM_MIGRATE_ASYMKEY -> pubDataDigest */ + sizeof(uint32_t) + /* TPM_MIGRATE_ASYMKEY -> partPrivKeyLen */ + TPM_DIGEST_SIZE + /* OAEP pHash */ + TPM_DIGEST_SIZE + /* OAEP seed */ + 1)) { /* OAEP 0x01 byte */ + printf(" TPM_StoreAsymkey_CheckO1Size: Error (fatal) k1k2_length %d too large for o1 %u\n", + k1k2_length, o1_size); + rc = TPM_FAIL; + } + return rc; +} + +/* TPM_StoreAsymkey_StoreO1() creates an OAEP encoded TPM_MIGRATE_ASYMKEY from a + TPM_STORE_ASYMKEY. + + It does the common steps of constructing the TPM_MIGRATE_ASYMKEY, serializing it, and OAEP + padding. +*/ + +TPM_RESULT TPM_StoreAsymkey_StoreO1(BYTE *o1, + uint32_t o1_size, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_DIGEST pHash, + TPM_PAYLOAD_TYPE payload_type, + TPM_SECRET usageAuth) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER k1k2_sbuffer; /* serialization of TPM_STORE_ASYMKEY -> privKey -> key */ + const unsigned char *k1k2; /* serialization results */ + uint32_t k1k2_length; + TPM_MIGRATE_ASYMKEY tpm_migrate_asymkey; + TPM_STORE_BUFFER tpm_migrate_asymkey_sbuffer; /* serialized tpm_migrate_asymkey */ + const unsigned char *tpm_migrate_asymkey_buffer; + uint32_t tpm_migrate_asymkey_length; + + printf(" TPM_StoreAsymkey_StoreO1:\n"); + TPM_Sbuffer_Init(&k1k2_sbuffer); /* freed @1 */ + TPM_MigrateAsymkey_Init(&tpm_migrate_asymkey); /* freed @2 */ + TPM_Sbuffer_Init(&tpm_migrate_asymkey_sbuffer); /* freed @3 */ + + /* NOTE Comments from TPM_CreateMigrationBlob rev 81 */ + /* a. Build two byte arrays, K1 and K2: */ + /* i. K1 = TPM_STORE_ASYMKEY.privKey[0..19] (TPM_STORE_ASYMKEY.privKey.keyLength + 16 bytes of + TPM_STORE_ASYMKEY.privKey.key), sizeof(K1) = 20 */ + /* ii. K2 = TPM_STORE_ASYMKEY.privKey[20..131] (position 16-127 of + TPM_STORE_ASYMKEY. privKey.key), sizeof(K2) = 112 */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(&k1k2_sbuffer, &(tpm_store_asymkey->privKey.p_key)); + } + if (rc == 0) { + TPM_Sbuffer_Get(&k1k2_sbuffer, &k1k2, &k1k2_length); + /* sanity check the TPM_STORE_ASYMKEY -> privKey -> key size against the requested o1 + size */ + rc = TPM_StoreAsymkey_CheckO1Size(o1_size, k1k2_length); + } + /* b. Build M1 a TPM_MIGRATE_ASYMKEY structure */ + /* i. TPM_MIGRATE_ASYMKEY.payload = TPM_PT_MIGRATE */ + /* ii. TPM_MIGRATE_ASYMKEY.usageAuth = TPM_STORE_ASYMKEY.usageAuth */ + /* iii. TPM_MIGRATE_ASYMKEY.pubDataDigest = TPM_STORE_ASYMKEY. pubDataDigest */ + /* iv. TPM_MIGRATE_ASYMKEY.partPrivKeyLen = 112 - 127. */ + /* v. TPM_MIGRATE_ASYMKEY.partPrivKey = K2 */ + if (rc == 0) { + tpm_migrate_asymkey.payload = payload_type; + TPM_Secret_Copy(tpm_migrate_asymkey.usageAuth, usageAuth); + TPM_Digest_Copy(tpm_migrate_asymkey.pubDataDigest, tpm_store_asymkey->pubDataDigest); + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: k1 -", k1k2); + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: k2 -", k1k2 + TPM_DIGEST_SIZE); + rc = TPM_SizedBuffer_Set(&(tpm_migrate_asymkey.partPrivKey), + k1k2_length - TPM_DIGEST_SIZE, /* k2 length 112 for 2048 bit key */ + k1k2 + TPM_DIGEST_SIZE); /* k2 */ + } + /* c. Create o1 (which SHALL be 198 bytes for a 2048 bit RSA key) by performing the OAEP + encoding of m using OAEP parameters of */ + /* i. m = M1 the TPM_MIGRATE_ASYMKEY structure */ + /* ii. pHash = d1->migrationAuth */ + /* iii. seed = s1 = K1 */ + if (rc == 0) { + /* serialize TPM_MIGRATE_ASYMKEY m */ + rc = TPM_MigrateAsymkey_Store(&tpm_migrate_asymkey_sbuffer, &tpm_migrate_asymkey); + } + if (rc == 0) { + /* get the serialization result */ + TPM_Sbuffer_Get(&tpm_migrate_asymkey_sbuffer, + &tpm_migrate_asymkey_buffer, &tpm_migrate_asymkey_length); + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: pHash -", pHash); + rc = TPM_RSA_padding_add_PKCS1_OAEP(o1, /* output */ + o1_size, + tpm_migrate_asymkey_buffer, /* message */ + tpm_migrate_asymkey_length, + pHash, + k1k2); /* k1, seed */ + TPM_PrintFour(" TPM_StoreAsymkey_StoreO1: o1 -", o1); + } + TPM_Sbuffer_Delete(&k1k2_sbuffer); /* @1 */ + TPM_MigrateAsymkey_Delete(&tpm_migrate_asymkey); /* @2 */ + TPM_Sbuffer_Delete(&tpm_migrate_asymkey_sbuffer); /* @3 */ + return rc; +} + +/* TPM_StoreAsymkey_LoadO1() extracts TPM_STORE_ASYMKEY from the OAEP encoded TPM_MIGRATE_ASYMKEY. + + It does the common steps OAEP depadding, deserializing the TPM_MIGRATE_ASYMKEY, and + reconstructing the TPM_STORE_ASYMKEY. + + It sets these, which may or may not be correct at a higher level + + TPM_STORE_ASYMKEY -> payload = TPM_MIGRATE_ASYMKEY -> payload + TPM_STORE_ASYMKEY -> usageAuth = TPM_MIGRATE_ASYMKEY -> usageAuth + TPM_STORE_ASYMKEY -> migrationAuth = pHash + TPM_STORE_ASYMKEY -> pubDataDigest = TPM_MIGRATE_ASYMKEY -> pubDataDigest + TPM_STORE_ASYMKEY -> privKey = seed + TPM_MIGRATE_ASYMKEY -> partPrivKey +*/ + +TPM_RESULT TPM_StoreAsymkey_LoadO1(TPM_STORE_ASYMKEY *tpm_store_asymkey, /* output */ + BYTE *o1, /* input */ + uint32_t o1_size) /* input */ +{ + TPM_RESULT rc = 0; + BYTE *tpm_migrate_asymkey_buffer; + uint32_t tpm_migrate_asymkey_length; + TPM_DIGEST seed; + TPM_DIGEST pHash; + unsigned char *stream; /* for deserializing structures */ + uint32_t stream_size; + TPM_MIGRATE_ASYMKEY tpm_migrate_asymkey; + TPM_STORE_BUFFER k1k2_sbuffer; + const unsigned char *k1k2_buffer; + uint32_t k1k2_length; + + printf(" TPM_StoreAsymkey_LoadO1:\n"); + TPM_MigrateAsymkey_Init(&tpm_migrate_asymkey); /* freed @1 */ + TPM_Sbuffer_Init(&k1k2_sbuffer); /* freed @2 */ + tpm_migrate_asymkey_buffer = NULL; /* freed @3 */ + /* allocate memory for TPM_MIGRATE_ASYMKEY after removing OAEP pad from o1 */ + if (rc == 0) { + rc = TPM_Malloc(&tpm_migrate_asymkey_buffer, o1_size); + } + if (rc == 0) { + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: o1 -", o1); + /* 5. Create m1, seed and pHash by OAEP decoding o1 */ + printf(" TPM_StoreAsymkey_LoadO1: Depadding\n"); + rc = TPM_RSA_padding_check_PKCS1_OAEP(tpm_migrate_asymkey_buffer, /* out: to */ + &tpm_migrate_asymkey_length, /* out: to length */ + o1_size, /* to size */ + o1, o1_size, /* from, from length */ + pHash, + seed); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: tpm_migrate_asymkey_buffer -", + tpm_migrate_asymkey_buffer); + printf(" TPM_StoreAsymkey_LoadO1: tpm_migrate_asymkey_length %u\n", + tpm_migrate_asymkey_length); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: - pHash", pHash); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: - seed", seed); + } + /* deserialize the buffer back to a TPM_MIGRATE_ASYMKEY */ + if (rc == 0) { + stream = tpm_migrate_asymkey_buffer; + stream_size = tpm_migrate_asymkey_length; + rc = TPM_MigrateAsymkey_Load(&tpm_migrate_asymkey, &stream, &stream_size); + printf(" TPM_StoreAsymkey_LoadO1: partPrivKey length %u\n", + tpm_migrate_asymkey.partPrivKey.size); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: partPrivKey -", + tpm_migrate_asymkey.partPrivKey.buffer); + } + /* create k1k2 by combining seed (k1) and TPM_MIGRATE_ASYMKEY.partPrivKey (k2) field */ + if (rc == 0) { + rc = TPM_Digest_Store(&k1k2_sbuffer, seed); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(&k1k2_sbuffer, + tpm_migrate_asymkey.partPrivKey.buffer, + tpm_migrate_asymkey.partPrivKey.size); + } + /* assemble the TPM_STORE_ASYMKEY structure */ + if (rc == 0) { + tpm_store_asymkey->payload = tpm_migrate_asymkey.payload; + TPM_Digest_Copy(tpm_store_asymkey->usageAuth, tpm_migrate_asymkey.usageAuth); + TPM_Digest_Copy(tpm_store_asymkey->migrationAuth, pHash); + TPM_Digest_Copy(tpm_store_asymkey->pubDataDigest, tpm_migrate_asymkey.pubDataDigest); + TPM_Sbuffer_Get(&k1k2_sbuffer, &k1k2_buffer, &k1k2_length); + printf(" TPM_StoreAsymkey_LoadO1: k1k2 length %u\n", k1k2_length); + TPM_PrintFour(" TPM_StoreAsymkey_LoadO1: k1k2", k1k2_buffer); + rc = TPM_SizedBuffer_Load(&(tpm_store_asymkey->privKey.p_key), + (unsigned char **)&k1k2_buffer, &k1k2_length); + } + TPM_MigrateAsymkey_Delete(&tpm_migrate_asymkey); /* @1 */ + TPM_Sbuffer_Delete(&k1k2_sbuffer); /* @2 */ + free(tpm_migrate_asymkey_buffer); /* @3 */ + return rc; +} + + +/* + TPM_MIGRATE_ASYMKEY +*/ + +/* TPM_MigrateAsymkey_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_MigrateAsymkey_Init(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) +{ + printf(" TPM_MigrateAsymkey_Init:\n"); + tpm_migrate_asymkey->payload = TPM_PT_MIGRATE; + TPM_Secret_Init(tpm_migrate_asymkey->usageAuth); + TPM_Digest_Init(tpm_migrate_asymkey->pubDataDigest); + TPM_SizedBuffer_Init(&(tpm_migrate_asymkey->partPrivKey)); + return; +} + +/* TPM_MigrateAsymkey_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_MigrateAsymkey_Init() + After use, call TPM_MigrateAsymkey_Delete() to free memory +*/ + +TPM_RESULT TPM_MigrateAsymkey_Load(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_MigrateAsymkey_Load:\n"); + /* load payload */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_migrate_asymkey->payload), stream, stream_size); + } + /* check payload value to ease debugging */ + if (rc == 0) { + if ((tpm_migrate_asymkey->payload != TPM_PT_MIGRATE) && + (tpm_migrate_asymkey->payload != TPM_PT_MAINT) && + (tpm_migrate_asymkey->payload != TPM_PT_CMK_MIGRATE)) { + printf("TPM_MigrateAsymkey_Load: Error illegal payload %02x\n", + tpm_migrate_asymkey->payload); + rc = TPM_INVALID_STRUCTURE; + } + } + /* load usageAuth */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_migrate_asymkey->usageAuth, stream, stream_size); + } + /* load pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_migrate_asymkey->pubDataDigest, stream, stream_size); + } + /* load partPrivKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_migrate_asymkey->partPrivKey), stream, stream_size); + } + return rc; +} + +/* TPM_MigrateAsymkey_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_MigrateAsymkey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_MigrateAsymkey_Store:\n"); + /* store payload */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_migrate_asymkey->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + /* store usageAuth */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_migrate_asymkey->usageAuth); + } + /* store pubDataDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_migrate_asymkey->pubDataDigest); + } + /* store partPrivKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_migrate_asymkey->partPrivKey)); + } + return rc; +} + +/* TPM_MigrateAsymkey_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_MigrateAsymkey_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_MigrateAsymkey_Delete(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey) +{ + printf(" TPM_MigrateAsymkey_Delete:\n"); + if (tpm_migrate_asymkey != NULL) { + TPM_Secret_Delete(tpm_migrate_asymkey->usageAuth); + TPM_SizedBuffer_Zero(&(tpm_migrate_asymkey->partPrivKey)); + TPM_SizedBuffer_Delete(&(tpm_migrate_asymkey->partPrivKey)); + TPM_MigrateAsymkey_Init(tpm_migrate_asymkey); + } + return; +} + +/* + TPM_STORE_PRIVKEY +*/ + +void TPM_StorePrivkey_Init(TPM_STORE_PRIVKEY *tpm_store_privkey) +{ + printf(" TPM_StorePrivkey_Init:\n"); + TPM_SizedBuffer_Init(&(tpm_store_privkey->d_key)); + TPM_SizedBuffer_Init(&(tpm_store_privkey->p_key)); + TPM_SizedBuffer_Init(&(tpm_store_privkey->q_key)); + return; +} + +/* TPM_StorePrivkey_Convert() sets the prime factor q and private key d based on the prime factor p + and the public key and exponent. +*/ + +TPM_RESULT TPM_StorePrivkey_Convert(TPM_STORE_ASYMKEY *tpm_store_asymkey, /* I/O result */ + TPM_KEY_PARMS *tpm_key_parms, /* to get exponent */ + TPM_SIZED_BUFFER *pubKey) /* to get public key */ +{ + TPM_RESULT rc = 0; + /* computed data */ + unsigned char *narr; + unsigned char *earr; + unsigned char *parr; + unsigned char *qarr = NULL; + unsigned char *darr = NULL; + uint32_t nbytes; + uint32_t ebytes; + uint32_t pbytes; + uint32_t qbytes; + uint32_t dbytes; + + + printf(" TPM_StorePrivkey_Convert:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_StorePrivkey_Convert: p", tpm_store_asymkey->privKey.p_key.buffer); + nbytes = pubKey->size; + narr = pubKey->buffer; + rc = TPM_KeyParms_GetExponent(&ebytes, &earr, tpm_key_parms); + } + if (rc == 0) { + rc = TPM_StoreAsymkey_GetPrimeFactorP(&pbytes, &parr, tpm_store_asymkey); + } + if (rc == 0) { + rc = TPM_RSAGetPrivateKey(&qbytes, &qarr, /* freed @1 */ + &dbytes, &darr, /* freed @2 */ + nbytes, narr, + ebytes, earr, + pbytes, parr); + } + if (rc == 0) { + TPM_PrintFour(" TPM_StorePrivkey_Convert: q", qarr); + TPM_PrintFour(" TPM_StorePrivkey_Convert: d", darr); + rc = TPM_SizedBuffer_Set((&(tpm_store_asymkey->privKey.q_key)), qbytes, qarr); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Set((&(tpm_store_asymkey->privKey.d_key)), dbytes, darr); + } + free(qarr); /* @1 */ + free(darr); /* @2 */ + return rc; +} + +/* TPM_StorePrivkey_Store serializes a TPM_STORE_PRIVKEY structure, appending results to 'sbuffer' + + Only the prime factor p is stored. The other prime factor q and the private key d are + recalculated after a load. + */ + +TPM_RESULT TPM_StorePrivkey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STORE_PRIVKEY *tpm_store_privkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StorePrivkey_Store:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_StorePrivkey_Store: p", tpm_store_privkey->p_key.buffer); + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_store_privkey->p_key)); + } + return rc; +} + +void TPM_StorePrivkey_Delete(TPM_STORE_PRIVKEY *tpm_store_privkey) +{ + printf(" TPM_StorePrivkey_Delete:\n"); + if (tpm_store_privkey != NULL) { + TPM_SizedBuffer_Zero(&(tpm_store_privkey->d_key)); + TPM_SizedBuffer_Zero(&(tpm_store_privkey->p_key)); + TPM_SizedBuffer_Zero(&(tpm_store_privkey->q_key)); + + TPM_SizedBuffer_Delete(&(tpm_store_privkey->d_key)); + TPM_SizedBuffer_Delete(&(tpm_store_privkey->p_key)); + TPM_SizedBuffer_Delete(&(tpm_store_privkey->q_key)); + TPM_StorePrivkey_Init(tpm_store_privkey); + } + return; +} + +/* + TPM_PUBKEY +*/ + +void TPM_Pubkey_Init(TPM_PUBKEY *tpm_pubkey) +{ + printf(" TPM_Pubkey_Init:\n"); + TPM_KeyParms_Init(&(tpm_pubkey->algorithmParms)); + TPM_SizedBuffer_Init(&(tpm_pubkey->pubKey)); + return; +} + +TPM_RESULT TPM_Pubkey_Load(TPM_PUBKEY *tpm_pubkey, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Load:\n"); + /* load algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Load(&(tpm_pubkey->algorithmParms), stream, stream_size); + } + /* load pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_pubkey->pubKey), stream, stream_size); + } + return rc; +} + +/* TPM_Pubkey_Store serializes a TPM_PUBKEY structure, appending results to 'sbuffer' +*/ + +TPM_RESULT TPM_Pubkey_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Store:\n"); + if (rc == 0) { + rc = TPM_KeyParms_Store(sbuffer, &(tpm_pubkey->algorithmParms)); + } + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_pubkey->pubKey)); + } + return rc; +} + +void TPM_Pubkey_Delete(TPM_PUBKEY *tpm_pubkey) +{ + printf(" TPM_Pubkey_Delete:\n"); + if (tpm_pubkey != NULL) { + TPM_KeyParms_Delete(&(tpm_pubkey->algorithmParms)); + TPM_SizedBuffer_Delete(&(tpm_pubkey->pubKey)); + TPM_Pubkey_Init(tpm_pubkey); + } + return; +} + +TPM_RESULT TPM_Pubkey_Set(TPM_PUBKEY *tpm_pubkey, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Set:\n"); + if (rc == 0) { + /* add TPM_KEY_PARMS algorithmParms */ + rc = TPM_KeyParms_Copy(&(tpm_pubkey->algorithmParms), + &(tpm_key->algorithmParms)); + } + if (rc == 0) { + /* add TPM_SIZED_BUFFER pubKey */ + rc = TPM_SizedBuffer_Copy(&(tpm_pubkey->pubKey), + &(tpm_key->pubKey)); + } + return rc; +} + +TPM_RESULT TPM_Pubkey_Copy(TPM_PUBKEY *dest_tpm_pubkey, + TPM_PUBKEY *src_tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_Copy:\n"); + /* copy TPM_KEY_PARMS algorithmParms */ + if (rc == 0) { + rc = TPM_KeyParms_Copy(&(dest_tpm_pubkey->algorithmParms), + &(src_tpm_pubkey->algorithmParms)); + } + /* copy TPM_SIZED_BUFFER pubKey */ + if (rc == 0) { + rc = TPM_SizedBuffer_Copy(&(dest_tpm_pubkey->pubKey), + &(src_tpm_pubkey->pubKey)); + } + return rc; + +} + +/* TPM_Pubkey_GetExponent() gets the exponent key from the TPM_RSA_KEY_PARMS contained in a + TPM_PUBKEY +*/ + +TPM_RESULT TPM_Pubkey_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_GetExponent:\n"); + if (rc == 0) { + rc = TPM_KeyParms_GetExponent(ebytes, earr, &(tpm_pubkey->algorithmParms)); + } + return rc; +} + +/* TPM_Pubkey_GetPublicKey() gets the public key from the TPM_PUBKEY + */ + +TPM_RESULT TPM_Pubkey_GetPublicKey(uint32_t *nbytes, + unsigned char **narr, + TPM_PUBKEY *tpm_pubkey) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Pubkey_GetPublicKey:\n"); + if (rc == 0) { + *nbytes = tpm_pubkey->pubKey.size; + *narr = tpm_pubkey->pubKey.buffer; + } + return rc; +} + +/* + TPM_RSA_KEY_PARMS +*/ + + +/* Allocates and loads a TPM_RSA_KEY_PARMS structure + + Must be delete'd and freed by the caller. +*/ + +void TPM_RSAKeyParms_Init(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + printf(" TPM_RSAKeyParms_Init:\n"); + tpm_rsa_key_parms->keyLength = 0; + tpm_rsa_key_parms->numPrimes = 0; + TPM_SizedBuffer_Init(&(tpm_rsa_key_parms->exponent)); + return; +} + +/* TPM_RSAKeyParms_Load() sets members from stream, and shifts the stream past the bytes consumed. + + Must call TPM_RSAKeyParms_Delete() to free +*/ + +TPM_RESULT TPM_RSAKeyParms_Load(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_Load:\n"); + /* load keyLength */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_rsa_key_parms->keyLength), stream, stream_size); + } + /* load numPrimes */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_rsa_key_parms->numPrimes), stream, stream_size); + } + /* load exponent */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_rsa_key_parms->exponent), stream, stream_size); + } + return rc; +} + +/* TPM_RSAKeyParms_Store serializes a TPM_RSA_KEY_PARMS structure, appending results to 'sbuffer' +*/ + +TPM_RESULT TPM_RSAKeyParms_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_Store:\n"); + /* store keyLength */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_rsa_key_parms->keyLength); + } + /* store numPrimes */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_rsa_key_parms->numPrimes); + } + /* store exponent */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_rsa_key_parms->exponent)); + } + return rc; +} + +/* TPM_RSAKeyParms_Delete frees any member allocated memory + + If 'tpm_rsa_key_parms' is NULL, this is a no-op. + */ + +void TPM_RSAKeyParms_Delete(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + printf(" TPM_RSAKeyParms_Delete:\n"); + if (tpm_rsa_key_parms != NULL) { + TPM_SizedBuffer_Delete(&(tpm_rsa_key_parms->exponent)); + TPM_RSAKeyParms_Init(tpm_rsa_key_parms); + } + return; +} + +/* TPM_RSAKeyParms_Copy() does a copy of the source to the destination. + + The destination must be initialized first. +*/ + +TPM_RESULT TPM_RSAKeyParms_Copy(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms_dest, + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms_src) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_Copy:\n"); + if (rc == 0) { + tpm_rsa_key_parms_dest->keyLength = tpm_rsa_key_parms_src->keyLength; + tpm_rsa_key_parms_dest->numPrimes = tpm_rsa_key_parms_src->numPrimes; + rc = TPM_SizedBuffer_Copy(&(tpm_rsa_key_parms_dest->exponent), + &(tpm_rsa_key_parms_src->exponent)); + } + return rc; +} + +/* TPM_RSAKeyParms_New() allocates memory for a TPM_RSA_KEY_PARMS and initializes the structure */ + +TPM_RESULT TPM_RSAKeyParms_New(TPM_RSA_KEY_PARMS **tpm_rsa_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_New:\n"); + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)tpm_rsa_key_parms, sizeof(TPM_RSA_KEY_PARMS)); + } + if (rc == 0) { + TPM_RSAKeyParms_Init(*tpm_rsa_key_parms); + } + return rc; +} + +/* TPM_RSAKeyParms_GetExponent() gets the exponent array and size from tpm_rsa_key_parms. + + If the structure exponent.size is zero, the default RSA exponent is returned. +*/ + +TPM_RESULT TPM_RSAKeyParms_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms) +{ + TPM_RESULT rc = 0; + + printf(" TPM_RSAKeyParms_GetExponent:\n"); + if (tpm_rsa_key_parms->exponent.size != 0) { + *ebytes = tpm_rsa_key_parms->exponent.size; + *earr = tpm_rsa_key_parms->exponent.buffer; + } + else { + *ebytes = 3; + *earr = tpm_default_rsa_exponent; + } + return rc; +} + +/* + A Key Handle Entry +*/ + +/* TPM_KeyHandleEntry_Init() removes an entry from the list. It DOES NOT delete the + TPM_KEY object. */ + +void TPM_KeyHandleEntry_Init(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + tpm_key_handle_entry->handle = 0; + tpm_key_handle_entry->key = NULL; + tpm_key_handle_entry->parentPCRStatus = TRUE; + tpm_key_handle_entry->keyControl = 0; + return; +} + +/* TPM_KeyHandleEntry_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_KeyHandleEntry_Init() + After use, call TPM_KeyHandleEntry_Delete() to free memory +*/ + +TPM_RESULT TPM_KeyHandleEntry_Load(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyHandleEntry_Load:\n"); + /* load handle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_key_handle_entry->handle), stream, stream_size); + } + /* malloc space for the key member */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_key_handle_entry->key), sizeof(TPM_KEY)); + } + /* load key */ + if (rc == 0) { + TPM_Key_Init(tpm_key_handle_entry->key); + rc = TPM_Key_LoadClear(tpm_key_handle_entry->key, + FALSE, /* not EK */ + stream, stream_size); + } + /* load parentPCRStatus */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_key_handle_entry->parentPCRStatus), stream, stream_size); + } + /* load keyControl */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_key_handle_entry->keyControl), stream, stream_size); + } + return rc; +} + +/* TPM_KeyHandleEntry_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_KeyHandleEntry_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + TPM_RESULT rc = 0; + + printf(" TPM_KeyHandleEntry_Store:\n"); + /* store handle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_handle_entry->handle); + } + /* store key with private data appended in clear text */ + if (rc == 0) { + rc = TPM_Key_StoreClear(sbuffer, + FALSE, /* not EK */ + tpm_key_handle_entry->key); + } + /* store parentPCRStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_key_handle_entry->parentPCRStatus), sizeof(TPM_BOOL)); + } + /* store keyControl */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_handle_entry->keyControl); + } + return rc; +} + +/* TPM_KeyHandleEntry_Delete() deletes an entry from the list, deletes the TPM_KEY object, and + free's the TPM_KEY. +*/ + +void TPM_KeyHandleEntry_Delete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + if (tpm_key_handle_entry != NULL) { + if (tpm_key_handle_entry->handle != 0) { + printf(" TPM_KeyHandleEntry_Delete: Deleting %08x\n", tpm_key_handle_entry->handle); + TPM_Key_Delete(tpm_key_handle_entry->key); + free(tpm_key_handle_entry->key); + } + TPM_KeyHandleEntry_Init(tpm_key_handle_entry); + } + return; +} + +/* TPM_KeyHandleEntry_FlushSpecific() flushes a key handle according to the rules of + TPM_FlushSpecific() +*/ + +TPM_RESULT TPM_KeyHandleEntry_FlushSpecific(tpm_state_t *tpm_state, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + TPM_RESULT rc = 0; + TPM_AUTHHANDLE authHandle = 0; /* dummy parameter */ + TPM_BOOL continueAuthSession; /* dummy parameter */ + + printf(" TPM_KeyHandleEntry_FlushSpecific:\n"); + if (rc == 0) { + /* Internal error, should never happen */ + if (tpm_key_handle_entry->key == NULL) { + printf("TPM_KeyHandleEntry_FlushSpecific: Error (fatal), key is NULL\n"); + rc = TPM_FAIL; + } + } + /* terminate OSAP and DSAP sessions associated with the key */ + if (rc == 0) { + /* The dummy parameters are not used. The session, if any, associated with this function + is handled elsewhere. */ + TPM_AuthSessions_TerminateEntity(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions, + TPM_ET_KEYHANDLE, /* TPM_ENTITY_TYPE */ + &(tpm_key_handle_entry->key-> + tpm_store_asymkey->pubDataDigest)); /* entityDigest */ + printf(" TPM_KeyHandleEntry_FlushSpecific: Flushing key handle %08x\n", + tpm_key_handle_entry->handle); + /* free the TPM_KEY resources, free the key itself, and remove entry from the key handle + entries list */ + TPM_KeyHandleEntry_Delete(tpm_key_handle_entry); + } + return rc; +} + +/* + Key Handle Entries +*/ + +/* TPM_KeyHandleEntries_Init() initializes the fixed TPM_KEY_HANDLE_ENTRY array. All entries are + emptied. The keys are not deleted. +*/ + +void TPM_KeyHandleEntries_Init(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + size_t i; + + printf(" TPM_KeyHandleEntries_Init:\n"); + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + TPM_KeyHandleEntry_Init(&(tpm_key_handle_entries[i])); + } + return; +} + +/* TPM_KeyHandleEntries_Delete() deletes and freed all TPM_KEY's stored in entries, and the entry + +*/ + +void TPM_KeyHandleEntries_Delete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + size_t i; + + printf(" TPM_KeyHandleEntries_Delete:\n"); + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + TPM_KeyHandleEntry_Delete(&(tpm_key_handle_entries[i])); + } + return; +} + +/* TPM_KeyHandleEntries_Load() loads the key handle entries from a stream created by + TPM_KeyHandleEntries_Store() + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_KeyHandleEntries_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t keyCount = 0; /* keys to be saved */ + size_t i; + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; + + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_KEY_HANDLE_ENTRIES_V1, stream, stream_size); + } + /* get the count of keys in the stream */ + if (rc == 0) { + rc = TPM_Load32(&keyCount, stream, stream_size); + printf(" TPM_KeyHandleEntries_Load: %u keys to be loaded\n", keyCount); + } + /* sanity check that keyCount not greater than key slots */ + if (rc == 0) { + if (keyCount > TPM_KEY_HANDLES) { + printf("TPM_KeyHandleEntries_Load: Error (fatal)" + " key handles in stream %u greater than %d\n", + keyCount, TPM_KEY_HANDLES); + rc = TPM_FAIL; + } + } + /* for each key handle entry */ + for (i = 0 ; (rc == 0) && (i < keyCount) ; i++) { + /* deserialize the key handle entry and its key member */ + if (rc == 0) { + TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* freed @2 on error */ + rc = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, stream, stream_size); + } + if (rc == 0) { + printf(" TPM_KeyHandleEntries_Load: Loading key handle %08x\n", + tpm_key_handle_entry.handle); + /* Add the entry to the list. Keep the handle. If the suggested value could not be + accepted, this is a "should never happen" fatal error. It means that the save key + handle was saved twice. */ + rc = TPM_KeyHandleEntries_AddEntry(&(tpm_key_handle_entry.handle), /* suggested */ + TRUE, /* keep handle */ + tpm_state->tpm_key_handle_entries, + &tpm_key_handle_entry); + } + /* if there was an error copying the entry to the array, the entry must be delete'd to + prevent a memory leak, since a key has been loaded to the entry */ + if (rc != 0) { + TPM_KeyHandleEntry_Delete(&tpm_key_handle_entry); /* @2 on error */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_Store() stores the key handle entries to a stream that can be restored + through TPM_KeyHandleEntries_Load(). + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_KeyHandleEntries_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + size_t start; /* iterator though key handle entries */ + size_t current; /* iterator though key handle entries */ + uint32_t keyCount; /* keys to be saved */ + TPM_BOOL save; /* should key be saved */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_KEY_HANDLE_ENTRIES_V1); + } + /* first count up the keys */ + if (rc == 0) { + start = 0; + keyCount = 0; + printf(" TPM_KeyHandleEntries_Store: Counting keys to be stored\n"); + } + while ((rc == 0) && + /* returns TPM_RETRY when at the end of the table, terminates loop */ + (TPM_KeyHandleEntries_GetNextEntry(&tpm_key_handle_entry, + ¤t, + tpm_state->tpm_key_handle_entries, + start)) == 0) { + TPM_SaveState_IsSaveKey(&save, tpm_key_handle_entry); + if (save) { + keyCount++; + } + start = current + 1; + } + /* store the number of entries to save */ + if (rc == 0) { + printf(" TPM_KeyHandleEntries_Store: %u keys to be stored\n", keyCount); + rc = TPM_Sbuffer_Append32(sbuffer, keyCount); + } + /* for each key handle entry */ + if (rc == 0) { + printf(" TPM_KeyHandleEntries_Store: Storing keys\n"); + start = 0; + } + while ((rc == 0) && + /* returns TPM_RETRY when at the end of the table, terminates loop */ + (TPM_KeyHandleEntries_GetNextEntry(&tpm_key_handle_entry, + ¤t, + tpm_state->tpm_key_handle_entries, + start)) == 0) { + TPM_SaveState_IsSaveKey(&save, tpm_key_handle_entry); + if (save) { + /* store the key handle entry and its associated key */ + rc = TPM_KeyHandleEntry_Store(sbuffer, tpm_key_handle_entry); + } + start = current + 1; + } + return rc; +} + + + +/* TPM_KeyHandleEntries_StoreHandles() stores only the two members which are part of the + specification. + + - the number of loaded keys + - a list of key handles + + A TPM_KEY_HANDLE_LIST structure that enumerates all key handles loaded on the TPM. The list only + contains the number of handles that an external manager can operate with and does not include the + EK or SRK. This is command is available for backwards compatibility. It is the same as + TPM_CAP_HANDLE with a resource type of keys. +*/ + +TPM_RESULT TPM_KeyHandleEntries_StoreHandles(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + TPM_RESULT rc = 0; + uint16_t i, loadedCount; + + printf(" TPM_KeyHandleEntries_StoreHandles:\n"); + if (rc == 0) { + loadedCount = 0; + /* count the number of loaded handles */ + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + if (tpm_key_handle_entries[i].key != NULL) { + loadedCount++; + } + } + /* store 'loaded' handle count */ + rc = TPM_Sbuffer_Append16(sbuffer, loadedCount); + } + for (i = 0 ; (rc == 0) && (i < TPM_KEY_HANDLES) ; i++) { + if (tpm_key_handle_entries[i].key != NULL) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, tpm_key_handle_entries[i].handle); /* store it */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_DeleteHandle() removes a handle from the list. + + The TPM_KEY object must be _Delete'd and possibly free'd separately, because it might not be in + the table. +*/ + +TPM_RESULT TPM_KeyHandleEntries_DeleteHandle(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_DeleteHandle: %08x\n", tpm_key_handle); + /* search for the handle */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_KeyHandleEntries_DeleteHandle: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + /* delete the entry */ + if (rc == 0) { + TPM_KeyHandleEntry_Init(tpm_key_handle_entry); + } + return rc; +} + +/* TPM_KeyHandleEntries_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not. + + If TRUE, 'index' holds the first free position. +*/ + +void TPM_KeyHandleEntries_IsSpace(TPM_BOOL *isSpace, + uint32_t *index, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + printf(" TPM_KeyHandleEntries_IsSpace:\n"); + for (*index = 0, *isSpace = FALSE ; *index < TPM_KEY_HANDLES ; (*index)++) { + if (tpm_key_handle_entries[*index].key == NULL) { /* if the index is empty */ + printf(" TPM_KeyHandleEntries_IsSpace: Found space at %u\n", *index); + *isSpace = TRUE; + break; + } + } + return; +} + +/* TPM_KeyHandleEntries_GetSpace() returns the number of unused key handle entries. + +*/ + +void TPM_KeyHandleEntries_GetSpace(uint32_t *space, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + uint32_t i; + + printf(" TPM_KeyHandleEntries_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_KEY_HANDLES ; i++) { + if (tpm_key_handle_entries[i].key == NULL) { /* if the index is empty */ + (*space)++; + } + } + return; +} + +/* TPM_KeyHandleEntries_IsEvictSpace() returns 'isSpace' TRUE if there are at least 'minSpace' + entries that do not have the ownerEvict bit set, FALSE if not. +*/ + +void TPM_KeyHandleEntries_IsEvictSpace(TPM_BOOL *isSpace, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + uint32_t minSpace) +{ + uint32_t evictSpace; + uint32_t i; + + for (i = 0, evictSpace = 0 ; i < TPM_KEY_HANDLES ; i++) { + if (tpm_key_handle_entries[i].key == NULL) { /* if the index is empty */ + evictSpace++; + } + else { /* is index is used */ + if (!(tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + evictSpace++; /* space that can be evicted */ + } + } + } + printf(" TPM_KeyHandleEntries_IsEvictSpace: evictable space, minimum %u free %u\n", + minSpace, evictSpace); + if (evictSpace >= minSpace) { + *isSpace = TRUE; + } + else { + *isSpace = FALSE; + } + return; +} + +/* TPM_KeyHandleEntries_AddKeyEntry() adds a TPM_KEY object to the list. + + If *tpm_key_handle == 0, a value is assigned. If *tpm_key_handle != 0, + that value is used if it it not currently in use. + + The handle is returned in tpm_key_handle. +*/ + +TPM_RESULT TPM_KeyHandleEntries_AddKeyEntry(TPM_KEY_HANDLE *tpm_key_handle, /* i/o */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, /* in */ + TPM_KEY *tpm_key, + TPM_BOOL parentPCRStatus, + TPM_KEY_CONTROL keyControl) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_AddKeyEntry:\n"); + tpm_key_handle_entry.key = tpm_key; + tpm_key_handle_entry.parentPCRStatus = parentPCRStatus; + tpm_key_handle_entry.keyControl = keyControl; + rc = TPM_KeyHandleEntries_AddEntry(tpm_key_handle, + FALSE, /* don't have to keep handle */ + tpm_key_handle_entries, + &tpm_key_handle_entry); + return rc; +} + +/* TPM_KeyHandleEntries_AddEntry() adds (copies) the TPM_KEY_HANDLE_ENTRY object to the list. + + If *tpm_key_handle == 0: + a value is assigned. + + If *tpm_key_handle != 0: + + If keepHandle is TRUE, the handle must be used. An error is returned if the handle is + already in use. + + If keepHandle is FALSE, if the handle is already in use, a new value is assigned. + + The handle is returned in tpm_key_handle. +*/ + +TPM_RESULT TPM_KeyHandleEntries_AddEntry(TPM_KEY_HANDLE *tpm_key_handle, /* i/o */ + TPM_BOOL keepHandle, /* input */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, /* input */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) /* input */ + +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_KeyHandleEntries_AddEntry: handle %08x, keepHandle %u\n", + *tpm_key_handle, keepHandle); + /* check for valid TPM_KEY */ + if (rc == 0) { + if (tpm_key_handle_entry->key == NULL) { /* should never occur */ + printf("TPM_KeyHandleEntries_AddEntry: Error (fatal), NULL TPM_KEY\n"); + rc = TPM_FAIL; + } + } + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_KeyHandleEntries_IsSpace(&isSpace, &index, tpm_key_handle_entries); + if (!isSpace) { + printf("TPM_KeyHandleEntries_AddEntry: Error, key handle entries full\n"); + rc = TPM_NOSPACE; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(tpm_key_handle, /* I/O */ + tpm_key_handle_entries, /* handle array */ + keepHandle, + TRUE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_KeyHandleEntries_GetEntry); + } + if (rc == 0) { + tpm_key_handle_entries[index].handle = *tpm_key_handle; + tpm_key_handle_entries[index].key = tpm_key_handle_entry->key; + tpm_key_handle_entries[index].keyControl = tpm_key_handle_entry->keyControl; + tpm_key_handle_entries[index].parentPCRStatus = tpm_key_handle_entry->parentPCRStatus; + printf(" TPM_KeyHandleEntries_AddEntry: Index %u key handle %08x key pointer %p\n", + index, tpm_key_handle_entries[index].handle, tpm_key_handle_entries[index].key); + } + return rc; +} + +/* TPM_KeyHandleEntries_GetEntry() searches all entries for the entry matching the handle, and + returns that entry */ + +TPM_RESULT TPM_KeyHandleEntries_GetEntry(TPM_KEY_HANDLE_ENTRY **tpm_key_handle_entry, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_KeyHandleEntries_GetEntry: Get entry for handle %08x\n", tpm_key_handle); + for (i = 0, found = FALSE ; (i < TPM_KEY_HANDLES) && !found ; i++) { + /* first test for matching handle. Then check for non-NULL to insure that entry is valid */ + if ((tpm_key_handle_entries[i].handle == tpm_key_handle) && + tpm_key_handle_entries[i].key != NULL) { /* found */ + found = TRUE; + *tpm_key_handle_entry = &(tpm_key_handle_entries[i]); + } + } + if (!found) { + printf(" TPM_KeyHandleEntries_GetEntry: key handle %08x not found\n", tpm_key_handle); + rc = TPM_INVALID_KEYHANDLE; + } + else { + printf(" TPM_KeyHandleEntries_GetEntry: key handle %08x found\n", tpm_key_handle); + } + return rc; +} + +/* TPM_KeyHandleEntries_GetNextEntry() gets the next valid TPM_KEY_HANDLE_ENTRY at or after the + 'start' index. + + The current position is returned in 'current'. For iteration, the next 'start' should be + 'current' + 1. + + Returns + + 0 on success. + Returns TPM_RETRY when no more valid entries are found. + */ + +TPM_RESULT TPM_KeyHandleEntries_GetNextEntry(TPM_KEY_HANDLE_ENTRY **tpm_key_handle_entry, + size_t *current, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + size_t start) +{ + TPM_RESULT rc = TPM_RETRY; + + printf(" TPM_KeyHandleEntries_GetNextEntry: Start %lu\n", (unsigned long)start); + for (*current = start ; *current < TPM_KEY_HANDLES ; (*current)++) { + if (tpm_key_handle_entries[*current].key != NULL) { + *tpm_key_handle_entry = &(tpm_key_handle_entries[*current]); + rc = 0; /* found an entry */ + break; + } + } + return rc; +} + +/* TPM_KeyHandleEntries_GetKey() gets the TPM_KEY associated with the handle. + + If the key has PCR usage (size is non-zero and one or more mask bits are set), PCR's have been + specified. It computes a PCR digest based on the TPM PCR's and verifies it against the key + digestAtRelease. + + Exceptions: readOnly is TRUE when the caller is indicating that only the public key is being read + (e.g. TPM_GetPubKey). In this case, if keyFlags TPM_PCRIGNOREDONREAD is also TRUE, the PCR + digest and locality must not be checked. + + If ignorePCRs is TRUE, the PCR digest is also ignored. A typical case is during OSAP and DSAP + session setup. + */ + +TPM_RESULT TPM_KeyHandleEntries_GetKey(TPM_KEY **tpm_key, + TPM_BOOL *parentPCRStatus, + tpm_state_t *tpm_state, + TPM_KEY_HANDLE tpm_key_handle, + TPM_BOOL readOnly, + TPM_BOOL ignorePCRs, + TPM_BOOL allowEK) +{ + TPM_RESULT rc = 0; + TPM_BOOL found = FALSE; /* found a special handle key */ + TPM_BOOL validatePcrs = TRUE; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_GetKey: For handle %08x\n", tpm_key_handle); + /* If it's one of the special handles, return the TPM_KEY */ + if (rc == 0) { + switch (tpm_key_handle) { + case TPM_KH_SRK: /* The handle points to the SRK */ + if (tpm_state->tpm_permanent_data.ownerInstalled) { + *tpm_key = &(tpm_state->tpm_permanent_data.srk); + *parentPCRStatus = FALSE; /* storage root key (SRK) has no parent */ + found = TRUE; + } + else { + printf(" TPM_KeyHandleEntries_GetKey: Error, SRK handle with no owner\n"); + rc = TPM_KEYNOTFOUND; + } + break; + case TPM_KH_EK: /* The handle points to the PUBEK, only usable with + TPM_OwnerReadInternalPub */ + if (rc == 0) { + if (!allowEK) { + printf(" TPM_KeyHandleEntries_GetKey: Error, EK handle not allowed\n"); + rc = TPM_KEYNOTFOUND; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_data.endorsementKey.keyUsage == + TPM_KEY_UNINITIALIZED) { + printf(" TPM_KeyHandleEntries_GetKey: Error, EK handle but no EK\n"); + rc = TPM_KEYNOTFOUND; + } + } + if (rc == 0) { + *tpm_key = &(tpm_state->tpm_permanent_data.endorsementKey); + *parentPCRStatus = FALSE; /* endorsement key (EK) has no parent */ + found = TRUE; + } + break; + case TPM_KH_OWNER: /* handle points to the TPM Owner */ + case TPM_KH_REVOKE: /* handle points to the RevokeTrust value */ + case TPM_KH_TRANSPORT: /* handle points to the EstablishTransport static authorization */ + case TPM_KH_OPERATOR: /* handle points to the Operator auth */ + case TPM_KH_ADMIN: /* handle points to the delegation administration auth */ + printf("TPM_KeyHandleEntries_GetKey: Error, Unsupported key handle %08x\n", + tpm_key_handle); + rc = TPM_INVALID_RESOURCE; + break; + default: + /* continue searching */ + break; + } + } + /* If not one of the special key handles, search for the handle in the list */ + if ((rc == 0) && !found) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_KeyHandleEntries_GetKey: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + /* Part 1 25.1 Validate Key for use + 2. Set LK to the loaded key that is being used */ + /* NOTE: For special handle keys, this was already done. Just do here for keys in table */ + if ((rc == 0) && !found) { + *tpm_key = tpm_key_handle_entry->key; + *parentPCRStatus = tpm_key_handle_entry->parentPCRStatus; + } + /* 3. If LK -> pcrInfoSize is not 0 - if the key specifies PCR's */ + /* NOTE Done by TPM_Key_CheckPCRDigest() */ + /* a. If LK -> pcrInfo -> releasePCRSelection identifies the use of one or more PCR */ + if (rc == 0) { +#ifdef TPM_V12 + validatePcrs = !ignorePCRs && + !(readOnly && ((*tpm_key)->keyFlags & TPM_PCRIGNOREDONREAD)); +#else + validatePcrs = !ignorePCRs && !readOnly; +#endif + } + if ((rc == 0) && validatePcrs) { + if (rc == 0) { + rc = TPM_Key_CheckPCRDigest(*tpm_key, tpm_state); + } + } + return rc; +} + +/* TPM_KeyHandleEntries_SetParentPCRStatus() updates the parentPCRStatus member of the + TPM_KEY_HANDLE_ENTRY */ + +TPM_RESULT TPM_KeyHandleEntries_SetParentPCRStatus(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle, + TPM_BOOL parentPCRStatus) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + printf(" TPM_KeyHandleEntries_SetParentPCRStatus: Handle %08x\n", tpm_key_handle); + /* get the entry for the handle from the table */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_KeyHandleEntries_SetParentPCRStatus: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + if (rc == 0) { + tpm_key_handle_entry->parentPCRStatus = parentPCRStatus; + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictLoad() loads all owner evict keys from the stream into the key + handle entries table. +*/ + +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictLoad(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint16_t keyCount; + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; /* each entry as read from the stream */ + TPM_TAG ownerEvictVersion; + + printf(" TPM_KeyHandleEntries_OwnerEvictLoad:\n"); + /* get the owner evict version number */ + if (rc == 0) { + rc = TPM_Load16(&ownerEvictVersion, stream, stream_size); + } + if (rc == 0) { + if (ownerEvictVersion != TPM_TAG_NVSTATE_OE_V1) { + printf("TPM_KeyHandleEntries_OwnerEvictLoad: " + "Error (fatal) unsupported version tag %04x\n", + ownerEvictVersion); + rc = TPM_FAIL; + } + } + /* get the count of owner evict keys in the stream */ + if (rc == 0) { + rc = TPM_Load16(&keyCount, stream, stream_size); + } + /* sanity check that keyCount not greater than key slots */ + if (rc == 0) { + if (keyCount > TPM_OWNER_EVICT_KEY_HANDLES) { + printf("TPM_KeyHandleEntries_OwnerEvictLoad: Error (fatal)" + " key handles in stream %u greater than %d\n", + keyCount, TPM_OWNER_EVICT_KEY_HANDLES); + rc = TPM_FAIL; + } + } + if (rc == 0) { + printf(" TPM_KeyHandleEntries_OwnerEvictLoad: Count %hu\n", keyCount); + } + for (i = 0 ; (rc == 0) && (i < keyCount) ; i++) { + /* Must init each time through. This just resets the structure members. It does not free + the key that is in the structure after the first time through. That key has been added + (copied) to the key handle entries array. */ + printf(" TPM_KeyHandleEntries_OwnerEvictLoad: Loading key %hu\n", i); + TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* freed @2 on error */ + if (rc == 0) { + rc = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, stream, stream_size); + } + /* add the entry to the list */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_AddEntry(&(tpm_key_handle_entry.handle), /* suggested */ + TRUE, /* keep handle */ + tpm_key_handle_entries, + &tpm_key_handle_entry); + } + /* if there was an error copying the entry to the array, the entry must be delete'd to + prevent a memory leak, since a key has been loaded to the entry */ + if (rc != 0) { + TPM_KeyHandleEntry_Delete(&tpm_key_handle_entry); /* @2 on error */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictStore() stores all owner evict keys from the key handle entries + table to the stream. + + It is used to serialize to NVRAM. +*/ + +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictStore(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + TPM_RESULT rc = 0; + uint16_t count; + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + + printf(" TPM_KeyHandleEntries_OwnerEvictStore:\n"); + /* append the owner evict version number to the stream */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_OE_V1); + } + /* count the number of owner evict keys */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_OwnerEvictGetCount(&count, tpm_key_handle_entries); + } + /* append the count to the stream */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, count); + } + for (i = 0 ; (rc == 0) && (i < TPM_KEY_HANDLES) ; i++) { + /* if the slot is occupied */ + if (tpm_key_handle_entries[i].key != NULL) { + /* if the key is owner evict */ + if ((tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + /* store it */ + rc = TPM_KeyHandleEntry_Store(sbuffer, &(tpm_key_handle_entries[i])); + } + } + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictGetCount returns the number of owner evict key entries + */ + +TPM_RESULT +TPM_KeyHandleEntries_OwnerEvictGetCount(uint16_t *count, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + TPM_RESULT rc = 0; + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + + printf(" TPM_KeyHandleEntries_OwnerEvictGetCount:\n"); + /* count the number of loaded owner evict handles */ + if (rc == 0) { + for (i = 0 , *count = 0 ; i < TPM_KEY_HANDLES ; i++) { + /* if the slot is occupied */ + if (tpm_key_handle_entries[i].key != NULL) { + /* if the key is owner evict */ + if ((tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + (*count)++; /* count it */ + } + } + } + printf(" TPM_KeyHandleEntries_OwnerEvictGetCount: Count %hu\n", *count); + } + /* sanity check */ + if (rc == 0) { + if (*count > TPM_OWNER_EVICT_KEY_HANDLES) { + printf("TPM_KeyHandleEntries_OwnerEvictGetCount: Error (fatal), " + "count greater that max %u\n", TPM_OWNER_EVICT_KEY_HANDLES); + rc = TPM_FAIL; /* should never occur */ + } + } + return rc; +} + +/* TPM_KeyHandleEntries_OwnerEvictDelete() flushes owner evict keys. It does NOT write to NV. + +*/ + +void TPM_KeyHandleEntries_OwnerEvictDelete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + uint16_t i; /* the uint16_t corresponds to the standard getcap */ + + for (i = 0 ; i < TPM_KEY_HANDLES ; i++) { + /* if the slot is occupied */ + if (tpm_key_handle_entries[i].key != NULL) { + /* if the key is owner evict */ + if ((tpm_key_handle_entries[i].keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + TPM_KeyHandleEntry_Delete(&(tpm_key_handle_entries[i])); + } + } + } + return; +} + +/* + Processing Functions +*/ + +/* 14.4 TPM_ReadPubek rev 99 + + Return the endorsement key public portion. This value should have controls placed upon access as + it is a privacy sensitive value + + The readPubek flag is set to FALSE by TPM_TakeOwnership and set to TRUE by TPM_OwnerClear, thus + mirroring if a TPM Owner is present. +*/ + +TPM_RESULT TPM_Process_ReadPubek(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NONCE antiReplay; + + /* processing */ + const unsigned char *pubEndorsementKeyStreamBuffer; + uint32_t pubEndorsementKeyStreamLength; + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER pubEndorsementKeyStream; + TPM_DIGEST checksum; + + printf("TPM_Process_ReadPubek: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubEndorsementKeyStream); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour(" TPM_Process_ReadPubek: antiReplay", antiReplay); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReadPubek: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If TPM_PERMANENT_FLAGS -> readPubek is FALSE return TPM_DISABLED_CMD. */ + if (returnCode == TPM_SUCCESS) { + printf(" TPM_Process_ReadPubek: readPubek %02x\n", + tpm_state->tpm_permanent_flags.readPubek); + if (!tpm_state->tpm_permanent_flags.readPubek) { + printf("TPM_Process_ReadPubek: Error, readPubek is FALSE\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* 2. If no EK is present the TPM MUST return TPM_NO_ENDORSEMENT */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_permanent_data.endorsementKey.keyUsage == TPM_KEY_UNINITIALIZED) { + printf("TPM_Process_ReadPubek: Error, no EK is present\n"); + returnCode = TPM_NO_ENDORSEMENT; + } + } + /* 3. Create checksum by performing SHA-1 on the concatenation of (pubEndorsementKey || + antiReplay). */ + if (returnCode == TPM_SUCCESS) { + /* serialize the TPM_PUBKEY components of the EK */ + returnCode = + TPM_Key_StorePubkey(&pubEndorsementKeyStream, /* output */ + &pubEndorsementKeyStreamBuffer, /* output */ + &pubEndorsementKeyStreamLength, /* output */ + &(tpm_state->tpm_permanent_data.endorsementKey)); /* input */ + } + if (returnCode == TPM_SUCCESS) { + printf(" TPM_Process_ReadPubek: pubEndorsementKey length %u\n", + pubEndorsementKeyStreamLength); + /* create the checksum */ + returnCode = TPM_SHA1(checksum, +#if 0 /* The old Atmel chip and the LTC test code assume this, but it is incorrect */ + tpm_state->tpm_permanent_data.endorsementKey.pubKey.keyLength, + tpm_state->tpm_permanent_data.endorsementKey.pubKey.key, +#else /* this meets the TPM 1.2 standard */ + pubEndorsementKeyStreamLength, pubEndorsementKeyStreamBuffer, +#endif + sizeof(TPM_NONCE), antiReplay, + 0, NULL); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReadPubek: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + /* 4. Export the PUBEK and checksum. */ + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append pubEndorsementKey */ + returnCode = TPM_Sbuffer_Append(response, + pubEndorsementKeyStreamBuffer, + pubEndorsementKeyStreamLength); + } + /* append checksum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, checksum); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubEndorsementKeyStream); /* @1 */ + return rcf; +} + +/* 14.2 TPM_CreateRevocableEK rev 98 + + This command creates the TPM endorsement key. It returns a failure code if an endorsement key + already exists. The TPM vendor may have a separate mechanism to create the EK and "squirt" the + value into the TPM. +*/ + +TPM_RESULT TPM_Process_CreateRevocableEK(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NONCE antiReplay; /* Arbitrary data */ + TPM_KEY_PARMS keyInfo; /* Information about key to be created, this includes all + algorithm parameters */ + TPM_BOOL generateReset = FALSE; /* If TRUE use TPM RNG to generate EKreset. If FALSE + use the passed value inputEKreset */ + TPM_NONCE inputEKreset; /* The authorization value to be used with TPM_RevokeTrust + if generateReset==FALSE, else the parameter is present + but unused */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_KEY *endorsementKey; /* EK object from permanent store */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back NV */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PUBKEY pubEndorsementKey; /* The public endorsement key */ + TPM_DIGEST checksum; /* Hash of pubEndorsementKey and antiReplay */ + + printf("TPM_Process_CreateRevocableEK: Ordinal Entry\n"); + /* get pointers */ + endorsementKey = &(tpm_state->tpm_permanent_data.endorsementKey); + /* so that Delete's are safe */ + TPM_KeyParms_Init(&keyInfo); /* freed @1 */ + TPM_Pubkey_Init(&pubEndorsementKey); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get keyInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_Load(&keyInfo, &command, ¶mSize); /* freed @1 */ + } + /* get generateReset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&generateReset, &command, ¶mSize); + } + /* get inputEKreset parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateRevocableEK: generateReset %02x\n", generateReset); + /* an email clarification says that this parameter is still present (but ignored) if + generateReset is TRUE */ + returnCode = TPM_Nonce_Load(inputEKreset, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateRevocableEK: inputEKreset", inputEKreset); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateRevocableEK: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. If an EK already exists, return TPM_DISABLED_CMD */ + /* 2. Perform the actions of TPM_CreateEndorsementKeyPair, if any errors return with error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CreateEndorsementKeyPair_Common(endorsementKey, + &pubEndorsementKey, + checksum, + &writeAllNV1, + tpm_state, + &keyInfo, + antiReplay); + } + if (returnCode == TPM_SUCCESS) { + /* 3. Set TPM_PERMANENT_FLAGS -> enableRevokeEK to TRUE */ + TPM_SetCapability_Flag(&writeAllNV1, /* altered */ + &(tpm_state->tpm_permanent_flags.enableRevokeEK), /* flag */ + TRUE); /* value */ + /* a. If generateReset is TRUE then */ + if (generateReset) { + /* i. Set TPM_PERMANENT_DATA -> EKreset to the next value from the TPM RNG */ + returnCode = TPM_Nonce_Generate(tpm_state->tpm_permanent_data.EKReset); + } + /* b. Else */ + else { + /* i. Set TPM_PERMANENT_DATA -> EKreset to inputEkreset */ + TPM_Nonce_Copy(tpm_state->tpm_permanent_data.EKReset, inputEKreset); + } + } + /* save the permanent data and flags structure sto NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + (TPM_BOOL)(writeAllNV1 || writeAllNV2), + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateRevocableEK: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 4. Return PUBEK, checksum and Ekreset */ + /* append pubEndorsementKey. */ + returnCode = TPM_Pubkey_Store(response, &pubEndorsementKey); + } + /* append checksum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, checksum); + } + /* append outputEKreset */ + /* 5. The outputEKreset authorization is sent in the clear. There is no uniqueness on the + TPM available to actually perform encryption or use an encrypted channel. The assumption + is that this operation is occurring in a controlled environment and sending the value in + the clear is acceptable. + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, tpm_state->tpm_permanent_data.EKReset); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_KeyParms_Delete(&keyInfo); /* @1 */ + TPM_Pubkey_Delete(&pubEndorsementKey); /* @2 */ + return rcf; +} + +/* 14.1 TPM_CreateEndorsementKeyPair rev 104 + + This command creates the TPM endorsement key. It returns a failure code if an endorsement key + already exists. +*/ + +TPM_RESULT TPM_Process_CreateEndorsementKeyPair(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NONCE antiReplay; /* Arbitrary data */ + TPM_KEY_PARMS keyInfo; /* Information about key to be created, this includes all + algorithm parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport session */ + TPM_KEY *endorsementKey = FALSE; /* EK object from permanent store */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back data */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PUBKEY pubEndorsementKey; /* The public endorsement key */ + TPM_DIGEST checksum; /* Hash of pubEndorsementKey and antiReplay */ + + printf("TPM_Process_CreateEndorsementKeyPair: Ordinal Entry\n"); + /* get pointers */ + endorsementKey = &(tpm_state->tpm_permanent_data.endorsementKey); + /* so that Delete's are safe */ + TPM_KeyParms_Init(&keyInfo); /* freed @1 */ + TPM_Pubkey_Init(&pubEndorsementKey); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get keyInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_Load(&keyInfo, &command, ¶mSize); /* freed @1 */ + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateEndorsementKeyPair: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CreateEndorsementKeyPair_Common(endorsementKey, + &pubEndorsementKey, + checksum, + &writeAllNV1, + tpm_state, + &keyInfo, + antiReplay); + } + /* 10. Set TPM_PERMANENT_FLAGS -> enableRevokeEK to FALSE */ + if (returnCode == TPM_SUCCESS) { + TPM_SetCapability_Flag(&writeAllNV2, /* altered */ + &(tpm_state->tpm_permanent_flags.enableRevokeEK), /* flag */ + FALSE); /* value */ + } + /* save the permanent data and flags structures to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + (TPM_BOOL)(writeAllNV1 || writeAllNV2), + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateEndorsementKeyPair: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + /* append pubEndorsementKey. */ + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + returnCode = TPM_Pubkey_Store(response, &pubEndorsementKey); + } + /* append checksum */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Store(response, checksum); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_KeyParms_Delete(&keyInfo); /* @1 */ + TPM_Pubkey_Delete(&pubEndorsementKey); /* @2 */ + return rcf; +} + +/* TPM_CreateEndorsementKeyPair_Common rev 104 + + Actions common to TPM_CreateEndorsementKeyPair and TPM_CreateRevocableEK + + 'endorsementKey' points to TPM_PERMANENT_DATA -> endorsementKey +*/ + +TPM_RESULT TPM_CreateEndorsementKeyPair_Common(TPM_KEY *endorsementKey, /* output */ + TPM_PUBKEY *pubEndorsementKey, /* output */ + TPM_DIGEST checksum, /* output */ + TPM_BOOL *writePermanentData, /* output */ + tpm_state_t *tpm_state, /* input */ + TPM_KEY_PARMS *keyInfo, /* input */ + TPM_NONCE antiReplay) /* input */ +{ + TPM_RESULT returnCode = TPM_SUCCESS; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; /* from keyInfo */ + TPM_STORE_BUFFER pubEndorsementKeySerial; /* serialization for checksum calculation */ + const unsigned char *pubEndorsementKeyBuffer; + uint32_t pubEndorsementKeyLength; + + printf("TPM_CreateEndorsementKeyPair_Common:\n"); + TPM_Sbuffer_Init(&pubEndorsementKeySerial); /* freed @1 */ + /* 1. If an EK already exists, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + if (endorsementKey->keyUsage != TPM_KEY_UNINITIALIZED) { + printf("TPM_CreateEndorsementKeyPair_Common: Error, key already initialized\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* 2. Validate the keyInfo parameters for the key description */ + if (returnCode == TPM_SUCCESS) { + /* + RSA + */ + /* a. If the algorithm type is RSA the key length MUST be a minimum of + 2048. For interoperability the key length SHOULD be 2048 */ + if (keyInfo->algorithmID == TPM_ALG_RSA) { + if (returnCode == TPM_SUCCESS) { + /* get the keyInfo TPM_RSA_KEY_PARMS structure */ + returnCode = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, + keyInfo); + } + if (returnCode == TPM_SUCCESS) { + if (tpm_rsa_key_parms->keyLength != TPM_KEY_RSA_NUMBITS) { /* in bits */ + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "Bad keyLength should be %u, was %u\n", + TPM_KEY_RSA_NUMBITS, tpm_rsa_key_parms->keyLength); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* kgold - Support only 2 primes */ + if (returnCode == TPM_SUCCESS) { + if (tpm_rsa_key_parms->numPrimes != 2) { + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "Bad numPrimes should be 2, was %u\n", + tpm_rsa_key_parms->numPrimes); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + } + /* + not RSA + */ + /* b. If the algorithm type is other than RSA the strength provided by + the key MUST be comparable to RSA 2048 */ + else { + if (returnCode == TPM_SUCCESS) { + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "algorithmID %08x not supported\n", + keyInfo->algorithmID); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + } + /* c. The other parameters of keyInfo (encScheme, sigScheme, etc.) are ignored. + */ + /* 3. Create a key pair called the "endorsement key pair" using a TPM-protected capability. The + type and size of key are that indicated by keyInfo. Set encScheme to + TPM_ES_RSAESOAEP_SHA1_MGF1. + + Save the endorsement key in permanent structure. Save the endorsement private key 'd' in the + TPM_KEY structure as encData */ + /* Certain HW TPMs do not ignore the encScheme parameter, and expect it to be + TPM_ES_RSAESOAEP_SHA1_MGF1. Test the value here to detect an application program that will + fail with that TPM. */ + + if (returnCode == TPM_SUCCESS) { + if (keyInfo->encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + returnCode = TPM_BAD_KEY_PROPERTY; + printf("TPM_CreateEndorsementKeyPair_Common: Error, " + "encScheme %08x must be TPM_ES_RSAESOAEP_SHA1_MGF1\n", + keyInfo->encScheme); + } + } + if (returnCode == TPM_SUCCESS) { + keyInfo->sigScheme = TPM_ES_NONE; + returnCode = TPM_Key_GenerateRSA(endorsementKey, + tpm_state, + NULL, /* parent key, indicate root key */ + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + 1, /* TPM_KEY */ + TPM_KEY_STORAGE, /* keyUsage */ + 0, /* keyFlags */ + TPM_AUTH_ALWAYS, /* authDataUsage */ + keyInfo, + NULL, /* no PCR's */ + NULL); /* no PCR's */ + *writePermanentData = TRUE; + } + /* Assemble the TPM_PUBKEY pubEndorsementKey for the response */ + if (returnCode == TPM_SUCCESS) { + /* add TPM_KEY_PARMS algorithmParms */ + returnCode = TPM_KeyParms_Copy(&(pubEndorsementKey->algorithmParms), + keyInfo); + } + if (returnCode == TPM_SUCCESS) { + /* add TPM_SIZED_BUFFER pubKey */ + returnCode = TPM_SizedBuffer_Set(&(pubEndorsementKey->pubKey), + endorsementKey->pubKey.size, + endorsementKey->pubKey.buffer); + } + /* 4. Create checksum by performing SHA-1 on the concatenation of (PUBEK + || antiReplay) */ + if (returnCode == TPM_SUCCESS) { + /* serialize the pubEndorsementKey */ + returnCode = TPM_Pubkey_Store(&pubEndorsementKeySerial, + pubEndorsementKey); + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_Get(&pubEndorsementKeySerial, + &pubEndorsementKeyBuffer, &pubEndorsementKeyLength); + /* create the checksum */ + returnCode = TPM_SHA1(checksum, + pubEndorsementKeyLength, pubEndorsementKeyBuffer, + sizeof(TPM_NONCE), antiReplay, + 0, NULL); + } + /* 5. Store the PRIVEK */ + /* NOTE Created in TPM_PERMANENT_DATA, call should save to NVRAM */ + /* 6. Create TPM_PERMANENT_DATA -> tpmDAASeed from the TPM RNG */ + /* 7. Create TPM_PERMANENT_DATA -> daaProof from the TPM RNG */ + /* 8. Create TPM_PERMANENT_DATA -> daaBlobKey from the TPM RNG */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentData_InitDaa(&(tpm_state->tpm_permanent_data)); + } + /* 9. Set TPM_PERMANENT_FLAGS -> CEKPUsed to TRUE */ + if (returnCode == TPM_SUCCESS) { + tpm_state->tpm_permanent_flags.CEKPUsed = TRUE; + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubEndorsementKeySerial); /* @1 */ + return returnCode; +} + +/* 14.3 TPM_RevokeTrust rev 98 + + This command clears the EK and sets the TPM back to a pure default state. The generation of the + AuthData value occurs during the generation of the EK. It is the responsibility of the EK + generator to properly protect and disseminate the RevokeTrust AuthData. +*/ + +TPM_RESULT TPM_Process_RevokeTrust(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NONCE EKReset; /* The value that will be matched to EK Reset */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back data */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back flags */ + TPM_BOOL writeAllNV3 = FALSE; /* flags to write back flags */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_RevokeTrust: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get EKReset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(EKReset, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour(" TPM_Process_RevokeTrust: EKReset", EKReset); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_RevokeTrust: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM MUST validate that TPM_PERMANENT_FLAGS -> enableRevokeEK is TRUE, return + TPM_PERMANENTEK on error */ + if (returnCode == TPM_SUCCESS) { + if (!tpm_state->tpm_permanent_flags.enableRevokeEK) { + printf("TPM_Process_RevokeTrust: Error, enableRevokeEK is FALSE\n"); + returnCode = TPM_PERMANENTEK; + } + } + /* 2. The TPM MUST validate that the EKReset matches TPM_PERMANENT_DATA -> EKReset, return + TPM_AUTHFAIL on error. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Compare(tpm_state->tpm_permanent_data.EKReset, EKReset); + if (returnCode != 0) { + printf("TPM_Process_RevokeTrust: Error, EKReset mismatch\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 3. Ensure that physical presence is being asserted */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_RevokeTrust: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 4. Perform the actions of TPM_OwnerClear (excepting the command authentication) */ + /* a. NV items with the pubInfo -> nvIndex D value set MUST be deleted. This changes the + TPM_OwnerClear handling of the same NV areas */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OwnerClearCommon(tpm_state, + TRUE); /* delete all NVRAM */ + writeAllNV1 = TRUE; + } + if (returnCode == TPM_SUCCESS) { + /* b. Set TPM_PERMANENT_FLAGS -> nvLocked to FALSE */ + TPM_SetCapability_Flag(&writeAllNV2, /* altered (dummy) */ + &(tpm_state->tpm_permanent_flags.nvLocked), /* flag */ + FALSE); /* value */ + /* 5. Invalidate TPM_PERMANENT_DATA -> tpmDAASeed */ + /* 6. Invalidate TPM_PERMANENT_DATA -> daaProof */ + /* 7. Invalidate TPM_PERMANENT_DATA -> daaBlobKey */ + returnCode = TPM_PermanentData_InitDaa(&(tpm_state->tpm_permanent_data)); + } + if (returnCode == TPM_SUCCESS) { + /* 8. Invalidate the EK and any internal state associated with the EK */ + printf("TPM_Process_RevokeTrust: Deleting endorsement key\n"); + TPM_Key_Delete(&(tpm_state->tpm_permanent_data.endorsementKey)); + TPM_SetCapability_Flag(&writeAllNV3, /* altered (dummy) */ + &(tpm_state->tpm_permanent_flags.CEKPUsed), /* flag */ + FALSE); /* value */ + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV1, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_RevokeTrust: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 27.7 TPM_DisablePubekRead rev 94 + + 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. + + This commands has in essence been deprecated as TPM_TakeOwnership now sets the value to false. + The commands remains at this time for backward compatibility. +*/ + +TPM_RESULT TPM_Process_DisablePubekRead(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: ownerAuth. */ + + /* processing */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DisablePubekRead: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DisablePubekRead: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* Verify that the TPM Owner authorizes the command and all of the input, on error return + TPM_AUTHFAIL. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 1. This capability sets the TPM_PERMANENT_FLAGS -> readPubek flag to FALSE. */ + if (returnCode == TPM_SUCCESS) { + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.readPubek), /* flag */ + FALSE); /* value */ + printf("TPM_Process_DisablePubekRead: readPubek now %02x\n", + tpm_state->tpm_permanent_flags.readPubek); + /* save the permanent flags structure to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DisablePubekRead: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + /* no outParam's, set authorization response data */ + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + return rcf; +} + +/* 27.6 TPM_OwnerReadPubek rev 94 + + Return the endorsement key public portion. This is authorized by the TPM Owner. +*/ + +TPM_RESULT TPM_Process_OwnerReadPubek(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + const unsigned char *pubEndorsementKeyStreamBuffer; + uint32_t pubEndorsementKeyStreamLength; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORE_BUFFER pubEndorsementKeyStream; /* The public endorsement key */ + + printf("TPM_Process_OwnerReadPubek: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubEndorsementKeyStream); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OwnerReadPubek: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the TPM Owner authorization to execute this command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* serialize the TPM_PUBKEY components of the EK */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Key_StorePubkey(&pubEndorsementKeyStream, /* output */ + &pubEndorsementKeyStreamBuffer, /* output */ + &pubEndorsementKeyStreamLength, /* output */ + &(tpm_state->tpm_permanent_data.endorsementKey)); /* input */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OwnerReadPubek: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 2. Export the PUBEK */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, + pubEndorsementKeyStreamBuffer, + pubEndorsementKeyStreamLength); + } + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + /* no outParam's, set authorization response data */ + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubEndorsementKeyStream); /* @1 */ + return rcf; +} + +/* 27.1.1 TPM_EvictKey rev 87 + + 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. + + The TPM will invalidate the key stored in the specified handle and return the space to the + available internal pool for subsequent query by TPM_GetCapability and usage by TPM_LoadKey. If + the specified key handle does not correspond to a valid key, an error will be returned. +*/ + +TPM_RESULT TPM_Process_EvictKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters*/ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE evictHandle; /* The handle of the key to be evicted. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* table entry for the evictHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_EvictKey: Ordinal Entry\n"); + /* + get inputs + */ + /* get evictHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&evictHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_EvictKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* New 1.2 functionality + The command must check the status of the ownerEvict flag for the key and if the flag is TRUE + return TPM_KEY_CONTROL_OWNER + */ + /* evict the key stored in the specified handle */ + /* get the TPM_KEY_HANDLE_ENTRY */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EvictKey: Evicting handle %08x\n", evictHandle); + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + evictHandle); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_EvictKey: Error, key handle %08x not found\n", + evictHandle); + } + } + /* If tpm_key_handle_entry -> ownerEvict is TRUE return TPM_KEY_OWNER_CONTROL */ + if (returnCode == TPM_SUCCESS) { + if (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) { + printf("TPM_Process_EvictKey: Error, keyHandle specifies owner evict\n"); + returnCode = TPM_KEY_OWNER_CONTROL; + } + } + /* delete the entry, delete the key structure, and free the key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntry_FlushSpecific(tpm_state, tpm_key_handle_entry); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_EvictKey: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 14.5 TPM_OwnerReadInternalPub rev 87 + + A TPM Owner authorized command that returns the public portion of the EK or SRK. + + The keyHandle parameter is included in the incoming session authorization to prevent + alteration of the value, causing a different key to be read. Unlike most key handles, which + can be mapped by higher layer software, this key handle has only two fixed values. + +*/ + +TPM_RESULT TPM_Process_OwnerReadInternalPub(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* of remaining parameters */ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle for either PUBEK or SRK */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *readKey = NULL; /* key to be read back */ + const unsigned char *stream; + uint32_t stream_size; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_OwnerReadInternalPub: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + /* NOTE: This is a special case, where the keyHandle is part of the HMAC calculation to + avoid a man-in-the-middle privacy attack that replaces the SRK handle with the EK + handle. */ + inParamStart = command; + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OwnerReadInternalPub: keyHandle %08x\n", keyHandle); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OwnerReadInternalPub: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the parameters and TPM Owner AuthData for this command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + /* 2. If keyHandle is TPM_KH_EK */ + if (keyHandle == TPM_KH_EK) { + /* a. Set publicPortion to PUBEK */ + printf("TPM_Process_OwnerReadInternalPub: Reading EK\n"); + readKey = &(tpm_state->tpm_permanent_data.endorsementKey); + } + /* 3. Else If keyHandle is TPM_KH_SRK */ + else if (keyHandle == TPM_KH_SRK) { + /* a. Set publicPortion to the TPM_PUBKEY of the SRK */ + printf("TPM_Process_OwnerReadInternalPub: Reading SRK\n"); + readKey = &(tpm_state->tpm_permanent_data.srk); + } + /* 4. Else return TPM_BAD_PARAMETER */ + else { + printf("TPM_Process_OwnerReadInternalPub: Error, invalid keyHandle %08x\n", + keyHandle); + returnCode = TPM_BAD_PARAMETER; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OwnerReadInternalPub: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 5. Export the public key of the referenced key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_StorePubkey(response, &stream, &stream_size, readKey); + } + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + /* no outParam's, set authorization response data */ + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + + diff --git a/src/tpm_key.h b/src/tpm_key.h new file mode 100644 index 00000000..d0418d78 --- /dev/null +++ b/src/tpm_key.h @@ -0,0 +1,455 @@ +/********************************************************************************/ +/* */ +/* Key Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_key.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_KEY_H +#define TPM_KEY_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_structures.h" + +#define TPM_KEY_RSA_NUMBITS 2048 + +extern unsigned char tpm_default_rsa_exponent[]; + +/* TPM_KEY */ + +void TPM_Key_Init(TPM_KEY *tpm_key); +void TPM_Key_InitTag12(TPM_KEY *tpm_key); + +TPM_RESULT TPM_Key_Load(TPM_KEY *tpm_key, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Key_LoadPubData(TPM_KEY *tpm_key, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Key_LoadClear(TPM_KEY *tpm_key, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Key_Store(TPM_STORE_BUFFER *sbuffer, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_StorePubData(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_StoreClear(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + TPM_KEY *tpm_key); + +void TPM_Key_Delete(TPM_KEY *tpm_key); + +TPM_RESULT TPM_Key_CheckStruct(int *ver, TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_Set(TPM_KEY *tpm_key, + tpm_state_t *tpm_state, + TPM_KEY *parent_key, + TPM_DIGEST *tpm_pcrs, + int ver, + TPM_KEY_USAGE keyUsage, + TPM_KEY_FLAGS keyFlags, + TPM_AUTH_DATA_USAGE authDataUsage, + TPM_KEY_PARMS *tpm_key_parms, + TPM_PCR_INFO *tpm_pcr_info, + TPM_PCR_INFO_LONG *tpm_pcr_info_long, + uint32_t keyLength, + BYTE* publicKey, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey); +TPM_RESULT TPM_Key_Copy(TPM_KEY *tpm_key_dest, + TPM_KEY *tpm_key_src, + TPM_BOOL copyEncData); +TPM_RESULT TPM_Key_LoadStoreAsymKey(TPM_KEY *tpm_key, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Key_StorePubkey(TPM_STORE_BUFFER *pubkeyStream, + const unsigned char **pubkKeyStreamBuffer, + uint32_t *pubkeyStreamLength, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GenerateRSA(TPM_KEY *tpm_key, + tpm_state_t *tpm_state, + TPM_KEY *parent_key, + TPM_DIGEST *tpm_pcrs, + int ver, + TPM_KEY_USAGE keyUsage, + TPM_KEY_FLAGS keyFlags, + TPM_AUTH_DATA_USAGE authDataUsage, + TPM_KEY_PARMS *tpm_key_parms, + TPM_PCR_INFO *tpm_pcr_info, + TPM_PCR_INFO_LONG *tpm_pcr_info_long); + +TPM_RESULT TPM_Key_GeneratePubDataDigest(TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GeneratePubkeyDigest(TPM_DIGEST tpm_digest, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_ComparePubkey(TPM_KEY *tpm_key, + TPM_PUBKEY *tpm_pubkey); + +TPM_RESULT TPM_Key_CheckPubDataDigest(TPM_KEY *tpm_key); + +TPM_RESULT TPM_Key_GenerateEncData(TPM_KEY *tpm_key, + TPM_KEY *parent_key); +TPM_RESULT TPM_Key_DecryptEncData(TPM_KEY *tpm_key, + TPM_KEY *parent_key); + +TPM_RESULT TPM_Key_GetStoreAsymkey(TPM_STORE_ASYMKEY **tpm_store_asymkey, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetMigrateAsymkey(TPM_MIGRATE_ASYMKEY **tpm_migrate_asymkey, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetUsageAuth(TPM_SECRET **usageAuth, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetPublicKey(uint32_t *nbytes, + unsigned char **narr, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetPrimeFactorP(uint32_t *pbytes, + unsigned char **parr, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetPrivateKey(uint32_t *dbytes, + unsigned char **darr, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_CheckProperties(int *ver, + TPM_KEY *tpm_key, + uint32_t keyLength, + TPM_BOOL FIPS); +TPM_RESULT TPM_Key_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_KEY *tpm_key, + size_t start_index); +TPM_RESULT TPM_Key_GetLocalityAtRelease(TPM_LOCALITY_SELECTION *localityAtRelease, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Key_CheckPCRDigest(TPM_KEY *tpm_key, + tpm_state_t *tpm_state); +TPM_RESULT TPM_Key_CheckRestrictDelegate(TPM_KEY *tpm_key, + TPM_CMK_DELEGATE restrictDelegate); + +/* + TPM_KEY_FLAGS +*/ + +TPM_RESULT TPM_KeyFlags_Load(TPM_KEY_FLAGS *tpm_key_flags, + unsigned char **stream, + uint32_t *stream_size); + +/* + TPM_KEY_PARMS +*/ + +void TPM_KeyParms_Init(TPM_KEY_PARMS *tpm_key_parms); +TPM_RESULT TPM_KeyParms_Set(TPM_KEY_PARMS *tpm_key_parms, + TPM_ALGORITHM_ID algorithmID, + TPM_ENC_SCHEME encScheme, + TPM_SIG_SCHEME sigScheme, + uint32_t parmSize, + BYTE* parms); +TPM_RESULT TPM_KeyParms_SetRSA(TPM_KEY_PARMS *tpm_key_parms, + TPM_ALGORITHM_ID algorithmID, + TPM_ENC_SCHEME encScheme, + TPM_SIG_SCHEME sigScheme, + uint32_t keyLength, + TPM_SIZED_BUFFER *exponent); +TPM_RESULT TPM_KeyParms_Copy(TPM_KEY_PARMS *tpm_key_parms_dest, + TPM_KEY_PARMS *tpm_key_parms_src); +TPM_RESULT TPM_KeyParms_Load(TPM_KEY_PARMS *tpm_key_parms, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_KeyParms_Store(TPM_STORE_BUFFER *sbuffer, + TPM_KEY_PARMS *tpm_key_parms); +void TPM_KeyParms_Delete(TPM_KEY_PARMS *tpm_key_parms); +TPM_RESULT TPM_KeyParms_GetRSAKeyParms(TPM_RSA_KEY_PARMS **tpm_rsa_key_parms, + TPM_KEY_PARMS *tpm_key_parms); +TPM_RESULT TPM_KeyParms_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_KEY_PARMS *tpm_key_parms); +TPM_RESULT TPM_KeyParms_CheckProperties(TPM_KEY_PARMS *tpm_key_parms, + TPM_KEY_USAGE tpm_key_usage, + uint32_t keyLength, + TPM_BOOL FIPS); +TPM_RESULT TPM_KeyParams_CheckDefaultExponent(TPM_SIZED_BUFFER *exponent); + +/* + TPM_PUBKEY +*/ + +void TPM_Pubkey_Init(TPM_PUBKEY *tpm_pubkey); +TPM_RESULT TPM_Pubkey_Load(TPM_PUBKEY *tpm_pubkey, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Pubkey_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PUBKEY *tpm_pubkey); +void TPM_Pubkey_Delete(TPM_PUBKEY *tpm_pubkey); + +TPM_RESULT TPM_Pubkey_Set(TPM_PUBKEY *tpm_pubkey, + TPM_KEY *tpm_key); +TPM_RESULT TPM_Pubkey_Copy(TPM_PUBKEY *dest_tpm_pubkey, + TPM_PUBKEY *src_tpm_pubkey); +TPM_RESULT TPM_Pubkey_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_PUBKEY *tpm_pubkey); +TPM_RESULT TPM_Pubkey_GetPublicKey(uint32_t *nbytes, + unsigned char **narr, + TPM_PUBKEY *tpm_pubkey); + +/* + TPM_KEY_HANDLE_ENTRY +*/ + +void TPM_KeyHandleEntry_Init(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); +TPM_RESULT TPM_KeyHandleEntry_Load(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_KeyHandleEntry_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); +void TPM_KeyHandleEntry_Delete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); + +TPM_RESULT TPM_KeyHandleEntry_FlushSpecific(tpm_state_t *tpm_state, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); + +/* + TPM_KEY_HANDLE_ENTRY entries list +*/ + +void TPM_KeyHandleEntries_Init(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); +void TPM_KeyHandleEntries_Delete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); + +TPM_RESULT TPM_KeyHandleEntries_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_KeyHandleEntries_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state); + +TPM_RESULT TPM_KeyHandleEntries_StoreHandles(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); +TPM_RESULT TPM_KeyHandleEntries_DeleteHandle(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle); + +void TPM_KeyHandleEntries_IsSpace(TPM_BOOL *isSpace, uint32_t *index, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); +void TPM_KeyHandleEntries_GetSpace(uint32_t *space, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); +void TPM_KeyHandleEntries_IsEvictSpace(TPM_BOOL *isSpace, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + uint32_t minSpace); +TPM_RESULT TPM_KeyHandleEntries_AddKeyEntry(TPM_KEY_HANDLE *tpm_key_handle, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY *tpm_key, + TPM_BOOL parentPCRStatus, + TPM_KEY_CONTROL keyControl); +TPM_RESULT TPM_KeyHandleEntries_AddEntry(TPM_KEY_HANDLE *tpm_key_handle, + TPM_BOOL keepHandle, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); +TPM_RESULT TPM_KeyHandleEntries_GetEntry(TPM_KEY_HANDLE_ENTRY **tpm_key_handle_entry, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle); +TPM_RESULT TPM_KeyHandleEntries_GetKey(TPM_KEY **tpm_key, + TPM_BOOL *parentPCRStatus, + tpm_state_t *tpm_state, + TPM_KEY_HANDLE tpm_key_handle, + TPM_BOOL readOnly, + TPM_BOOL ignorePCRs, + TPM_BOOL allowEK); +TPM_RESULT TPM_KeyHandleEntries_SetParentPCRStatus(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + TPM_KEY_HANDLE tpm_key_handle, + TPM_BOOL parentPCRStatus); +TPM_RESULT TPM_KeyHandleEntries_GetNextEntry(TPM_KEY_HANDLE_ENTRY **tpm_key_handle_entry, + size_t *current, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + size_t start); + +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictLoad(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + unsigned char **stream, uint32_t *stream_size); +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictStore(TPM_STORE_BUFFER *sbuffer, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); +TPM_RESULT TPM_KeyHandleEntries_OwnerEvictGetCount(uint16_t *count, + const TPM_KEY_HANDLE_ENTRY + *tpm_key_handle_entries); +void TPM_KeyHandleEntries_OwnerEvictDelete(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); + +/* TPM_RSA_KEY_PARMS */ + +void TPM_RSAKeyParms_Init(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms); +TPM_RESULT TPM_RSAKeyParms_Load(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_RSAKeyParms_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_RSA_KEY_PARMS *tpm_rsa_key_parms); +void TPM_RSAKeyParms_Delete(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms); + +TPM_RESULT TPM_RSAKeyParms_Copy(TPM_RSA_KEY_PARMS *tpm_rsa_key_parms_dest, + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms_src); +TPM_RESULT TPM_RSAKeyParms_New(TPM_RSA_KEY_PARMS **tpm_rsa_key_parms); +TPM_RESULT TPM_RSAKeyParms_GetExponent(uint32_t *ebytes, + unsigned char **earr, + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms); + +/* TPM_STORE_ASYMKEY */ + +void TPM_StoreAsymkey_Init(TPM_STORE_ASYMKEY *tpm_store_asymkey); +TPM_RESULT TPM_StoreAsymkey_Load(TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_BOOL isEK, + unsigned char **stream, + uint32_t *stream_size, + TPM_KEY_PARMS *tpm_key_parms, + TPM_SIZED_BUFFER *tpm_store_pubkey); +TPM_RESULT TPM_StoreAsymkey_Store(TPM_STORE_BUFFER *sbuffer, + TPM_BOOL isEK, + const TPM_STORE_ASYMKEY *tpm_store_asymkey); +void TPM_StoreAsymkey_Delete(TPM_STORE_ASYMKEY *tpm_store_asymkey); + +TPM_RESULT TPM_StoreAsymkey_GenerateEncData(TPM_SIZED_BUFFER *encData, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_KEY *parent_key); +TPM_RESULT TPM_StoreAsymkey_GetPrimeFactorP(uint32_t *pbytes, + unsigned char **parr, + TPM_STORE_ASYMKEY *tpm_store_asymkey); +void TPM_StoreAsymkey_GetO1Size(uint32_t *o1_size, + TPM_STORE_ASYMKEY *tpm_store_asymkey); +TPM_RESULT TPM_StoreAsymkey_CheckO1Size(uint32_t o1_size, + uint32_t k1k2_length); +TPM_RESULT TPM_StoreAsymkey_StoreO1(BYTE *o1, + uint32_t o1_size, + TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_DIGEST pHash, + TPM_PAYLOAD_TYPE payload_type, + TPM_SECRET usageAuth); +TPM_RESULT TPM_StoreAsymkey_LoadO1(TPM_STORE_ASYMKEY *tpm_store_asymkey, + BYTE *o1, + uint32_t o1_size); + +/* TPM_MIGRATE_ASYMKEY */ + +void TPM_MigrateAsymkey_Init(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey); +TPM_RESULT TPM_MigrateAsymkey_Load(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_MigrateAsymkey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey); +void TPM_MigrateAsymkey_Delete(TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey); + +/* + TPM_STORE_PRIVKEY +*/ + +void TPM_StorePrivkey_Init(TPM_STORE_PRIVKEY *tpm_store_privkey); +TPM_RESULT TPM_StorePrivkey_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STORE_PRIVKEY *tpm_store_privkey); +void TPM_StorePrivkey_Delete(TPM_STORE_PRIVKEY *tpm_store_privkey); + +TPM_RESULT TPM_StorePrivkey_Convert(TPM_STORE_ASYMKEY *tpm_store_asymkey, + TPM_KEY_PARMS *tpm_key_parms, + TPM_SIZED_BUFFER *pubKey); + + +/* Command Processing Functions */ + + +TPM_RESULT TPM_Process_ReadPubek(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_CreateRevocableEK(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_CreateEndorsementKeyPair(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_CreateEndorsementKeyPair_Common(TPM_KEY *endorsementKey, + TPM_PUBKEY *pubEndorsementKey, + TPM_DIGEST checksum, + TPM_BOOL *writePermanentData, + tpm_state_t *tpm_state, + TPM_KEY_PARMS *keyInfo, + TPM_NONCE antiReplay); + +TPM_RESULT TPM_Process_RevokeTrust(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_DisablePubekRead(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_OwnerReadPubek(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_EvictKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_OwnerReadInternalPub(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +#endif diff --git a/src/tpm_library.c b/src/tpm_library.c new file mode 100644 index 00000000..a9b9f3b2 --- /dev/null +++ b/src/tpm_library.c @@ -0,0 +1,364 @@ +/********************************************************************************/ +/* */ +/* LibTPM interface functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_library.c 4615 2011-08-30 15:35:24Z stefanb $ */ +/* */ +/* (c) Copyright IBM Corporation 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_library.h" +#include "tpm_library_intern.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_process.h" +#include "tpm_startup.h" + +#define ROUNDUP(VAL, SIZE) \ + ( ( (VAL) + (SIZE) - 1 ) / (SIZE) ) * (SIZE) + + + +static const struct tags_and_indices { + const char *starttag; + const char *endtag; +} tags_and_indices[] = { + [TPMLIB_BLOB_TYPE_INITSTATE] = + { + .starttag = TPMLIB_INITSTATE_START_TAG, + .endtag = TPMLIB_INITSTATE_END_TAG, + }, +}; + + + +uint32_t TPMLIB_GetVersion(void) +{ + return TPM_LIBRARY_VERSION; +} + +TPM_RESULT TPMLIB_MainInit(void) +{ + return TPM_MainInit(); +} + + +void TPMLIB_Terminate(void) +{ + TPM_Global_Delete(tpm_instances[0]); +} + + +/* + * Send a command to the TPM. The command buffer must hold a well formatted + * TPM command and the command_size indicate the size of the command. + * The respbuffer parameter may be provided by the user and grow if + * the respbufsize size indicator is determined to be too small for the + * response. In that case a new buffer will be allocated and the size of that + * buffer returned in the respbufsize parameter. resp_size describes the + * size of the actual response within the respbuffer. + */ +TPM_RESULT TPMLIB_Process(unsigned char **respbuffer, uint32_t *resp_size, + uint32_t *respbufsize, + unsigned char *command, uint32_t command_size) +{ + *resp_size = 0; + return TPM_ProcessA(respbuffer, resp_size, respbufsize, + command, command_size); +} + + +/* + * Get the volatile state from the TPM. This function will return the + * buffer and the length of the buffer to the caller in case everything + * went alright. + */ +TPM_RESULT TPMLIB_VolatileAll_Store(unsigned char **buffer, + uint32_t *buflen) +{ + TPM_RESULT rc; + TPM_STORE_BUFFER tsb; + TPM_Sbuffer_Init(&tsb); + uint32_t total; + +#ifdef TPM_DEBUG + assert(tpm_instances[0] != NULL); +#endif + + rc = TPM_VolatileAll_Store(&tsb, tpm_instances[0]); + + if (rc == TPM_SUCCESS) { + /* caller now owns the buffer and needs to free it */ + TPM_Sbuffer_GetAll(&tsb, buffer, buflen, &total); + } else { + TPM_Sbuffer_Delete(&tsb); + *buflen = 0; + *buffer = NULL; + } + + return rc; +} + + +/* + * Get a property of the TPM. The functions currently only + * return compile-time #defines but this may change in future + * versions where we may return parameters with which the TPM + * was created (rather than compiled). + */ +TPM_RESULT TPMLIB_GetTPMProperty(enum TPMLIB_TPMProperty prop, + int *result) +{ + switch (prop) { + case TPMPROP_TPM_RSA_KEY_LENGTH_MAX: + *result = TPM_RSA_KEY_LENGTH_MAX; + break; + + case TPMPROP_TPM_BUFFER_MAX: + *result = TPM_BUFFER_MAX; + break; + + case TPMPROP_TPM_KEY_HANDLES: + *result = TPM_KEY_HANDLES; + break; + + case TPMPROP_TPM_OWNER_EVICT_KEY_HANDLES: + *result = TPM_OWNER_EVICT_KEY_HANDLES; + break; + + case TPMPROP_TPM_MIN_AUTH_SESSIONS: + *result = TPM_MIN_AUTH_SESSIONS; + break; + + case TPMPROP_TPM_MIN_TRANS_SESSIONS: + *result = TPM_MIN_TRANS_SESSIONS; + break; + + case TPMPROP_TPM_MIN_DAA_SESSIONS: + *result = TPM_MIN_DAA_SESSIONS; + break; + + case TPMPROP_TPM_MIN_SESSION_LIST: + *result = TPM_MIN_SESSION_LIST; + break; + + case TPMPROP_TPM_MIN_COUNTERS: + *result = TPM_MIN_COUNTERS; + break; + + case TPMPROP_TPM_NUM_FAMILY_TABLE_ENTRY_MIN: + *result = TPM_NUM_FAMILY_TABLE_ENTRY_MIN; + break; + + case TPMPROP_TPM_NUM_DELEGATE_TABLE_ENTRY_MIN: + *result = TPM_NUM_DELEGATE_TABLE_ENTRY_MIN; + break; + + case TPMPROP_TPM_SPACE_SAFETY_MARGIN: + *result = TPM_SPACE_SAFETY_MARGIN; + break; + + case TPMPROP_TPM_MAX_NV_SPACE: + /* fill up 20 kb.; this provides some safety margin (currently + >4Kb) for possible future expansion of this blob */ + *result = ROUNDUP(TPM_MAX_NV_SPACE, 20 * 1024); + break; + + case TPMPROP_TPM_MAX_SAVESTATE_SPACE: + *result = TPM_MAX_SAVESTATE_SPACE; + break; + + case TPMPROP_TPM_MAX_VOLATILESTATE_SPACE: + *result = TPM_MAX_VOLATILESTATE_SPACE; + break; + + default: + return TPM_FAIL; + } + + return TPM_SUCCESS; +} + +static struct libtpms_callbacks libtpms_cbs; + +struct libtpms_callbacks *TPMLIB_GetCallbacks(void) +{ + return &libtpms_cbs; +} + + +TPM_RESULT TPMLIB_RegisterCallbacks(struct libtpms_callbacks *callbacks) +{ + int max_size = sizeof(struct libtpms_callbacks); + + /* restrict the size of the structure to what we know currently + future versions may know more callbacks */ + if (callbacks->sizeOfStruct < max_size) + max_size = callbacks->sizeOfStruct; + + /* clear the internal callback structure and copy the user provided + callbacks into it */ + memset(&libtpms_cbs, 0x0, sizeof(libtpms_cbs)); + memcpy(&libtpms_cbs, callbacks, max_size); + + return TPM_SUCCESS; +} + + +static int is_base64ltr(char c) +{ + return ((c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') || + c == '+' || + c == '/' || + c == '='); +} + + +/* + * Base64 decode the string starting at 'start' and the last + * valid character may be a 'end'. The length of the decoded string + * is returned in *length. + */ +static unsigned char *TPMLIB_Base64Decode(const char *start, const char *end, + size_t *length) +{ + unsigned char *ret = NULL; + char *input = NULL, *d; + const char *s; + char c; + unsigned int numbase64chars = 0; + + if (end < start) + return NULL; + + while (end > start && !is_base64ltr(*end)) + end--; + + end++; + + if (TPM_Malloc((unsigned char **)&input, end - start + 1) != TPM_SUCCESS) + return NULL; + + /* copy from source string skipping '\n' and '\r' and using + '=' to calculate the exact length */ + d = input; + s = start; + + while (s < end) { + c = *s; + if (c != '=' && is_base64ltr(c)) { + *d = c; + d++; + numbase64chars++; + } else if (c == 0) { + break; + } + s++; + } + *d = 0; + + *length = (numbase64chars / 4) * 3; + switch (numbase64chars % 4) { + case 2: + case 3: + *length += (numbase64chars % 4) - 1; + break; + case 0: + break; + case 1: + fprintf(stderr,"malformed base64\n"); + goto err_exit; + break; + } + + ret = (unsigned char *)PL_Base64Decode(input, 0, NULL); + +err_exit: + free(input); + + return ret; +} + + +static unsigned char *TPMLIB_GetPlaintext(const char *stream, + const char *starttag, + const char *endtag, + size_t *length) +{ + char *start, *end; + unsigned char *plaintext = NULL; + + start = strstr(stream, starttag); + if (start) { + start += strlen(starttag); + while (isspace(*start)) + start++; + end = strstr(start, endtag); + if (end) { + plaintext = TPMLIB_Base64Decode(start, --end, length); + } + } + return plaintext; +} + + +TPM_RESULT TPMLIB_DecodeBlob(const char *buffer, enum TPMLIB_BlobType type, + unsigned char **result, size_t *result_len) +{ + TPM_RESULT res = TPM_SUCCESS; + + *result = TPMLIB_GetPlaintext(buffer, + tags_and_indices[type].starttag, + tags_and_indices[type].endtag, + result_len); + + if (*result == NULL) { + res = TPM_FAIL; + } + + return res; +} + diff --git a/src/tpm_library_conf.h b/src/tpm_library_conf.h new file mode 100644 index 00000000..0359f73d --- /dev/null +++ b/src/tpm_library_conf.h @@ -0,0 +1,172 @@ +/********************************************************************************/ +/* */ +/* LibTPM compile-time choices (#defines) */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_library_conf.h 4589 2011-07-05 12:22:40Z stefanb $ */ +/* */ +/* (c) Copyright IBM Corporation 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ +#ifndef TPM_LIBRARY_CONF_H +#define TPM_LIBRARY_CONF_H + +/* Note: None of these defines should be used directly; rather, + * the TPMLIB_GetTPMProperty() call should be used to + * query their value. + * Since tpm_constants.h defines some default values if none + * other are defined, this header should be included before + * tpm_constants.h is included. + */ + +/* need to restrict the maximum size of keys to cap the below blobs */ +#define TPM_RSA_KEY_LENGTH_MAX 2048 + +/* maximum size of the IO buffer used for requests and responses */ +#define TPM_BUFFER_MAX 4096 + +/* + * Below the following acronyms are used to identify what + * #define influences which one of the state blobs the TPM + * produces. + * + * PA : permanentall + * SS : savestate + * VA : volatileall + * + * BAL: contributes to the ballooning of the state blob + */ + +/* + * Do not touch these #define's anymore. They are fixed forever + * and define the properties of the TPM library and have a + * direct influence on the size requirements of the TPM's block + * store and the organization of data inside that block store. + */ +/* + * Every 2048 bit key in volatile space accounts for an + * increase of maximum of 559 bytes (PCR_INFO_LONG, tied to PCRs). + */ +#define TPM_KEY_HANDLES 20 /* SS, VA, BAL */ + +/* + * Every 2048 bit key on which the owner evict key flag is set + * accounts for an increase of 559 bytes of the permanentall + * blob. + */ +#define TPM_OWNER_EVICT_KEY_HANDLES 10 /* PA, BAL */ + +/* + * The largets auth session is DSAP; each such session consumes 119 bytes + */ +#define TPM_MIN_AUTH_SESSIONS 16 /* SS, VA, BAL */ + +/* + * Every transport session accounts for an increase of 78 bytes + */ +#define TPM_MIN_TRANS_SESSIONS 16 /* SS, VA, BAL */ +/* + * Every DAA session accounts for an increase of 844 bytes. + */ +#define TPM_MIN_DAA_SESSIONS 2 /* SS, VA, BAL */ + +#define TPM_MIN_SESSION_LIST 128 /* SS, VA */ +#define TPM_MIN_COUNTERS 8 /* PA */ +#define TPM_NUM_FAMILY_TABLE_ENTRY_MIN 16 /* PA */ +#define TPM_NUM_DELEGATE_TABLE_ENTRY_MIN 4 /* PA */ + +/* + * NB: above #defines directly influence the largest size of the + * 'permanentall', 'savestate' and 'volatileall' data. If these + * #define's allow the below space requirements to be exceeded, the + * TPM may go into shutdown mode, something we would definitely + * like to prevent. We are mostly concerned about the size of + * the 'permanentall' blob, which is capped by TPM_MAX_NV_SPACE, + * and that of the 'savestate' blob, which is capped by + * TPM_MAX_SAVESTATE_SPACE. + */ + +#define TPM_SPACE_SAFETY_MARGIN (4 * 1024) + +/* + * As of V0.5.1 (may have increased since then): + * permanent space + 10 keys = 7920 bytes + * full volatile space = 17223 bytes + * full savestate space = 16992 bytes + */ + +/* + * For the TPM_MAX_NV_SPACE we cannot provide a safety margin here + * since the TPM will allow NVRAM spaces to allocate everything. + * So, we tell the user in TPMLIB_GetTPMProperty that it's 20kb. This + * gives us some safety margin for the future. + */ +#define TPM_PERMANENT_ALL_BASE_SIZE (2334 /* incl. SRK, EK */ + \ + 2048 /* extra space */) + +#define TPM_MAX_NV_DEFINED_SIZE (2048 /* min. NVRAM spaces */ + \ + 26*1024 /* extra NVRAM space */ ) + +#define TPM_MAX_NV_SPACE (TPM_PERMANENT_ALL_BASE_SIZE + \ + TPM_OWNER_EVICT_KEY_HANDLES * 559 + \ + TPM_MAX_NV_DEFINED_SIZE) + +#define TPM_MAX_SAVESTATE_SPACE (972 + /* base size */ \ + TPM_KEY_HANDLES * 559 + \ + TPM_MIN_TRANS_SESSIONS * 78 + \ + TPM_MIN_DAA_SESSIONS * 844 + \ + TPM_MIN_AUTH_SESSIONS * 119 + \ + TPM_SPACE_SAFETY_MARGIN) + +#define TPM_MAX_VOLATILESTATE_SPACE (1203 + /* base size */ \ + TPM_KEY_HANDLES * 559 + \ + TPM_MIN_TRANS_SESSIONS * 78 + \ + TPM_MIN_DAA_SESSIONS * 844 + \ + TPM_MIN_AUTH_SESSIONS * 119 + \ + TPM_SPACE_SAFETY_MARGIN) + +/* + * The timeouts in microseconds. + * + * The problem with the timeouts is that on a heavily utilized + * virtualized platform, the processing of the TPM's commands will + * take much longer than on a system that's not very busy. So, we + * now choose values that are very high so that we don't hit timeouts + * in TPM drivers just because the system is busy. However, hitting + * timeouts on a very busy system may be inevitable... + */ + +#define TPM_SMALL_DURATION ( 50 * 1000 * 1000) +#define TPM_MEDIUM_DURATION (100 * 1000 * 1000) +#define TPM_LONG_DURATION (300 * 1000 * 1000) + + +#endif /* TPM_LIBRARY_CONF_H */ diff --git a/src/tpm_library_intern.h b/src/tpm_library_intern.h new file mode 100644 index 00000000..c1c6db78 --- /dev/null +++ b/src/tpm_library_intern.h @@ -0,0 +1,46 @@ +/********************************************************************************/ +/* */ +/* LibTPM internal interface functions */ +/* Written by Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_library_intern.h 4432 2011-02-11 15:30:31Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2011. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ +#ifndef TPM_LIBRARY_INTERN_H +#define TPM_LIBRARY_INTERN_H + +#include "tpm_library.h" + +struct libtpms_callbacks *TPMLIB_GetCallbacks(void); + +#endif /* TPM_LIBRARY_INTERN_H */ diff --git a/src/tpm_libtpms_io.c b/src/tpm_libtpms_io.c new file mode 100644 index 00000000..dfb56468 --- /dev/null +++ b/src/tpm_libtpms_io.c @@ -0,0 +1,70 @@ +/********************************************************************************/ +/* */ +/* Libtpms IO Init */ +/* Written by Ken Goldman, Stefan Berger */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_io.c 4564 2011-04-13 19:33:38Z stefanb $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_platform.h" +#include "tpm_types.h" + +#include "tpm_library_intern.h" + +/* header for this file */ +#include "tpm_io.h" + +/* TPM_IO_Init initializes the TPM to host interface. + + This is the Unix platform dependent socket version. +*/ + +TPM_RESULT TPM_IO_Init(void) +{ + TPM_RESULT rc = 0; + struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); + + /* call user-provided function if available */ + if (cbs->tpm_io_init) { + rc = cbs->tpm_io_init(); + return rc; + } else { + /* Below code would start a TCP server socket; we don't want this + but rather expect all commands via TPMLIB_Process() to be sent + to the TPM. */ + return TPM_SUCCESS; + } +} diff --git a/src/tpm_load.c b/src/tpm_load.c new file mode 100644 index 00000000..dc05c4f5 --- /dev/null +++ b/src/tpm_load.c @@ -0,0 +1,307 @@ +/********************************************************************************/ +/* */ +/* Load from Stream Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_load.c 4668 2012-01-25 21:16:48Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +/* Generally useful utilities to deserialize structures from a stream */ + +#include +#include +#include + +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_sizedbuffer.h" +#include "tpm_types.h" + +#include "tpm_load.h" + +/* The LOADn() functions convert a big endian stream to integer types */ + +uint32_t LOAD32(const unsigned char *buffer, unsigned int offset) +{ + unsigned int i; + uint32_t result = 0; + + for (i = 0 ; i < 4 ; i++) { + result <<= 8; + result |= buffer[offset + i]; + } + return result; +} + +uint16_t LOAD16(const unsigned char *buffer, unsigned int offset) +{ + unsigned int i; + uint16_t result = 0; + + for (i = 0 ; i < 2 ; i++) { + result <<= 8; + result |= buffer[offset + i]; + } + return result; +} + +uint8_t LOAD8(const unsigned char *buffer, unsigned int offset) +{ + uint8_t result = 0; + + result |= buffer[offset]; + return result; +} + +/* TPM_Load32() loads 'tpm_uint32' from the stream. + + It checks that the stream has sufficient data, and adjusts 'stream' + and 'stream_size' past the data. +*/ + +TPM_RESULT TPM_Load32(uint32_t *tpm_uint32, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + /* check stream_size */ + if (rc == 0) { + if (*stream_size < sizeof(uint32_t)) { + printf("TPM_Load32: Error, stream_size %u less than %lu\n", + *stream_size, (unsigned long)sizeof(uint32_t)); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* load the parameter */ + if (rc == 0) { + *tpm_uint32 = LOAD32(*stream, 0); + *stream += sizeof (uint32_t); + *stream_size -= sizeof (uint32_t); + } + return rc; +} + +/* TPM_Load16() loads 'tpm_uint16' from the stream. + + It checks that the stream has sufficient data, and adjusts 'stream' + and 'stream_size' past the data. +*/ + +TPM_RESULT TPM_Load16(uint16_t *tpm_uint16, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + /* check stream_size */ + if (rc == 0) { + if (*stream_size < sizeof(uint16_t)) { + printf("TPM_Load16: Error, stream_size %u less than %lu\n", + *stream_size, (unsigned long)sizeof(uint16_t)); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* load the parameter */ + if (rc == 0) { + *tpm_uint16 = LOAD16(*stream, 0); + *stream += sizeof (uint16_t); + *stream_size -= sizeof (uint16_t); + } + return rc; +} + +TPM_RESULT TPM_Load8(uint8_t *tpm_uint8, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + /* check stream_size */ + if (rc == 0) { + if (*stream_size < sizeof(uint8_t)) { + printf("TPM_Load8: Error, stream_size %u less than %lu\n", + *stream_size, (unsigned long)sizeof(uint8_t)); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* load the parameter */ + if (rc == 0) { + *tpm_uint8 = LOAD8(*stream, 0); + *stream += sizeof (uint8_t); + *stream_size -= sizeof (uint8_t); + } + return rc; +} + +/* Boolean incoming parameter values other than 0x00 and 0x01 have an implementation specific + interpretation. The TPM SHOULD return TPM_BAD_PARAMETER. +*/ + +TPM_RESULT TPM_LoadBool(TPM_BOOL *tpm_bool, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + /* check stream_size */ + if (rc == 0) { + if (*stream_size < sizeof(TPM_BOOL)) { + printf("TPM_LoadBool: Error, stream_size %u less than %lu\n", + *stream_size, (unsigned long)sizeof(TPM_BOOL)); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* load the parameter */ + if (rc == 0) { + *tpm_bool = LOAD8(*stream, 0); + *stream += sizeof (uint8_t); + *stream_size -= sizeof (uint8_t); + } + if (rc == 0) { + if ((*tpm_bool != TRUE) && (*tpm_bool != FALSE)) { + printf("TPM_LoadBool: Error, illegal value %02x\n", *tpm_bool); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_Loadn() copies 'data_length' bytes from 'stream' to 'data' with + no endian adjustments. */ + +TPM_RESULT TPM_Loadn(BYTE *data, + size_t data_length, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + /* check stream_size */ + if (rc == 0) { + if (*stream_size < data_length) { + printf("TPM_Loadn: Error, stream_size %u less than %lu\n", + *stream_size, (unsigned long)data_length); + rc = TPM_BAD_PARAM_SIZE; + } + } + /* load the parameter */ + if (rc == 0) { + memcpy(data, *stream, data_length); + *stream += data_length; + *stream_size -= data_length; + } + return rc; +} + +/* TPM_LoadLong() creates a long from a stream in network byte order. + + The stream is not advanced. +*/ + +TPM_RESULT TPM_LoadLong(unsigned long *result, + const unsigned char *stream, + uint32_t stream_size) +{ + TPM_RESULT rc = 0; + size_t i; /* byte iterator */ + + printf(" TPM_LoadLong:\n"); + if (rc == 0) { + if (stream_size > sizeof(unsigned long)) { + printf(" TPM_LoadLong: Error, stream size %u too large\n", stream_size); + rc = TPM_BAD_PARAM_SIZE; + } + } + if (rc == 0) { + *result = 0; /* initialize all bytes to 0 in case buffer is less than sizeof(unsigned + long) bytes */ + for (i = 0 ; i < stream_size ; i++) { + /* copy big endian stream, put lowest address in an upper byte, highest address in byte + 0 */ + *result |= stream[i] << ((stream_size - 1 - i) * 8); + } + printf(" TPM_LoadLong: Result %08lx\n", *result); + } + return rc; +} + +/* TPM_LoadString() returns a pointer to a C string. It does not copy the string. + + */ + +TPM_RESULT TPM_LoadString(const char **name, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + char *ptr; + + *name = NULL; + /* search for the first nul character */ + if (rc == 0) { + ptr = memchr(*stream, (int)'\0', *stream_size); + if (ptr == NULL) { + rc = TPM_BAD_PARAM_SIZE; + } + } + if (rc == 0) { + *name = (char *)*stream; /* cast because converting binary to string */ + *stream_size -= (ptr - *name) + 1; + *stream = (unsigned char *)ptr + 1; + } + return rc; +} + +/* TPM_CheckTag() loads a TPM_STRUCTURE_TAG from 'stream'. It check that the value is 'expectedTag' + and returns TPM_INVALID_STRUCTURE on error. + +*/ + +TPM_RESULT TPM_CheckTag(TPM_STRUCTURE_TAG expectedTag, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_STRUCTURE_TAG tag; + + if (rc == 0) { + rc = TPM_Load16(&tag, stream, stream_size); + } + if (rc == 0) { + if (tag != expectedTag) { + printf("TPM_CheckTag: Error, tag expected %04x found %04hx\n", expectedTag, tag); + rc = TPM_INVALID_STRUCTURE; + } + } + return rc; +} + diff --git a/src/tpm_load.h b/src/tpm_load.h new file mode 100644 index 00000000..de214fdb --- /dev/null +++ b/src/tpm_load.h @@ -0,0 +1,78 @@ +/********************************************************************************/ +/* */ +/* Load from Stream Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_load.h 4668 2012-01-25 21:16:48Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_LOAD_H +#define TPM_LOAD_H + +#include "tpm_types.h" + +TPM_RESULT TPM_Load32(uint32_t *tpm_uint32, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Load16(uint16_t *tpm_uint16, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Load8(uint8_t *tpm_uint8, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Loadn(BYTE *data, + size_t data_length, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_LoadBool(TPM_BOOL *tpm_bool, + unsigned char **stream, + uint32_t *stream_size); + +TPM_RESULT TPM_LoadLong(unsigned long *result, + const unsigned char *stream, + uint32_t stream_size); +TPM_RESULT TPM_LoadString(const char **name, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CheckTag(TPM_STRUCTURE_TAG expectedTag, + unsigned char **stream, + uint32_t *stream_size); + +/* byte stream to type */ + +uint32_t LOAD32(const unsigned char *buffer, unsigned int offset); +uint16_t LOAD16(const unsigned char *buffer, unsigned int offset); +uint8_t LOAD8(const unsigned char *buffer, unsigned int offset); + +#endif diff --git a/src/tpm_maint.c b/src/tpm_maint.c new file mode 100644 index 00000000..6cb65c74 --- /dev/null +++ b/src/tpm_maint.c @@ -0,0 +1,1304 @@ +/********************************************************************************/ +/* */ +/* Maintenance Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_maint.c 4442 2011-02-14 20:20:01Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_NOMAINTENANCE + +#include +#include + +#include "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_owner.h" +#include "tpm_permanent.h" +#include "tpm_process.h" + +#include "tpm_maint.h" + +/* + Processing Functions +*/ + +/* 12. Maintenance Functions (optional) + + The maintenance mechanisms in the TPM MUST not require the TPM to hold a global secret. The + definition of global secret is a secret value shared by more than one TPM. + + The TPME is not allowed to pre-store or use unique identifiers in the TPM for the purpose of + maintenance. The TPM MUST NOT use the endorsement key for identification or encryption in the + maintenance process. The maintenance process MAY use a TPM Identity to deliver maintenance + information to specific TPM's. + + The maintenance process can only change the SRK, tpmProof and TPM Owner AuthData fields. + + The maintenance process can only access data in shielded locations where this data is necessary + to validate the TPM Owner, validate the TPME and manipulate the blob + + The TPM MUST be conformant to the TPM specification, protection profiles and security targets + after maintenance. The maintenance MAY NOT decrease the security values from the original + security target. + + The security target used to evaluate this TPM MUST include this command in the TOE. +*/ + +/* When a maintenance archive is created with generateRandom FALSE, the maintenance blob is XOR + encrypted with the owner authorization before encryption with the maintenance public key. This + prevents the manufacturer from obtaining plaintext data. The receiving TPM must have the same + owner authorization as the sending TPM in order to XOR decrypt the archive. + + When generateRandom is TRUE, the maintenance blob is XOR encrypted with random data, which is + also returned. This permits someone trusted by the Owner to load the maintenance archive into the + replacement platform in the absence of the Owner and manufacturer, without the Owner having to + reveal information about his auth value. The receiving and sending TPM's may have different owner + authorizations. The random data is transferred from the sending TPM owner to the receiving TPM + owner out of band, so the maintenance blob remains hidden from the manufacturer. + + This is a typical maintenance sequence: + 1. Manufacturer: + - generates maintenance key pair + - gives public key to TPM1 owner + 2. TPM1: TPM_LoadManuMaintPub + - load maintenance public key + 3. TPM1: TPM_CreateMaintenanceArchive + - XOR encrypt with owner auth or random + - encrypt with maintenance public key + 4. Manufacturer: + - decrypt with maintenance private key + - (still XOR encrypted with owner auth or random) + - encrypt with TPM2 SRK public key + 5. TPM2: TPM_LoadMaintenanceArchive + - decrypt with SRK private key + - XOR decrypt with owner auth or random +*/ + +/* 12.1 TPM_CreateMaintenanceArchive rev 101 + + This command creates the MaintenanceArchive. It can only be executed by the owner, and may be + shut off with the TPM_KillMaintenanceFeature command. +*/ + +TPM_RESULT TPM_Process_CreateMaintenanceArchive(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_BOOL generateRandom; /* Use RNG or Owner auth to generate 'random'. */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey = NULL; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + uint32_t o1Oaep_size; + BYTE *o1Oaep; + BYTE *r1InnerWrapKey; + BYTE *x1InnerWrap; + TPM_KEY a1; /* SRK archive result */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER random; /* Random data to XOR with result. */ + TPM_STORE_BUFFER archive; /* Encrypted key archive. */ + + printf("TPM_Process_CreateMaintenanceArchive: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&random); /* freed @1 */ + TPM_Key_Init(&a1); /* freed @2 */ + TPM_Sbuffer_Init(&archive); /* freed @3 */ + o1Oaep = NULL; /* freed @4 */ + r1InnerWrapKey = NULL; /* freed @5 */ + x1InnerWrap = NULL; /* freed @6 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get generateRandom parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&generateRandom, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateMaintenanceArchive: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* Upon authorization being confirmed this command does the following: */ + /* 1. Validates that the TPM_PERMANENT_FLAGS -> AllowMaintenance is TRUE. If it is FALSE, the + TPM SHALL return TPM_DISABLED_CMD and exit this capability. */ + if (returnCode == TPM_SUCCESS) { + if (!tpm_state->tpm_permanent_flags.allowMaintenance) { + printf("TPM_Process_CreateMaintenanceArchive: Error allowMaintenance FALSE\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* 2. Validates the TPM Owner AuthData. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 3. If the value of TPM_PERMANENT_DATA -> ManuMaintPub is zero, the TPM MUST return the error + code TPM_KEYNOTFOUND */ + if (returnCode == TPM_SUCCESS) { + /* since there is no keyUsage, algorithmID seems like a way to check for an empty key */ + if (tpm_state->tpm_permanent_data.manuMaintPub.algorithmParms.algorithmID != TPM_ALG_RSA) { + printf("TPM_Process_CreateMaintenanceArchive: manuMaintPub key not found\n"); + returnCode = TPM_KEYNOTFOUND; + } + } + /* 4. Build a1 a TPM_KEY structure using the SRK. The encData field is not a normal + TPM_STORE_ASYMKEY structure but rather a TPM_MIGRATE_ASYMKEY structure built using the + following actions. */ + if (returnCode == TPM_SUCCESS) { + TPM_Key_Copy(&a1, + &(tpm_state->tpm_permanent_data.srk), + FALSE); /* don't copy encData */ + } + /* 5. Build a TPM_STORE_PRIVKEY structure from the SRK. This privKey element should be 132 bytes + long for a 2K RSA key. */ + /* 6. Create k1 and k2 by splitting the privKey element created in step 4 into 2 parts. k1 is + the first 20 bytes of privKey, k2 contains the remainder of privKey. */ + /* 7. Build m1 by creating and filling in a TPM_MIGRATE_ASYMKEY structure */ + /* a. m1 -> usageAuth is set to TPM_PERMANENT_DATA -> tpmProof */ + /* b. m1 -> pubDataDigest is set to the digest value of the SRK fields from step 4 */ + /* c. m1 -> payload is set to TPM_PT_MAINT */ + /* d. m1 -> partPrivKey is set to k2 */ + /* 8. Create o1 (which SHALL be 198 bytes for a 2048 bit RSA key) by performing the OAEP + encoding of m using OAEP parameters of */ + /* a. m = TPM_MIGRATE_ASYMKEY structure (step 7) */ + /* b. pHash = TPM_PERMANENT_DATA -> ownerAuth */ + /* c. seed = s1 = k1 (step 6) */ + if (returnCode == TPM_SUCCESS) { + TPM_StoreAsymkey_GetO1Size(&o1Oaep_size, + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&o1Oaep, o1Oaep_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&r1InnerWrapKey, o1Oaep_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&x1InnerWrap, o1Oaep_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StoreAsymkey_StoreO1 + (o1Oaep, + o1Oaep_size, + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey, + tpm_state->tpm_permanent_data.ownerAuth, /* pHash */ + TPM_PT_MAINT, /* TPM_PAYLOAD_TYPE */ + tpm_state->tpm_permanent_data.tpmProof); /* usageAuth */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateMaintenanceArchive: o1 -", o1Oaep); + /* 9. If generateRandom = TRUE */ + if (generateRandom) { + /* a. Create r1 by obtaining values from the TPM RNG. The size of r1 MUST be the same + size as o1. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Random(r1InnerWrapKey, o1Oaep_size); + } + /* Set random parameter to r1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Set(&random, o1Oaep_size, r1InnerWrapKey); + } + } + /* 10. If generateRandom = FALSE */ + else { + /* a. Create r1 by applying MGF1 to the TPM Owner AuthData. The size of r1 MUST be the + same size as o1. */ + returnCode = TPM_MGF1(r1InnerWrapKey, /* unsigned char *mask */ + o1Oaep_size, /* long len */ + tpm_state->tpm_permanent_data.ownerAuth, /* const unsigned + char *seed */ + TPM_SECRET_SIZE); /* long seedlen */ + /* Set randomSize to 0. */ + /* NOTE Done by TPM_SizedBuffer_Init() */ + } + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateMaintenanceArchive: r1 -", r1InnerWrapKey); + /* 11. Create x1 by XOR of o1 with r1 */ + TPM_XOR(x1InnerWrap, o1Oaep, r1InnerWrapKey, o1Oaep_size); + TPM_PrintFour("TPM_Process_CreateMaintenanceArchive: x1", x1InnerWrap); + /* 12. Encrypt x1 with the manuMaintPub key using the TPM_ES_RSAESOAEP_SHA1_MGF1 + encryption scheme. NOTE The check for OAEP is done by TPM_LoadManuMaintPub */ + /* 13. Set a1 -> encData to the encryption of x1 */ + returnCode = TPM_RSAPublicEncrypt_Pubkey(&(a1.encData), + x1InnerWrap, + o1Oaep_size, + &(tpm_state->tpm_permanent_data.manuMaintPub)); + TPM_PrintFour("TPM_Process_CreateMaintenanceArchive: encData", a1.encData.buffer); + } + /* 14. Set TPM_PERMANENT_FLAGS -> maintenanceDone to TRUE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMaintenanceArchive: Set maintenanceDone\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.maintenanceDone), /* flag */ + TRUE); /* value */ + } + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* 15. Return a1 in the archive parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Store(&archive, &a1); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateMaintenanceArchive: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return randomSize and random */ + returnCode = TPM_SizedBuffer_Store(response, &random); + } + if (returnCode == TPM_SUCCESS) { + /* return archiveSize and archive */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &archive); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&random); /* @1 */ + TPM_Key_Delete(&a1); /* @2 */ + TPM_Sbuffer_Delete(&archive); /* @3 */ + free(o1Oaep); /* @4 */ + free(r1InnerWrapKey); /* @5 */ + free(x1InnerWrap); /* @6 */ + return rcf; +} + +/* 12.2 TPM_LoadMaintenanceArchive rev 98 + + This command loads in a Maintenance archive that has been massaged by the manufacturer to load + into another TPM + + If the maintenance archive was created using the owner authorization for XOR encryption, the + current owner authorization must be used for decryption. The owner authorization does not change. + + If the maintenance archive was created using random data for the XOR encryption, the vendor + specific arguments must include the random data. The owner authorization may change. +*/ + +TPM_RESULT TPM_Process_LoadMaintenanceArchive(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + TPM_SIZED_BUFFER archive; /* Vendor specific arguments, from + TPM_CreateMaintenanceArchive */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth.*/ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_SECRET saveKey; /* copy of HMAC key, since key changes */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + unsigned char *stream; /* the input archive stream */ + uint32_t stream_size; + BYTE *x1InnerWrap; + uint32_t x1InnerWrap_size; + BYTE *r1InnerWrapKey; /* for XOR decryption */ + BYTE *o1Oaep; + TPM_KEY newSrk; + TPM_STORE_ASYMKEY srk_store_asymkey; + TPM_STORE_BUFFER asym_sbuffer; + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back data */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + /* Vendor specific arguments */ + + printf("TPM_Process_LoadMaintenanceArchive: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&archive); /* freed @1 */ + TPM_Key_Init(&newSrk); /* freed @2 */ + x1InnerWrap = NULL; /* freed @3 */ + r1InnerWrapKey = NULL; /* freed @4 */ + o1Oaep = NULL; /* freed @5 */ + TPM_StoreAsymkey_Init(&srk_store_asymkey); /* freed @6 */ + TPM_Sbuffer_Init(&asym_sbuffer); /* freed @7 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get Vendor specific arguments */ + if (returnCode == TPM_SUCCESS) { + /* NOTE TPM_CreateMaintenanceArchive sends a TPM_SIZED_BUFFER archive. */ + returnCode = TPM_SizedBuffer_Load(&archive, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadMaintenanceArchive: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the TPM Owner's AuthData */ + /* Upon authorization being confirmed this command does the following: */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Validate that the maintenance information was sent by the TPME. The validation mechanism + MUST use a strength of function that is at least the same strength of function as a digital + signature performed using a 2048 bit RSA key. */ + /* NOTE SRK is 2048 bits minimum */ + /* 3. The packet MUST contain m2 as defined in Section 12.1 */ + /* The TPM_SIZED_BUFFER archive contains a TPM_KEY with a TPM_MIGRATE_ASYMKEY that will become + the new SRK */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadMaintenanceArchive: Deserializing TPM_KEY parameter\n"); + stream = archive.buffer; + stream_size = archive.size; + returnCode = TPM_Key_Load(&newSrk, &stream, &stream_size); + } + /* decrypt the TPM_KEY -> encData to x1 using the current SRK */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadMaintenanceArchive: Decrypting TPM_KEY -> encData with SRK\n"); + returnCode = TPM_RSAPrivateDecryptMalloc(&x1InnerWrap, + &x1InnerWrap_size, + newSrk.encData.buffer, + newSrk.encData.size, + &(tpm_state->tpm_permanent_data.srk)); + } + /* allocate memory for r1 based on x1 XOR encrypted data */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_LoadMaintenanceArchive: x1", x1InnerWrap); + printf("TPM_Process_LoadMaintenanceArchive: x1 size %u\n", x1InnerWrap_size); + returnCode = TPM_Malloc(&r1InnerWrapKey, x1InnerWrap_size); + } + /* allocate memory for o1 based on x1 XOR encrypted data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&o1Oaep, x1InnerWrap_size); + } + /* generate the XOR encryption secret from the ownerAuth */ + /* NOTE: This does not yet support a supplied random number as the inner wrapper key */ + if (returnCode == TPM_SUCCESS) { + TPM_MGF1(r1InnerWrapKey, /* unsigned char *mask */ + x1InnerWrap_size, /* long len */ + tpm_state->tpm_permanent_data.ownerAuth, /* const unsigned char *seed */ + TPM_SECRET_SIZE); /* long seedlen */ + TPM_PrintFour("TPM_Process_LoadMaintenanceArchive: r1 -", r1InnerWrapKey); + /* decrypt x1 to o1 using XOR encryption secret */ + printf("TPM_Process_LoadMaintenanceArchive: XOR Decrypting TPM_KEY SRK parameter\n"); + TPM_XOR(o1Oaep, x1InnerWrap, r1InnerWrapKey, x1InnerWrap_size); + TPM_PrintFour("TPM_Process_LoadMaintenanceArchive: o1 -", o1Oaep); + } + /* convert o1 to TPM_STORE_ASYMKEY */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StoreAsymkey_LoadO1(&srk_store_asymkey, o1Oaep, x1InnerWrap_size); + } + /* TPM1 tpmProof comes in as TPM_STORE_ASYMKEY -> usageAuth */ + /* TPM1 ownerAuth comes in as TPM_STORE_ASYMKEY -> migrationAuth (from pHash) */ + /* 4. Ensure that only the target TPM can interpret the maintenance packet. The protection + mechanism MUST use a strength of function that is at least the same strength of function as a + digital signature performed using a 2048 bit RSA key. */ + /* 5. Execute the actions of TPM_OwnerClear. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OwnerClearCommon(tpm_state, + FALSE); /* don't erase NVRAM with D bit set */ + writeAllNV1 = TRUE; + } + if (returnCode == TPM_SUCCESS) { + /* 6. Process the maintenance information */ + /* a. Update the SRK */ + /* i. Set the SRK usageAuth to be the same as the TPM source owner's AuthData */ + /* NOTE The source srk.usageAuth was lost, as usageAuth is used to transfer the tpmProof */ + TPM_Secret_Copy(srk_store_asymkey.usageAuth, srk_store_asymkey.migrationAuth); + /* b. Update TPM_PERMANENT_DATA -> tpmProof */ + TPM_Secret_Copy(tpm_state->tpm_permanent_data.tpmProof, srk_store_asymkey.usageAuth); + /* save a copy of the HMAC key for the response before invalidating */ + TPM_Secret_Copy(saveKey, *hmacKey); + /* c. Update TPM_PERMANENT_DATA -> ownerAuth */ + TPM_Secret_Copy(tpm_state->tpm_permanent_data.ownerAuth, srk_store_asymkey.migrationAuth); + /* serialize the TPM_STORE_ASYMKEY object */ + returnCode = TPM_StoreAsymkey_Store(&asym_sbuffer, FALSE, &srk_store_asymkey); + } + /* copy back to the new srk encData (clear text for SRK) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(newSrk.encData), &asym_sbuffer); + } + if (returnCode == TPM_SUCCESS) { + /* free old SRK resources */ + TPM_Key_Delete(&(tpm_state->tpm_permanent_data.srk)); + /* Copy new SRK to TPM_PERMANENT_DATA -> srk */ + /* This copies the basic TPM_KEY, but not the TPM_STORE_ASYMKEY cache */ + returnCode = TPM_Key_Copy(&(tpm_state->tpm_permanent_data.srk), &newSrk, + TRUE); /* copy encData */ + } + /* Recreate the TPM_STORE_ASYMKEY cache */ + if (returnCode == TPM_SUCCESS) { + stream = newSrk.encData.buffer; + stream_size = newSrk.encData.size; + returnCode = TPM_Key_LoadStoreAsymKey(&(tpm_state->tpm_permanent_data.srk), FALSE, + &stream, &stream_size); + } + /* 7. Set TPM_PERMANENT_FLAGS -> maintenanceDone to TRUE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadMaintenanceArchive: Set maintenanceDone\n"); + TPM_SetCapability_Flag(&writeAllNV2, /* altered */ + &(tpm_state->tpm_permanent_flags.maintenanceDone), /* flag */ + TRUE); /* value */ + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + (TPM_BOOL)(writeAllNV1 || writeAllNV2), + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadMaintenanceArchive: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + saveKey, /* the original owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&archive); /* @1 */ + TPM_Key_Delete(&newSrk); /* @2 */ + free(x1InnerWrap); /* @3 */ + free(r1InnerWrapKey); /* @4 */ + free(o1Oaep); /* @5 */ + TPM_StoreAsymkey_Delete(&srk_store_asymkey); /* @6 */ + TPM_Sbuffer_Delete(&asym_sbuffer); /* @7 */ + return rcf; +} + +/* 12.3 TPM_KillMaintenanceFeature rev 87 + + 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 not allow the + use of the maintenance feature. + + At the discretion of the Owner, it should be possible to kill the maintenance feature in such a + way that the only way to recover maintainability of the platform would be to wipe out the root + keys. This feature is mandatory in any TPM that implements the maintenance feature. +*/ + +TPM_RESULT TPM_Process_KillMaintenanceFeature(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth.*/ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_KillMaintenanceFeature: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_KillMaintenanceFeature: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the TPM Owner AuthData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Set the TPM_PERMANENT_FLAGS.allowMaintenance flag to FALSE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_KillMaintenanceFeature: Clear allowMaintenance\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.allowMaintenance), /* flag */ + FALSE); /* value */ + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_KillMaintenanceFeature: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 12.4 TPM_LoadManuMaintPub rev 96 + + The LoadManuMaintPub command loads the manufacturer's public key for use in the maintenance + process. The command installs ManuMaintPub in PERMANENT data storage inside a TPM. Maintenance + enables duplication of non-migratory data in protected storage. There is therefore a security + hole if a platform is shipped before the maintenance public key has been installed in a TPM. + + The command is expected to be used before installation of a TPM Owner or any key in TPM protected + storage. It therefore does not use authorization. + + The pubKey MUST specify an algorithm whose strength is not less than the RSA algorithm with 2048 + bit keys. + + pubKey SHOULD unambiguously identify the entity that will perform the maintenance process with + the TPM Owner. + + TPM_PERMANENT_DATA -> manuMaintPub SHALL exist in a TPM-shielded location, only. + + If an entity (Platform Entity) does not support the maintenance process but issues a platform + credential for a platform containing a TPM that supports the maintenance process, the value of + TPM_PERMANENT_DATA -> manuMaintPub MUST be set to zero before the platform leaves the entity's + control. +*/ + +TPM_RESULT TPM_Process_LoadManuMaintPub(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NONCE antiReplay; /* AntiReplay and validation nonce */ + TPM_PUBKEY pubKey; /* The public key of the manufacturer to be in use for maintenance + */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport session */ + TPM_STORE_BUFFER pubKeySerial; /* serialization for checksum calculation */ + const unsigned char *pubKeyBuffer; + uint32_t pubKeyLength; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST checksum; /* Digest of pubKey and antiReplay */ + + printf("TPM_Process_LoadManuMaintPub: Ordinal Entry\n"); + TPM_Pubkey_Init(&pubKey); /* freed @1 */ + TPM_Sbuffer_Init(&pubKeySerial); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get pubKey parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Pubkey_Load(&pubKey, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadManuMaintPub: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* The first valid TPM_LoadManuMaintPub command received by a TPM SHALL */ + if (returnCode == TPM_SUCCESS) { + if (!tpm_state->tpm_permanent_data.allowLoadMaintPub) { + printf("TPM_Process_LoadManuMaintPub: Error, command already run\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* The pubKey MUST specify an algorithm whose strength is not less than the RSA algorithm with + 2048 bit keys. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_CheckProperties(&(pubKey.algorithmParms), /* TPM_KEY_PARMS */ + TPM_KEY_STORAGE, /* TPM_KEY_USAGE */ + 2048, /* required, in bits */ + TRUE); /* FIPS */ + } + /* 1. Store the parameter pubKey as TPM_PERMANENT_DATA -> manuMaintPub. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Pubkey_Copy(&(tpm_state->tpm_permanent_data.manuMaintPub), + &pubKey); + writeAllNV = TRUE; + } + /* 2. Set checksum to SHA-1 of (pubkey || antiReplay) */ + if (returnCode == TPM_SUCCESS) { + /* serialize pubkey */ + returnCode = TPM_Pubkey_Store(&pubKeySerial, &pubKey); + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_Get(&pubKeySerial, &pubKeyBuffer, &pubKeyLength); + /* create the checksum */ + returnCode = TPM_SHA1(checksum, + pubKeyLength, pubKeyBuffer, + sizeof(TPM_NONCE), antiReplay, + 0, NULL); + } + /* 4. Subsequent calls to TPM_LoadManuMaintPub SHALL return code TPM_DISABLED_CMD. */ + if (returnCode == TPM_SUCCESS) { + tpm_state->tpm_permanent_data.allowLoadMaintPub = FALSE; + } + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadManuMaintPub: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 3. Export the checksum */ + returnCode = TPM_Digest_Store(response, checksum); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Pubkey_Delete(&pubKey); /* @1 */ + TPM_Sbuffer_Delete(&pubKeySerial); /* @2 */ + return rcf; +} + +/* 12.5 TPM_ReadManuMaintPub rev 99 + + The ReadManuMaintPub command is used to check whether the manufacturer's public maintenance key + in a TPM has the expected value. This may be useful during the manufacture process. The command + returns a digest of the installed key, rather than the key itself. This hinders discovery of the + maintenance key, which may (or may not) be useful for manufacturer privacy. + + The command is expected to be used before installation of a TPM Owner or any key in TPM protected + storage. It therefore does not use authorization. + + This command returns the hash of the antiReplay nonce and the previously loaded manufacturer's + maintenance public key. +*/ + +TPM_RESULT TPM_Process_ReadManuMaintPub(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NONCE antiReplay; /* AntiReplay and validation nonce */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_STORE_BUFFER pubKeySerial; /* serialization for checksum calculation */ + const unsigned char *pubKeyBuffer; + uint32_t pubKeyLength; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_DIGEST checksum; /* Digest of pubKey and antiReplay */ + + printf("TPM_Process_ReadManuMaintPub: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubKeySerial); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReadManuMaintPub: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Create "checksum" by concatenating data to form (TPM_PERMANENT_DATA -> manuMaintPub + || antiReplay) and passing the concatenated data through SHA-1. */ + if (returnCode == TPM_SUCCESS) { + /* serialize pubkey */ + returnCode = TPM_Pubkey_Store(&pubKeySerial, &(tpm_state->tpm_permanent_data.manuMaintPub)); + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_Get(&pubKeySerial, &pubKeyBuffer, &pubKeyLength); + /* create the checksum */ + returnCode = TPM_SHA1(checksum, + pubKeyLength, pubKeyBuffer, + sizeof(TPM_NONCE), antiReplay, + 0, NULL); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReadManuMaintPub: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 2. Export the checksum */ + returnCode = TPM_Digest_Store(response, checksum); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubKeySerial); /* @1 */ + return rcf; +} + +#endif diff --git a/src/tpm_maint.h b/src/tpm_maint.h new file mode 100644 index 00000000..f26f084b --- /dev/null +++ b/src/tpm_maint.h @@ -0,0 +1,89 @@ +/********************************************************************************/ +/* */ +/* Maintenance Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_maint.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_MAINT_H +#define TPM_MAINT_H + +#include "tpm_types.h" +#include "tpm_global.h" + + + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_CreateMaintenanceArchive(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_LoadMaintenanceArchive(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_KillMaintenanceFeature(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_LoadManuMaintPub(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ReadManuMaintPub(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + +#endif diff --git a/src/tpm_memory.c b/src/tpm_memory.c new file mode 100644 index 00000000..5bfa4f18 --- /dev/null +++ b/src/tpm_memory.c @@ -0,0 +1,131 @@ +/********************************************************************************/ +/* */ +/* TPM Memory Allocation */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_memory.c 4609 2011-08-26 19:27:38Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_constants.h" +#include "tpm_debug.h" +#include "tpm_error.h" + +#include "tpm_memory.h" + +/* TPM_Malloc() is a general purpose wrapper around malloc() + */ + +TPM_RESULT TPM_Malloc(unsigned char **buffer, uint32_t size) +{ + TPM_RESULT rc = 0; + + /* assertion test. The coding style requires that all allocated pointers are initialized to + NULL. A non-NULL value indicates either a missing initialization or a pointer reuse (a + memory leak). */ + if (rc == 0) { + if (*buffer != NULL) { + printf("TPM_Malloc: Error (fatal), *buffer %p should be NULL before malloc\n", *buffer); + rc = TPM_FAIL; + } + } + /* verify that the size is not "too large" */ + if (rc == 0) { + if (size > TPM_ALLOC_MAX) { + printf("TPM_Malloc: Error, size %u greater than maximum allowed\n", size); + rc = TPM_SIZE; + } + } + /* verify that the size is not 0, this would be implementation defined and should never occur */ + if (rc == 0) { + if (size == 0) { + printf("TPM_Malloc: Error (fatal), size is zero\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + *buffer = malloc(size); + if (*buffer == NULL) { + printf("TPM_Malloc: Error allocating %u bytes\n", size); + rc = TPM_SIZE; + } + } + return rc; +} + +/* TPM_Realloc() is a general purpose wrapper around realloc() + */ + +TPM_RESULT TPM_Realloc(unsigned char **buffer, + uint32_t size) +{ + TPM_RESULT rc = 0; + unsigned char *tmpptr = NULL; + + /* verify that the size is not "too large" */ + if (rc == 0) { + if (size > TPM_ALLOC_MAX) { + printf("TPM_Realloc: Error, size %u greater than maximum allowed\n", size); + rc = TPM_SIZE; + } + } + if (rc == 0) { + tmpptr = realloc(*buffer, size); + if (tmpptr == NULL) { + printf("TPM_Realloc: Error reallocating %u bytes\n", size); + rc = TPM_SIZE; + } + } + if (rc == 0) { + *buffer = tmpptr; + } + return rc; +} + +/* TPM_Free() is the companion to the TPM allocation functions. It is not used internally. The + intent is for use by an application that links directly to a TPM and wants to free memory + allocated by the TPM. + + It avoids a potential problem if the application uses a different allocation library, perhaps one + that wraps the functions to detect overflows or memory leaks. +*/ + +void TPM_Free(unsigned char *buffer) +{ + free(buffer); + return; +} + diff --git a/src/tpm_migration.c b/src/tpm_migration.c new file mode 100644 index 00000000..03111a45 --- /dev/null +++ b/src/tpm_migration.c @@ -0,0 +1,4287 @@ +/********************************************************************************/ +/* */ +/* TPM Migration */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_migration.c 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_secret.h" + +#include "tpm_migration.h" + +/* + TPM_MIGRATIONKEYAUTH +*/ + +/* TPM_Migrationkeyauth_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_Migrationkeyauth_Init(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth) +{ + printf(" TPM_Migrationkeyauth_Init:\n"); + TPM_Pubkey_Init(&(tpm_migrationkeyauth->migrationKey)); + tpm_migrationkeyauth->migrationScheme = 0; + TPM_Digest_Init(tpm_migrationkeyauth->digest); + return; +} + +/* TPM_Migrationkeyauth_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_Migrationkeyauth_Init() + After use, call TPM_Migrationkeyauth_Delete() to free memory +*/ + +TPM_RESULT TPM_Migrationkeyauth_Load(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Migrationkeyauth_Load:\n"); + /* load migrationKey */ + if (rc == 0) { + rc = TPM_Pubkey_Load(&(tpm_migrationkeyauth->migrationKey), stream, stream_size); + } + /* load migrationScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_migrationkeyauth->migrationScheme), stream, stream_size); + } + /* load digest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_migrationkeyauth->digest, stream, stream_size); + } + return rc; +} + +/* TPM_Migrationkeyauth_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_Migrationkeyauth_Store(TPM_STORE_BUFFER *sbuffer, + TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Migrationkeyauth_Store:\n"); + /* store migrationKey */ + if (rc == 0) { + rc = TPM_Pubkey_Store(sbuffer, &(tpm_migrationkeyauth->migrationKey)); + } + /* store migrationScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_migrationkeyauth->migrationScheme); + } + /* store digest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_migrationkeyauth->digest); + } + return rc; +} + +/* TPM_Migrationkeyauth_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_Migrationkeyauth_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_Migrationkeyauth_Delete(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth) +{ + printf(" TPM_Migrationkeyauth_Delete:\n"); + if (tpm_migrationkeyauth != NULL) { + TPM_Pubkey_Delete(&(tpm_migrationkeyauth->migrationKey)); + TPM_Migrationkeyauth_Init(tpm_migrationkeyauth); + } + return; +} + +/* + TPM_MSA_COMPOSITE +*/ + +/* TPM_MsaComposite_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_MsaComposite_Init(TPM_MSA_COMPOSITE *tpm_msa_composite) +{ + printf(" TPM_MsaComposite_Init:\n"); + tpm_msa_composite->MSAlist = 0; + tpm_msa_composite->migAuthDigest = NULL; + return; +} + +/* TPM_MsaComposite_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_MsaComposite_Init() + After use, call TPM_MsaComposite_Delete() to free memory +*/ + +TPM_RESULT TPM_MsaComposite_Load(TPM_MSA_COMPOSITE *tpm_msa_composite, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t i; + + printf(" TPM_MsaComposite_Load:\n"); + /* load MSAlist */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_msa_composite->MSAlist), stream, stream_size); + } + /* MSAlist MUST be one (1) or greater. */ + if (rc == 0) { + if (tpm_msa_composite->MSAlist == 0) { + printf("TPM_MsaComposite_Load: Error, MSAlist is zero\n"); + rc = TPM_INVALID_STRUCTURE; + } + } + /* FIXME add MSAlist limit */ + /* allocate memory for the migAuthDigest array */ + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)&(tpm_msa_composite->migAuthDigest), + (tpm_msa_composite->MSAlist) * TPM_DIGEST_SIZE); + } + /* load migAuthDigest array */ + for (i = 0 ; (rc == 0) && (i < tpm_msa_composite->MSAlist) ; i++) { + rc = TPM_Digest_Load(tpm_msa_composite->migAuthDigest[i], stream, stream_size); + } + return rc; +} + +/* TPM_MsaComposite_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_MsaComposite_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_MSA_COMPOSITE *tpm_msa_composite) +{ + TPM_RESULT rc = 0; + uint32_t i; + + printf(" TPM_MsaComposite_Store:\n"); + /* store MSAlist */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_msa_composite->MSAlist); + } + /* store migAuthDigest array */ + for (i = 0 ; (rc == 0) && (i < tpm_msa_composite->MSAlist) ; i++) { + rc = TPM_Digest_Store(sbuffer, tpm_msa_composite->migAuthDigest[i]); + } + return rc; +} + +/* TPM_MsaComposite_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_MsaComposite_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_MsaComposite_Delete(TPM_MSA_COMPOSITE *tpm_msa_composite) +{ + printf(" TPM_MsaComposite_Delete:\n"); + if (tpm_msa_composite != NULL) { + free(tpm_msa_composite->migAuthDigest); + TPM_MsaComposite_Init(tpm_msa_composite); + } + return; +} + +TPM_RESULT TPM_MsaComposite_CheckMigAuthDigest(TPM_DIGEST tpm_digest, /* value to check vs list */ + TPM_MSA_COMPOSITE *tpm_msa_composite) +{ + TPM_RESULT rc = 0; + uint32_t n; /* count through msaList */ + TPM_BOOL match; + + printf(" TPM_MsaComposite_CheckMigAuthDigest:\n"); + for (n = 0 , match = FALSE ; (n < tpm_msa_composite->MSAlist) && !match ; n++) { + rc = TPM_Digest_Compare(tpm_digest, tpm_msa_composite->migAuthDigest[n]); + if (rc == 0) { + match = TRUE; + } + } + if (match) { + rc = TPM_SUCCESS; + } + else { + printf("TPM_MsaComposite_CheckMigAuthDigest: Error, no match to msaList\n"); + rc = TPM_MA_TICKET_SIGNATURE; + } + return rc; +} + +/* TPM_MsaComposite_CheckSigTicket() + + i. Verify that for one of the n=1 to n=(msaList -> MSAlist) values of msaList -> + migAuthDigest[n], sigTicket == HMAC (V1) using tpmProof as the secret where V1 is a + TPM_CMK_SIGTICKET structure such that: + + (1) V1 -> verKeyDigest = msaList -> migAuthDigest[n] + (2) V1 -> signedData = SHA1[restrictTicket] +*/ + +TPM_RESULT TPM_MsaComposite_CheckSigTicket(TPM_DIGEST sigTicket, /* expected HMAC */ + TPM_SECRET tpmProof, /* HMAC key */ + TPM_MSA_COMPOSITE *tpm_msa_composite, + TPM_CMK_SIGTICKET *tpm_cmk_sigticket) +{ + TPM_RESULT rc = 0; + uint32_t n; /* count through msaList */ + TPM_BOOL match; + TPM_STORE_BUFFER sbuffer; + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_MsaComposite_CheckSigTicket: TPM_MSA_COMPOSITE length %u\n", + tpm_msa_composite->MSAlist); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + for (n = 0 , match = FALSE ; + (rc == 0) && (n < tpm_msa_composite->MSAlist) && !match ; n++) { + + if (rc == 0) { + /* verKeyDigest = msaList -> migAuthDigest[n]. The rest of the structure is initialized + by the caller */ + TPM_PrintFour(" TPM_MsaComposite_CheckSigTicket: Checking migAuthDigest: ", + tpm_msa_composite->migAuthDigest[n]); + TPM_Digest_Copy(tpm_cmk_sigticket->verKeyDigest, tpm_msa_composite->migAuthDigest[n]); + /* serialize the TPM_CMK_SIGTICKET structure */ + TPM_Sbuffer_Clear(&sbuffer); /* reset pointers without free */ + rc = TPM_CmkSigticket_Store(&sbuffer, tpm_cmk_sigticket); + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + } + if (rc == 0) { + rc = TPM_HMAC_Check(&match, + sigTicket, /* expected */ + tpmProof, /* HMAC key*/ + length, buffer, /* TPM_CMK_SIGTICKET */ + 0, NULL); + } + } + if (rc == 0) { + if (!match) { + printf("TPM_MsaComposite_CheckSigTicket: Error, no match to msaList\n"); + rc = TPM_MA_TICKET_SIGNATURE; + } + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + TPM_CMK_AUTH +*/ + +/* TPM_CmkAuth_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CmkAuth_Init(TPM_CMK_AUTH *tpm_cmk_auth) +{ + printf(" TPM_CmkAuth_Init:\n"); + TPM_Digest_Init(tpm_cmk_auth->migrationAuthorityDigest); + TPM_Digest_Init(tpm_cmk_auth->destinationKeyDigest); + TPM_Digest_Init(tpm_cmk_auth->sourceKeyDigest); + return; +} + +/* TPM_CmkAuth_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CmkAuth_Init() + After use, call TPM_CmkAuth_Delete() to free memory +*/ + +TPM_RESULT TPM_CmkAuth_Load(TPM_CMK_AUTH *tpm_cmk_auth, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkAuth_Load:\n"); + /* load migrationAuthorityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_auth->migrationAuthorityDigest, stream, stream_size); + } + /* load destinationKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_auth->destinationKeyDigest, stream, stream_size); + } + /* load sourceKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_auth->sourceKeyDigest, stream, stream_size); + } + return rc; +} + +/* TPM_CmkAuth_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CmkAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_AUTH *tpm_cmk_auth) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkAuth_Store:\n"); + /* store migrationAuthorityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_auth->migrationAuthorityDigest); + } + /* store destinationKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_auth->destinationKeyDigest); + } + /* store sourceKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_auth->sourceKeyDigest); + } + return rc; +} + +/* TPM_CmkAuth_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CmkAuth_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CmkAuth_Delete(TPM_CMK_AUTH *tpm_cmk_auth) +{ + printf(" TPM_CmkAuth_Delete:\n"); + if (tpm_cmk_auth != NULL) { + TPM_CmkAuth_Init(tpm_cmk_auth); + } + return; +} + +/* + TPM_CMK_MIGAUTH +*/ + +/* TPM_CmkMigauth_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CmkMigauth_Init(TPM_CMK_MIGAUTH *tpm_cmk_migauth) +{ + printf(" TPM_CmkMigauth_Init:\n"); + TPM_Digest_Init(tpm_cmk_migauth->msaDigest); + TPM_Digest_Init(tpm_cmk_migauth->pubKeyDigest); + return; +} + +/* TPM_CmkMigauth_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CmkMigauth_Init() + After use, call TPM_CmkMigauth_Delete() to free memory +*/ + +TPM_RESULT TPM_CmkMigauth_Load(TPM_CMK_MIGAUTH *tpm_cmk_migauth, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkMigauth_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CMK_MIGAUTH, stream, stream_size); + } + /* load msaDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_migauth->msaDigest , stream, stream_size); + } + /* load pubKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_migauth->pubKeyDigest , stream, stream_size); + } + return rc; +} + +/* TPM_CmkMigauth_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CmkMigauth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_MIGAUTH *tpm_cmk_migauth) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkMigauth_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CMK_MIGAUTH); + } + /* store msaDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_migauth->msaDigest); + } + /* store pubKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_migauth->pubKeyDigest); + } + return rc; +} + +/* TPM_CmkMigauth_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CmkMigauth_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CmkMigauth_Delete(TPM_CMK_MIGAUTH *tpm_cmk_migauth) +{ + printf(" TPM_CmkMigauth_Delete:\n"); + if (tpm_cmk_migauth != NULL) { + TPM_CmkMigauth_Init(tpm_cmk_migauth); + } + return; +} + +/* TPM_CmkMigauth_CheckHMAC() checks an HMAC of a TPM_CMK_MIGAUTH object. + + It serializes the structure and HMAC's the result. The common function cannot be used because + 'tpm_hmac' is not part of the structure and cannot be NULL'ed. +*/ + +TPM_RESULT TPM_CmkMigauth_CheckHMAC(TPM_BOOL *valid, /* result */ + TPM_HMAC tpm_hmac, /* expected */ + TPM_SECRET tpm_hmac_key, /* key */ + TPM_CMK_MIGAUTH *tpm_cmk_migauth) /* data */ +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized TPM_CMK_MIGAUTH */ + + printf(" TPM_CmkMigauth_CheckHMAC:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* Serialize the TPM_CMK_MIGAUTH structure */ + if (rc == 0) { + rc = TPM_CmkMigauth_Store(&sbuffer, tpm_cmk_migauth); + } + /* verify the HMAC of the serialized structure */ + if (rc == 0) { + rc = TPM_HMAC_CheckSbuffer(valid, /* result */ + tpm_hmac, /* expected */ + tpm_hmac_key, /* key */ + &sbuffer); /* data stream */ + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + TPM_CMK_SIGTICKET +*/ + +/* TPM_CmkSigticket_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CmkSigticket_Init(TPM_CMK_SIGTICKET *tpm_cmk_sigticket) +{ + printf(" TPM_CmkSigticket_Init:\n"); + TPM_Digest_Init(tpm_cmk_sigticket->verKeyDigest); + TPM_Digest_Init(tpm_cmk_sigticket->signedData); + return; +} + +/* TPM_CmkSigticket_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CmkSigticket_Init() + After use, call TPM_CmkSigticket_Delete() to free memory +*/ + +TPM_RESULT TPM_CmkSigticket_Load(TPM_CMK_SIGTICKET *tpm_cmk_sigticket, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkSigticket_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CMK_SIGTICKET, stream, stream_size); + } + /* load verKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_sigticket->verKeyDigest , stream, stream_size); + } + /* load signedData */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_sigticket->signedData , stream, stream_size); + } + return rc; +} + +/* TPM_CmkSigticket_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CmkSigticket_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_SIGTICKET *tpm_cmk_sigticket) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkSigticket_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CMK_SIGTICKET); + } + /* store verKeyDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_sigticket->verKeyDigest); + } + /* store signedData */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_sigticket->signedData); + } + return rc; +} + +/* TPM_CmkSigticket_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CmkSigticket_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CmkSigticket_Delete(TPM_CMK_SIGTICKET *tpm_cmk_sigticket) +{ + printf(" TPM_CmkSigticket_Delete:\n"); + if (tpm_cmk_sigticket != NULL) { + TPM_CmkSigticket_Init(tpm_cmk_sigticket); + } + return; +} + +/* + TPM_CMK_MA_APPROVAL +*/ + +/* TPM_CmkMaApproval_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CmkMaApproval_Init(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval) +{ + printf(" TPM_CmkMaApproval_Init:\n"); + TPM_Digest_Init(tpm_cmk_ma_approval->migrationAuthorityDigest); + return; +} + +/* TPM_CmkMaApproval_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CmkMaApproval_Init() + After use, call TPM_CmkMaApproval_Delete() to free memory +*/ + +TPM_RESULT TPM_CmkMaApproval_Load(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkMaApproval_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CMK_MA_APPROVAL, stream, stream_size); + } + /* load migrationAuthorityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_cmk_ma_approval->migrationAuthorityDigest, stream, stream_size); + } + return rc; +} + +/* TPM_CmkMaApproval_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CmkMaApproval_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CmkMaApproval_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CMK_MA_APPROVAL); + } + /* store migrationAuthorityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_cmk_ma_approval->migrationAuthorityDigest); + } + return rc; +} + +/* TPM_CmkMaApproval_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CmkMaApproval_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CmkMaApproval_Delete(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval) +{ + printf(" TPM_CmkMaApproval_Delete:\n"); + if (tpm_cmk_ma_approval != NULL) { + TPM_CmkMaApproval_Init(tpm_cmk_ma_approval); + } + return; +} + +/* TPM_CmkMaApproval_CheckHMAC() generates an HMAC of a TPM_CMK_MIGAUTH object + + It serializes the structure and HMAC's the result.The common function cannot be used because + 'tpm_hmac' is not part of the structure and cannot be NULL'ed. +*/ + +TPM_RESULT TPM_CmkMaApproval_CheckHMAC(TPM_BOOL *valid, /* result */ + TPM_HMAC tpm_hmac, /* expected */ + TPM_SECRET tpm_hmac_key, /* key */ + TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval) /* data */ +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized TPM_CMK_MA_APPROVAL */ + + printf(" TPM_CmkMaApproval_CheckHMAC:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* Serialize the TPM_CMK_MA_APPROVAL structure */ + if (rc == 0) { + rc = TPM_CmkMaApproval_Store(&sbuffer, tpm_cmk_ma_approval); + } + /* verify the HMAC of the serialized structure */ + if (rc == 0) { + rc = TPM_HMAC_CheckSbuffer(valid, /* result */ + tpm_hmac, /* expected */ + tpm_hmac_key, /* key */ + &sbuffer); /* data stream */ + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + Processing functions +*/ + +/* TPM_CreateBlobCommon() does the steps common to TPM_CreateMigrationBlob and + TPM_CMK_CreateBlob + + It takes a TPM_STORE_ASYMKEY, and + - splits the TPM_STORE_PRIVKEY into k1 (20) and k2 (112) + - builds a TPM_MIGRATE_ASYMKEY using + 'payload_type' + TPM_STORE_ASYMKEY usageAuth, pubDataDigest + k2 as partPrivKey + - serializes the TPM_MIGRATE_ASYMKEY + - OAEP encode using + 'phash' + k1 as seed +*/ + +TPM_RESULT TPM_CreateBlobCommon(TPM_SIZED_BUFFER *outData, /* The modified, encrypted + entity. */ + TPM_STORE_ASYMKEY *d1AsymKey, + TPM_DIGEST pHash, /* for OAEP padding */ + TPM_PAYLOAD_TYPE payload_type, + TPM_SIZED_BUFFER *random, /* String used for xor encryption */ + TPM_PUBKEY *migrationKey) /* public key of the migration + facility */ +{ + TPM_RESULT rc = 0; + uint32_t o1_size; + BYTE *o1; + BYTE *r1; + BYTE *x1; + + printf("TPM_CreateBlobCommon:\n"); + o1 = NULL; /* freed @1 */ + r1 = NULL; /* freed @2 */ + x1 = NULL; /* freed @3 */ + if (rc == 0) { + TPM_StoreAsymkey_GetO1Size(&o1_size, d1AsymKey); + } + if (rc == 0) { + rc = TPM_Malloc(&o1, o1_size); + } + if (rc == 0) { + rc = TPM_Malloc(&r1, o1_size); + } + if (rc == 0) { + rc = TPM_Malloc(&x1, o1_size); + } + if (rc == 0) { + rc = TPM_StoreAsymkey_StoreO1(o1, + o1_size, + d1AsymKey, + pHash, + payload_type, + d1AsymKey->usageAuth); + } + /* NOTE Comments from TPM_CreateMigrationBlob rev 81 */ + /* d. Create r1 a random value from the TPM RNG. The size of r1 MUST be the size of o1. Return + r1 in the Random parameter. */ + if (rc == 0) { + rc = TPM_Random(r1, o1_size); + } + /* e. Create x1 by XOR of o1 with r1 */ + if (rc == 0) { + TPM_PrintFour("TPM_CreateBlobCommon: r1 -", r1); + TPM_XOR(x1, o1, r1, o1_size); + TPM_PrintFour("TPM_CreateBlobCommon: x1 -", x1); + /* f. Copy r1 into the output field "random".*/ + rc = TPM_SizedBuffer_Set(random, o1_size, r1); + } + /* g. Encrypt x1 with the migration public key included in migrationKeyAuth. */ + if (rc == 0) { + rc = TPM_RSAPublicEncrypt_Pubkey(outData, + x1, + o1_size, + migrationKey); + TPM_PrintFour("TPM_CreateBlobCommon: outData", outData->buffer); + } + free(o1); /* @1 */ + free(r1); /* @2 */ + free(x1); /* @3 */ + return rc; +} + +/* 11.1 TPM_CreateMigrationBlob rev 109 + + The TPM_CreateMigrationBlob command implements the first step in the process of moving a + migratable key to a new parent or platform. Execution of this command requires knowledge of the + migrationAuth field of the key to be migrated. + + Migrate mode is generally used to migrate keys from one TPM to another for backup, upgrade or to + clone a key on another platform. To do this, the TPM needs to create a data blob that another TPM + can deal with. This is done by loading in a backup public key that will be used by the TPM to + create a new data blob for a migratable key. + + The TPM Owner does the selection and authorization of migration public keys at any time prior to + the execution of TPM_CreateMigrationBlob by performing the TPM_AuthorizeMigrationKey command. + + IReWrap mode is used to directly move the key to a new parent (either on this platform or + another). The TPM simply re-encrypts the key using a new parent, and outputs a normal encrypted + element that can be subsequently used by a TPM_LoadKey command. + + TPM_CreateMigrationBlob implicitly cannot be used to migrate a non-migratory key. No explicit + check is required. Only the TPM knows tpmProof. Therefore it is impossible for the caller to + submit an authorization value equal to tpmProof and migrate a non-migratory key. +*/ + +TPM_RESULT TPM_Process_CreateMigrationBlob(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* Handle of the parent key that can decrypt encData. */ + TPM_MIGRATE_SCHEME migrationType; /* The migration type, either MIGRATE or REWRAP */ + TPM_MIGRATIONKEYAUTH migrationKeyAuth; /* Migration public key and its authorization + digest. */ + TPM_SIZED_BUFFER encData; /* The encrypted entity that is to be modified. */ + TPM_AUTHHANDLE parentAuthHandle; /* The authorization handle used for the parent key. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with + parentAuthHandle */ + TPM_BOOL continueAuthSession; /* Continue use flag for parent session */ + TPM_AUTHDATA parentAuth; /* Authorization HMAC key: parentKey.usageAuth. */ + TPM_AUTHHANDLE entityAuthHandle; /* The authorization handle used for the encrypted + entity. */ + TPM_NONCE entitynonceOdd; /* Nonce generated by system associated with + entityAuthHandle */ + TPM_BOOL continueEntitySession = TRUE; /* Continue use flag for entity session */ + TPM_AUTHDATA entityAuth; /* Authorization HMAC key: entity.migrationAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL parentAuthHandleValid = FALSE; + TPM_BOOL entityAuthHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *parent_auth_session_data = NULL; /* session data for + parentAuthHandle */ + TPM_AUTH_SESSION_DATA *entity_auth_session_data = NULL; /* session data for + entityAuthHandle */ + TPM_SECRET *hmacKey; + TPM_SECRET *entityHmacKey; + TPM_KEY *parentKey; + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + unsigned char *d1Decrypt; /* decryption of encData */ + uint32_t d1DecryptLength = 0; /* actual valid data */ + unsigned char *stream; /* for deserializing decrypted encData */ + uint32_t stream_size; + TPM_STORE_ASYMKEY d1AsymKey; /* structure from decrypted encData */ + TPM_STORE_BUFFER mka_sbuffer; /* serialized migrationKeyAuth */ + const unsigned char *mka_buffer; + uint32_t mka_length; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER random; /* String used for xor encryption */ + TPM_SIZED_BUFFER outData; /* The modified, encrypted entity. */ + + printf("TPM_Process_CreateMigrationBlob: Ordinal Entry\n"); + TPM_Migrationkeyauth_Init(&migrationKeyAuth); /* freed @1 */ + TPM_SizedBuffer_Init(&encData); /* freed @2 */ + TPM_SizedBuffer_Init(&random); /* freed @3 */ + TPM_SizedBuffer_Init(&outData); /* freed @4 */ + d1Decrypt = NULL; /* freed @5 */ + TPM_StoreAsymkey_Init(&d1AsymKey); /* freed @6 */ + TPM_Sbuffer_Init(&mka_sbuffer); /* freed @7 */ + /* + get inputs + */ + /* get parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get migrationType */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMigrationBlob: parentHandle %08x\n", parentHandle); + returnCode = TPM_Load16(&migrationType, &command, ¶mSize); + } + /* get migrationKeyAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Migrationkeyauth_Load(&migrationKeyAuth, &command, ¶mSize); + } + /* get encData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&encData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag21(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&parentAuthHandle, + &parentAuthHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_CreateMigrationBlob: parentAuthHandle %08x\n", parentAuthHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&entityAuthHandle, + &entityAuthHandleValid, + entitynonceOdd, + &continueEntitySession, + entityAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMigrationBlob: entityAuthHandle %08x\n", entityAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateMigrationBlob: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + parentAuthHandleValid = FALSE; + entityAuthHandleValid = FALSE; + } + /* + Processing + */ + /* The TPM does not check the PCR values when migrating values locked to a PCR. */ + /* get the key associated with parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* read-only, do not check PCR's */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get parentHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&parent_auth_session_data, + &hmacKey, + tpm_state, + parentAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate that parentAuth authorizes the use of the key pointed to by parentHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + parent_auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* if there is no parent authorization, check that the parent authDataUsage is TPM_AUTH_NEVER */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_CreateMigrationBlob: Error, parent key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 2. Validate that parentHandle -> keyUsage is TPM_KEY_STORAGE, if not return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_CreateMigrationBlob: Error, keyUsage %04hx is invalid\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Create d1 a TPM_STORE_ASYMKEY structure by decrypting encData using the key pointed to by + parentHandle. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMigrationBlob: Decrypting encData\n"); + /* decrypt with the parent key to a stream */ + returnCode = TPM_RSAPrivateDecryptMalloc(&d1Decrypt, /* decrypted data */ + &d1DecryptLength, /* actual size of d1 data */ + encData.buffer,/* encrypted data */ + encData.size, /* encrypted data size */ + parentKey); + } + /* deserialize the stream to a TPM_STORE_ASYMKEY d1AsymKey */ + if (returnCode == TPM_SUCCESS) { + stream = d1Decrypt; + stream_size = d1DecryptLength; + returnCode = TPM_StoreAsymkey_Load(&d1AsymKey, FALSE, + &stream, &stream_size, + NULL, /* TPM_KEY_PARMS */ + NULL); /* TPM_SIZED_BUFFER pubKey */ + } + /* a. Verify that d1 -> payload is TPM_PT_ASYM. */ + if (returnCode == TPM_SUCCESS) { + if (d1AsymKey.payload != TPM_PT_ASYM) { + printf("TPM_Process_CreateMigrationBlob: Error, bad payload %02x\n", + d1AsymKey.payload); + returnCode = TPM_BAD_MIGRATION; + } + } + /* 4. Validate that entityAuth authorizes the migration of d1. The validation MUST use d1 -> + migrationAuth as the secret. */ + /* get the second session data */ + /* The second authorisation session (using entityAuth) MUST be OIAP because OSAP does not have a + suitable entityType */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&entity_auth_session_data, + &entityHmacKey, + tpm_state, + entityAuthHandle, + TPM_PID_OIAP, + TPM_ET_KEYHANDLE, + ordinal, + NULL, + &(d1AsymKey.migrationAuth), + NULL); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Auth2data_Check(tpm_state, + *entityHmacKey, /* HMAC key */ + inParamDigest, + entity_auth_session_data, /* authorization session */ + entitynonceOdd, /* Nonce generated by system + associated with authHandle */ + continueEntitySession, + entityAuth); /* Authorization digest for input */ + } + /* 5. Validate that migrationKeyAuth -> digest is the SHA-1 hash of (migrationKeyAuth -> + migrationKey || migrationKeyAuth -> migrationScheme || TPM_PERMANENT_DATA -> tpmProof). */ + /* first serialize the TPM_PUBKEY migrationKeyAuth -> migrationKey */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMigrationBlob: Verifying migrationKeyAuth\n"); + returnCode = TPM_Pubkey_Store(&mka_sbuffer, &(migrationKeyAuth.migrationKey)); + } + if (returnCode == TPM_SUCCESS) { + /* get the serialization result */ + TPM_Sbuffer_Get(&mka_sbuffer, &mka_buffer, &mka_length); + /* compare to migrationKeyAuth -> digest */ + returnCode = TPM_SHA1_Check(migrationKeyAuth.digest, + mka_length, mka_buffer, /* serialized migrationKey */ + sizeof(TPM_MIGRATE_SCHEME), &(migrationKeyAuth.migrationScheme), + TPM_SECRET_SIZE, tpm_state->tpm_permanent_data.tpmProof, + 0, NULL); + } + /* 6. If migrationType == TPM_MS_MIGRATE the TPM SHALL perform the following actions: */ + if ((returnCode == TPM_SUCCESS) && (migrationType == TPM_MS_MIGRATE)) { + printf("TPM_Process_CreateMigrationBlob: migrationType TPM_MS_MIGRATE\n"); + /* a. Build two byte arrays, K1 and K2: */ + /* i. K1 = d1.privKey[0..19] (d1.privKey.keyLength + 16 bytes of d1.privKey.key), sizeof(K1) + = 20 */ + /* ii. K2 = d1.privKey[20..131] (position 16-127 of TPM_STORE_ASYMKEY. privKey.key) + (position 16-127 of d1 . privKey.key), sizeof(K2) = 112 */ + /* b. Build M1 a TPM_MIGRATE_ASYMKEY structure */ + /* i. TPM_MIGRATE_ASYMKEY.payload = TPM_PT_MIGRATE */ + /* ii. TPM_MIGRATE_ASYMKEY.usageAuth = d1.usageAuth */ + /* iii. TPM_MIGRATE_ASYMKEY.pubDataDigest = d1.pubDataDigest */ + /* iv. TPM_MIGRATE_ASYMKEY.partPrivKeyLen = 112 - 127. */ + /* v. TPM_MIGRATE_ASYMKEY.partPrivKey = K2 */ + /* c. Create o1 (which SHALL be 198 bytes for a 2048 bit RSA key) by performing the OAEP + encoding of m using OAEP parameters of */ + /* i. m = M1 the TPM_MIGRATE_ASYMKEY structure */ + /* ii. pHash = d1->migrationAuth */ + /* iii. seed = s1 = K1 */ + /* d. Create r1 a random value from the TPM RNG. The size of r1 MUST be the size of + o1. Return r1 in the Random parameter. */ + /* e. Create x1 by XOR of o1 with r1*/ + /* f. Copy r1 into the output field "random".*/ + /* g. Encrypt x1 with the migration public key included in migrationKeyAuth.*/ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CreateBlobCommon(&outData, /* output */ + &d1AsymKey, /* TPM_STORE_ASYMKEY */ + d1AsymKey.migrationAuth, /* pHash */ + TPM_PT_MIGRATE, /* payload type */ + &random, /* string for XOR encryption */ + &(migrationKeyAuth.migrationKey)); /* TPM_PUBKEY */ + } + } + /* 7. If migrationType == TPM_MS_REWRAP the TPM SHALL perform the following actions: */ + else if ((returnCode == TPM_SUCCESS) && (migrationType == TPM_MS_REWRAP)) { + printf("TPM_Process_CreateMigrationBlob: migrationType TPM_MS_REWRAP\n"); + /* a. Rewrap the key using the public key in migrationKeyAuth, keeping the existing contents + of that key. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPublicEncrypt_Pubkey(&outData, + d1Decrypt, /* decrypted encData parameter */ + d1DecryptLength, + &(migrationKeyAuth.migrationKey)); + } + /* b. Set randomSize to 0 in the output parameter array */ + /* NOTE Done by TPM_SizedBuffer_Init() */ + } + /* 8. Else */ + /* a. Return TPM_BAD_PARAMETER */ + else if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateMigrationBlob: Error, illegal migrationType %04hx\n", + migrationType); + returnCode = TPM_BAD_PARAMETER; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateMigrationBlob: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return random */ + returnCode = TPM_SizedBuffer_Store(response, &random); + } + if (returnCode == TPM_SUCCESS) { + /* return outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + parent_auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *entityHmacKey, /* HMAC key */ + entity_auth_session_data, + outParamDigest, + entitynonceOdd, + continueEntitySession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) + && parentAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, + parentAuthHandle); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueEntitySession) && + entityAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, + entityAuthHandle); + } + /* + cleanup + */ + TPM_Migrationkeyauth_Delete(&migrationKeyAuth); /* @1 */ + TPM_SizedBuffer_Delete(&encData); /* @2 */ + TPM_SizedBuffer_Delete(&random); /* @3 */ + TPM_SizedBuffer_Delete(&outData); /* @4 */ + free(d1Decrypt); /* @5 */ + TPM_StoreAsymkey_Delete(&d1AsymKey); /* @6 */ + TPM_Sbuffer_Delete(&mka_sbuffer); /* @7 */ + return rcf; +} + + + +/* 11.2 TPM_ConvertMigrationBlob rev 87 + + 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. The migration of the associated public keys is + not specified by TPM because they are not security sensitive. Migration of the associated public + keys may be specified in a platform specific specification. A TPM_KEY structure must be recreated + before the migrated key can be used by the target TPM in a LoadKey command. +*/ + +/* The relationship between Create and Convert parameters are: + + Create: k1 || k2 = privKey + m = TPM_MIGRATE_ASYMKEY, partPrivKey = k2 + o1 = OAEP (m), seed = k1 + x1 = o1 ^ r1 + out = pub (x1) + Convert: + d1 = priv (in) + o1 = d1 ^ r1 + m1, seed = OAEP (o1) + k1 = seed || partPrivKey +*/ + +TPM_RESULT TPM_Process_ConvertMigrationBlob(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* Handle of a loaded key that can decrypt keys. */ + TPM_SIZED_BUFFER inData; /* The XOR'd and encrypted key */ + TPM_SIZED_BUFFER random; /* Random value used to hide key data. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization digest that authorizes the inputs and + the migration of the key in parentHandle. HMAC key: + parentKey.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_KEY *parentKey = NULL; /* the key specified by parentHandle */ + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + unsigned char *d1Decrypt; + uint32_t d1DecryptLength = 0; /* actual valid data */ + BYTE *o1Oaep; + TPM_STORE_ASYMKEY d2AsymKey; + TPM_STORE_BUFFER d2_sbuffer; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outData; /* The encrypted private key that can be loaded with + TPM_LoadKey */ + + printf("TPM_Process_ConvertMigrationBlob: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inData); /* freed @1 */ + TPM_SizedBuffer_Init(&random); /* freed @2 */ + TPM_SizedBuffer_Init(&outData); /* freed @3 */ + d1Decrypt = NULL; /* freed @4 */ + o1Oaep = NULL; /* freed @5 */ + TPM_StoreAsymkey_Init(&d2AsymKey); /* freed @6 */ + TPM_Sbuffer_Init(&d2_sbuffer); /* freed @7 */ + /* + get inputs + */ + /* get parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get inData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ConvertMigrationBlob: parentHandle %08x\n", parentHandle); + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + /* get random */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&random, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ConvertMigrationBlob: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* Verify that parentHandle points to a valid key. Get the TPM_KEY associated with parentHandle + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to decrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* check TPM_AUTH_DATA_USAGE authDataUsage */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_ConvertMigrationBlob: Error, parent key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get parentHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate the authorization to use the key in parentHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* 2. If the keyUsage field of the key referenced by parentHandle does not have the value + TPM_KEY_STORAGE, the TPM must return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_ConvertMigrationBlob: Error, " + "parentHandle -> keyUsage should be TPM_KEY_STORAGE, is %04x\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Create d1 by decrypting the inData area using the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ConvertMigrationBlob: Decrypting inData\n"); + TPM_PrintFour("TPM_Process_ConvertMigrationBlob: inData", inData.buffer); + returnCode = TPM_RSAPrivateDecryptMalloc(&d1Decrypt, /* decrypted data */ + &d1DecryptLength, /* actual size of d1 data */ + inData.buffer, /* encrypted data */ + inData.size, + parentKey); + } + /* the random input parameter must be the same length as the decrypted data */ + if (returnCode == TPM_SUCCESS) { + if (d1DecryptLength != random.size) { + printf("TPM_Process_ConvertMigrationBlob: Error " + "decrypt data length %u random size %u\n", + d1DecryptLength, random.size); + returnCode = TPM_BAD_PARAMETER; + } + } + /* allocate memory for o1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&o1Oaep, d1DecryptLength); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ConvertMigrationBlob: d1 length %u\n", d1DecryptLength); + TPM_PrintFour("TPM_Process_ConvertMigrationBlob: d1 -", d1Decrypt); + /* 4. Create o1 by XOR d1 and random parameter */ + TPM_XOR(o1Oaep, d1Decrypt, random.buffer, d1DecryptLength); + /* 5. Create m1 a TPM_MIGRATE_ASYMKEY structure, seed and pHash by OAEP decoding o1 */ + /* NOTE TPM_StoreAsymkey_LoadO1() extracts TPM_STORE_ASYMKEY from the OAEP encoded + TPM_MIGRATE_ASYMKEY. */ + returnCode = TPM_StoreAsymkey_LoadO1(&d2AsymKey, o1Oaep, d1DecryptLength); + } + /* 6. Create k1 by combining seed and the TPM_MIGRATE_ASYMKEY -> partPrivKey field */ + /* NOTE Done by TPM_StoreAsymkey_LoadO1 () */ + /* 7. Create d2 a TPM_STORE_ASYMKEY structure */ + if (returnCode == TPM_SUCCESS) { + /* a. Verify that m1 -> payload == TPM_PT_MIGRATE */ + /* NOTE TPM_StoreAsymkey_LoadO1() copied TPM_MIGRATE_ASYMKEY -> payload to TPM_STORE_ASYMKEY + -> payload */ + if (d2AsymKey.payload != TPM_PT_MIGRATE) { + printf("TPM_Process_ConvertMigrationBlob: Error, invalid payload %02x\n", + d2AsymKey.payload); + returnCode = TPM_BAD_MIGRATION; + } + } + if (returnCode == TPM_SUCCESS) { + /* b. Set d2 -> payload = TPM_PT_ASYM */ + d2AsymKey.payload = TPM_PT_ASYM; + /* c. Set d2 -> usageAuth to m1 -> usageAuth */ + /* d. Set d2 -> migrationAuth to pHash */ + /* e. Set d2 -> pubDataDigest to m1 -> pubDataDigest */ + /* f. Set d2 -> privKey field to k1 */ + /* NOTE Done by TPM_StoreAsymkey_LoadO1() */ + /* 9. Create outData using the key in parentHandle to perform the encryption */ + /* serialize d2key to d2 */ + returnCode = TPM_StoreAsymkey_Store(&d2_sbuffer, FALSE, &d2AsymKey); + } + /* encrypt d2 with parentKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPublicEncryptSbuffer_Key(&outData, &d2_sbuffer, parentKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ConvertMigrationBlob: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inData); /* @1 */ + TPM_SizedBuffer_Delete(&random); /* @2 */ + TPM_SizedBuffer_Delete(&outData); /* @3 */ + free(d1Decrypt); /* @4 */ + free(o1Oaep); /* @5 */ + TPM_StoreAsymkey_Delete(&d2AsymKey); /* @6 */ + TPM_Sbuffer_Delete(&d2_sbuffer); /* @7 */ + return rcf; +} + +/* 11.3 TPM_AuthorizeMigrationKey rev 114 + + 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. + + It is the responsibility of the TPM Owner to determine whether migrationKey is appropriate for + migration. The TPM checks just the cryptographic strength of migrationKey. +*/ + +TPM_RESULT TPM_Process_AuthorizeMigrationKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_MIGRATE_SCHEME migrationScheme; /* Type of migration operation that is to be permitted for + this key. */ + TPM_PUBKEY migrationKey; /* The public key to be authorized. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_RSA_KEY_PARMS *rsa_key_parms; /* for migrationKey */ + TPM_STORE_BUFFER sbuffer; + const unsigned char *buffer; + uint32_t length; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_MIGRATIONKEYAUTH outData; /* (f1) Returned public key and authorization digest. */ + + printf("TPM_Process_AuthorizeMigrationKey: Ordinal Entry\n"); + TPM_Pubkey_Init(&migrationKey); /* freed @1 */ + TPM_Migrationkeyauth_Init(&outData); /* freed @2 */ + TPM_Sbuffer_Init(&sbuffer); /* freed @3 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get migrationScheme */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&migrationScheme, &command, ¶mSize); + } + /* get migrationKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Pubkey_Load(&migrationKey, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_AuthorizeMigrationKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Check that the cryptographic strength of migrationKey is at least that of a 2048 bit RSA + key. If migrationKey is an RSA key, this means that migrationKey MUST be 2048 bits or greater + and MUST use the default exponent. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&rsa_key_parms, + &(migrationKey.algorithmParms)); + } + if (returnCode == TPM_SUCCESS) { + if (rsa_key_parms->keyLength < 2048) { + printf("TPM_Process_AuthorizeMigrationKey: Error, " + "migrationKey length %u less than 2048\n", + rsa_key_parms->keyLength); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParams_CheckDefaultExponent(&(rsa_key_parms->exponent)); + } + /* 2. Validate the AuthData to use the TPM by the TPM Owner */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 3. Create a f1 a TPM_MIGRATIONKEYAUTH structure */ + /* NOTE: This is outData */ + /* 4. Verify that migrationKey-> algorithmParms -> encScheme is TPM_ES_RSAESOAEP_SHA1_MGF1, and + return the error code TPM_INAPPROPRIATE_ENC if it is not */ + if (returnCode == TPM_SUCCESS) { + if (migrationKey.algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_Process_AuthorizeMigrationKey: Error, " + "migrationKey encScheme %04hx must be TPM_ES_RSAESOAEP_SHA1_MGF1\n", + migrationKey.algorithmParms.encScheme); + returnCode = TPM_INAPPROPRIATE_ENC; + } + } + /* 5. Set f1 -> migrationKey to the input migrationKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Pubkey_Copy(&(outData.migrationKey), &(migrationKey)); + } + if (returnCode == TPM_SUCCESS) { + /* 6. Set f1 -> migrationScheme to the input migrationScheme */ + outData.migrationScheme = migrationScheme; + /* 7. Create v1 by concatenating (migrationKey || migrationScheme || TPM_PERMANENT_DATA -> + tpmProof) */ + /* 8. Create h1 by performing a SHA-1 hash of v1 */ + /* first serialize the TPM_PUBKEY migrationKey */ + returnCode = TPM_Pubkey_Store(&sbuffer, &migrationKey); + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + /* 9. Set f1 -> digest to h1 */ + returnCode = TPM_SHA1(outData.digest, + length, buffer, /* serialized migrationKey */ + sizeof(TPM_MIGRATE_SCHEME), &(migrationScheme), + TPM_SECRET_SIZE, tpm_state->tpm_permanent_data.tpmProof, + 0, NULL); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_AuthorizeMigrationKey: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 10. Return f1 as outData */ + returnCode = TPM_Migrationkeyauth_Store(response, &outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_Pubkey_Delete(&migrationKey); /* @1 */ + TPM_Migrationkeyauth_Delete(&outData); /* @2 */ + TPM_Sbuffer_Delete(&sbuffer); /* @3 */ + return rcf; +} + +/* 11.4 TPM_MigrateKey rev 87 + + The TPM_MigrateKey command performs the function of a migration authority. + + The command is relatively simple; it just decrypts the input packet (coming from + TPM_CreateMigrationBlob or TPM_CMK_CreateBlob) and then re-encrypts it with the input public + key. The output of this command would then be sent to TPM_ConvertMigrationBlob or + TPM_CMK_ConvertMigration on the target TPM. + + TPM_MigrateKey does not make ANY assumptions about the contents of the encrypted blob. Since it + does not have the XOR string, it cannot actually determine much about the key that is being + migrated. + + This command exists to permit the TPM to be a migration authority. If used in this way, it is + expected that the physical security of the system containing the TPM and the AuthData value for + the MA key would be tightly controlled. + + To prevent the execution of this command using any other key as a parent key, this command works + only if keyUsage for maKeyHandle is TPM_KEY_MIGRATE. +*/ + +TPM_RESULT TPM_Process_MigrateKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE maKeyHandle; /* Handle of the key to be used to migrate the key. */ + TPM_PUBKEY pubKey; /* Public key to which the blob is to be migrated */ + TPM_SIZED_BUFFER inData; /* The input blob */ + + TPM_AUTHHANDLE maAuthHandle; /* The authorization session handle used for maKeyHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with certAuthHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA keyAuth; /* The authorization session digest for the inputs and key to be + signed. HMAC key: maKeyHandle.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL maAuthHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_KEY *maKey = NULL; /* the key specified by maKeyHandle */ + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; /* for maKey */ + TPM_SECRET *maKeyUsageAuth; + TPM_BOOL maPCRStatus; + uint32_t decrypt_data_size; /* resulting decrypted data size */ + BYTE *decrypt_data = NULL; /* The resulting decrypted data. */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outData; /* The re-encrypted blob */ + + printf("TPM_Process_MigrateKey: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inData); /* freed @1 */ + TPM_SizedBuffer_Init(&outData); /* freed @2 */ + TPM_Pubkey_Init(&pubKey); /* freed @4 */ + /* + get inputs + */ + /* get maKeyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&maKeyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pubKey */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MigrateKey: maKeyHandle %08x\n", maKeyHandle); + returnCode = TPM_Pubkey_Load(&pubKey, &command, ¶mSize); + } + /* get encData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&maAuthHandle, + &maAuthHandleValid, + nonceOdd, + &continueAuthSession, + keyAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_MigrateKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + maAuthHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate that keyAuth authorizes the use of the key pointed to by maKeyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&maKey, &maPCRStatus, tpm_state, maKeyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get maKeyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&maKeyUsageAuth, maKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_Process_MigrateKey: maAuthHandle %08x\n", maAuthHandle); + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + maAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + maKey, + maKeyUsageAuth, /* OIAP */ + maKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + keyAuth); /* Authorization digest for input */ + } + /* check TPM_AUTH_DATA_USAGE authDataUsage */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (maKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_MigrateKey: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 2. The TPM validates that the key pointed to by maKeyHandle has a key usage value of + TPM_KEY_MIGRATE, and that the allowed encryption scheme is TPM_ES_RSAESOAEP_SHA1_MGF1. */ + if (returnCode == TPM_SUCCESS) { + if (maKey->keyUsage != TPM_KEY_MIGRATE) { + printf("TPM_Process_MigrateKey: Error, keyUsage %04hx not TPM_KEY_MIGRATE\n", + maKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + else if (maKey->algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_Process_MigrateKey: Error, encScheme %04hx not TPM_ES_RSAESOAEP_SHA_MGF1\n", + maKey->algorithmParms.encScheme); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* 3. The TPM validates that pubKey is of a size supported by the TPM and that its size is + consistent with the input blob and maKeyHandle. */ + /* NOTE: Let the encryption step do this step */ + /* 4. The TPM decrypts inData and re-encrypts it using pubKey. */ + /* get the TPM_RSA_KEY_PARMS associated with maKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, &(maKey->algorithmParms)); + } + /* decrypt using maKey */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MigrateKey: Decrypt using maKey\n"); + returnCode = + TPM_RSAPrivateDecryptMalloc(&decrypt_data, /* decrypted data, freed @3 */ + &decrypt_data_size, /* actual size of decrypt data */ + inData.buffer, + inData.size, + maKey); + + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_MigrateKey: Encrypt using pubKey\n"); + returnCode = TPM_RSAPublicEncrypt_Pubkey(&outData, /* encrypted data */ + decrypt_data, + decrypt_data_size, + &pubKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_MigrateKey: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + maAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, maAuthHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inData); /* @1 */ + TPM_SizedBuffer_Delete(&outData); /* @2 */ + free(decrypt_data); /* @3 */ + TPM_Pubkey_Delete(&pubKey); /* @4 */ + return rcf; +} + +/* 11.7 TPM_CMK_CreateKey rev 114 + + The TPM_CMK_CreateKey command both generates and creates a secure storage bundle for asymmetric + keys whose migration is controlled by a migration authority. + + TPM_CMK_CreateKey is very similar to TPM_CreateWrapKey, but: (1) the resultant key must be a + migratable key and can be migrated only by TPM_CMK_CreateBlob; (2) the command is Owner + authorized via a ticket. + + TPM_CMK_CreateKey creates an otherwise normal migratable key except that (1) migrationAuth is an + HMAC of the migration authority and the new key's public key, signed by tpmProof (instead of + being tpmProof); (2) the migrationAuthority bit is set TRUE; (3) the payload type is + TPM_PT_MIGRATE_RESTRICTED. + + The migration-selection/migration authority is specified by passing in a public key (actually the + digests of one or more public keys, so more than one migration authority can be specified). +*/ + +TPM_RESULT TPM_Process_CMK_CreateKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* Handle of a loaded key that can perform key wrapping. */ + TPM_ENCAUTH dataUsageAuth; /* Encrypted usage authorization data for the key. */ + TPM_KEY keyInfo; /* Information about key to be created, pubkey.keyLength and + keyInfo.encData elements are 0. MUST be TPM_KEY12 */ + TPM_HMAC migrationAuthorityApproval;/* A ticket, created by the TPM Owner using + TPM_CMK_ApproveMA, approving a TPM_MSA_COMPOSITE + structure */ + TPM_DIGEST migrationAuthorityDigest;/* The digest of a TPM_MSA_COMPOSITE structure */ + + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parent key + authorization. Must be an OSAP session. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization session digest that authorizes the use + of the public key in parentHandle. HMAC key: + parentKey.usageAuth.*/ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for entityAuthHandle + */ + TPM_SECRET *hmacKey; + TPM_KEY *parentKey = NULL; /* the key specified by parentHandle */ + TPM_BOOL parentPCRStatus; + TPM_BOOL hmacValid; /* for migrationAuthorityApproval */ + TPM_SECRET du1DecryptAuth; + TPM_STORE_ASYMKEY *wrappedStoreAsymkey; /* substructure of wrappedKey */ + TPM_CMK_MA_APPROVAL m1CmkMaApproval; + TPM_CMK_MIGAUTH m2CmkMigauth; + int ver; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY wrappedKey; /* The TPM_KEY structure which includes the public and + encrypted private key. MUST be TPM_KEY12 */ + + printf("TPM_Process_CMK_CreateKey: Ordinal Entry\n"); + TPM_Key_Init(&keyInfo); /* freed @1 */ + TPM_Key_Init(&wrappedKey); /* freed @2 */ + TPM_CmkMaApproval_Init(&m1CmkMaApproval); /* freed @3 */ + TPM_CmkMigauth_Init(&m2CmkMigauth); /* freed @4 */ + /* + get inputs + */ + /* get parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get dataUsageAuth */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: parentHandle %08x\n", parentHandle); + returnCode = TPM_Authdata_Load(dataUsageAuth, &command, ¶mSize); + } + /* get keyInfo */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&keyInfo, &command, ¶mSize); + } + /* get migrationAuthorityApproval */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(migrationAuthorityApproval, &command, ¶mSize); + } + /* get migrationAuthorityDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(migrationAuthorityDigest, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_CreateKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the authorization to use the key pointed to by parentHandle. Return TPM_AUTHFAIL + on any error. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to encrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the session data */ + /* 2. Validate the session type for parentHandle is OSAP. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + NULL, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 3. If the TPM is not designed to create a key of the type requested in keyInfo, return the + error code TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_CheckProperties(&ver, &keyInfo, 0, + tpm_state->tpm_permanent_flags.FIPS); + printf("TPM_Process_CMK_CreateKey: key parameters v = %d\n", ver); + } + /* 4. Verify that parentHandle->keyUsage equals TPM_KEY_STORAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: Checking parent key\n"); + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_CMK_CreateKey: Error, parent keyUsage not TPM_KEY_STORAGE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Verify that parentHandle-> keyFlags-> migratable == FALSE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_CMK_CreateKey: Error, parent migratable\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. If keyInfo -> keyFlags -> migratable is FALSE then return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: Checking key flags\n"); + if (!(keyInfo.keyFlags & TPM_MIGRATABLE)) { + printf("TPM_Process_CMK_CreateKey: Error, keyInfo migratable is FALSE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 7. If keyInfo -> keyFlags -> migrateAuthority is FALSE , return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (!(keyInfo.keyFlags & TPM_MIGRATEAUTHORITY)) { + printf("TPM_Process_CMK_CreateKey: Error, keyInfo migrateauthority is FALSE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 8. Verify that the migration authority is authorized */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: Checking migration authority authorization\n"); + /* a. Create M1 a TPM_CMK_MA_APPROVAL structure */ + /* NOTE Done by TPM_CmkMaApproval_Init() */ + /* i. Set M1 ->migrationAuthorityDigest to migrationAuthorityDigest */ + TPM_Digest_Copy(m1CmkMaApproval.migrationAuthorityDigest, migrationAuthorityDigest); + /* b. Verify that migrationAuthorityApproval == HMAC(M1) using tpmProof as the secret and + return error TPM_MA_AUTHORITY on mismatch */ + returnCode = + TPM_CmkMaApproval_CheckHMAC(&hmacValid, + migrationAuthorityApproval, /* expect */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m1CmkMaApproval); + if (!hmacValid) { + printf("TPM_Process_CMK_CreateKey: Error, Invalid migrationAuthorityApproval\n"); + returnCode = TPM_MA_AUTHORITY; + } + } + /* 9. Validate key parameters */ + /* a. keyInfo -> keyUsage MUST NOT be TPM_KEY_IDENTITY or TPM_KEY_AUTHCHANGE. If it is, return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateKey: Checking key usage\n"); + if ((keyInfo.keyUsage == TPM_KEY_IDENTITY) || + (keyInfo.keyUsage == TPM_KEY_AUTHCHANGE)) { + printf("TPM_Process_CMK_CreateKey: Error, invalid keyInfo -> keyUsage %04hx\n", + keyInfo.keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 10. If TPM_PERMANENT_FLAGS -> FIPS is TRUE then */ + /* a. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS */ + /* b. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS */ + /* c. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return TPM_NOTFIPS */ + /* NOTE Done by TPM_Key_CheckProperties() */ + /* 11. If keyInfo -> keyUsage equals TPM_KEY_STORAGE or TPM_KEY_MIGRATE */ + /* a. algorithmID MUST be TPM_ALG_RSA */ + /* b. encScheme MUST be TPM_ES_RSAESOAEP_SHA1_MGF1 */ + /* c. sigScheme MUST be TPM_SS_NONE */ + /* d. key size MUST be 2048 */ + /* e. exponentSize MUST be 0 */ + /* NOTE Done by TPM_Key_CheckProperties() */ + /* 12. If keyInfo -> tag is NOT TPM_TAG_KEY12 return TPM_INVALID_STRUCTURE */ + if (returnCode == TPM_SUCCESS) { + if (ver != 2) { + printf("TPM_Process_CMK_CreateKey: Error, keyInfo must be TPM_TAG_KEY12\n"); + returnCode = TPM_INVALID_STRUCTURE; + } + } + /* 13. Map wrappedKey to a TPM_KEY12 structure */ + /* NOTE: Not required. TPM_KEY functions handle TPM_KEY12 subclass */ + /* 14. Create DU1 by decrypting dataUsageAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(du1DecryptAuth, + NULL, + dataUsageAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + if (returnCode == TPM_SUCCESS) { + /* 15. Set continueAuthSession to FALSE */ + continueAuthSession = FALSE; + /* 16. Generate asymmetric key according to algorithm information in keyInfo */ + /* 17. Fill in the wrappedKey structure with information from the newly generated key. */ + printf("TPM_Process_CMK_CreateKey: Generating key\n"); + returnCode = TPM_Key_GenerateRSA(&wrappedKey, + tpm_state, + parentKey, + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + ver, /* TPM_KEY12 */ + keyInfo.keyUsage, + keyInfo.keyFlags, + keyInfo.authDataUsage, /* TPM_AUTH_DATA_USAGE */ + &(keyInfo.algorithmParms), /* TPM_KEY_PARMS */ + keyInfo.tpm_pcr_info, /* TPM_PCR_INFO */ + keyInfo.tpm_pcr_info_long); /* TPM_PCR_INFO_LONG */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetStoreAsymkey(&wrappedStoreAsymkey, + &wrappedKey); + } + if (returnCode == TPM_SUCCESS) { + /* a. Set wrappedKey -> encData -> usageAuth to DU1 */ + TPM_Secret_Copy(wrappedStoreAsymkey->usageAuth, du1DecryptAuth); + /* b. Set wrappedKey -> encData -> payload to TPM_PT_MIGRATE_RESTRICTED */ + wrappedStoreAsymkey->payload = TPM_PT_MIGRATE_RESTRICTED; + /* c. Create thisPubKey, a TPM_PUBKEY structure containing wrappedKey's public key. */ + /* NOTE All that is really needed is its digest, which is calculated directly */ + } + if (returnCode == TPM_SUCCESS) { + /* d. Create M2 a TPM_CMK_MIGAUTH structure */ + /* NOTE Done by TPM_CmkMigauth_Init() */ + /* i. Set M2 -> msaDigest to migrationAuthorityDigest */ + TPM_Digest_Copy(m2CmkMigauth.msaDigest, migrationAuthorityDigest); + /* ii. Set M2 -> pubKeyDigest to SHA-1 (thisPubKey) */ + returnCode = TPM_Key_GeneratePubkeyDigest(m2CmkMigauth.pubKeyDigest, &wrappedKey); + /* e. Set wrappedKey -> encData -> migrationAuth equal to HMAC(M2), using tpmProof as the + shared secret */ + returnCode = TPM_HMAC_GenerateStructure + (wrappedStoreAsymkey->migrationAuth, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkMigauth, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_CmkMigauth_Store); /* store function */ + } + /* 18. If keyInfo->PCRInfoSize is non-zero */ + /* a. Set wrappedKey -> pcrInfo to a TPM_PCR_INFO_LONG structure */ + /* b. Set wrappedKey -> pcrInfo to keyInfo -> pcrInfo */ + /* b. Set wrappedKey -> digestAtCreation to the TPM_COMPOSITE_HASH indicated by + creationPCRSelection */ + /* c. Set wrappedKey -> localityAtCreation to TPM_STANY_FLAGS -> localityModifier */ + /* NOTE This is done during TPM_Key_GenerateRSA() */ + /* 19. Encrypt the private portions of the wrappedKey structure using the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GenerateEncData(&wrappedKey, parentKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_CreateKey: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 20. Return the newly generated key in the wrappedKey parameter */ + returnCode = TPM_Key_Store(response, &wrappedKey); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_Key_Delete(&keyInfo); /* @1 */ + TPM_Key_Delete(&wrappedKey); /* @2 */ + TPM_CmkMaApproval_Delete(&m1CmkMaApproval); /* @3 */ + TPM_CmkMigauth_Delete(&m2CmkMigauth); /* @4 */ + return rcf; +} + + +/* 11.5 TPM_CMK_CreateTicket rev 101 + + The TPM_verifySignature command uses a public key to verify the signature over a digest. + + TPM_verifySignature returns 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_Process_CMK_CreateTicket(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_PUBKEY verificationKey; /* The public key to be used to check signatureValue */ + TPM_DIGEST signedData; /* The data to be verified */ + TPM_SIZED_BUFFER signatureValue; /* The signatureValue to be verified */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest for inputs and owner. HMAC key: + ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_CMK_SIGTICKET m2CmkSigticket; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_HMAC sigTicket; /* Ticket that proves digest created on this TPM */ + + printf("TPM_Process_CMK_CreateTicket: Ordinal Entry\n"); + TPM_Pubkey_Init(&verificationKey); /* freed @1 */ + TPM_SizedBuffer_Init(&signatureValue); /* freed @2 */ + TPM_CmkSigticket_Init(&m2CmkSigticket); /* freed @3 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get verificationKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Pubkey_Load(&verificationKey, &command, ¶mSize); + } + /* get signedData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(signedData, &command, ¶mSize); + } + /* get signatureValue */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&signatureValue, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_CreateTicket: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the TPM Owner authorization to use the command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 2. Validate that the key type and algorithm are correct */ + /* a. Validate that verificationKey -> algorithmParms -> algorithmID == TPM_ALG_RSA */ + if (returnCode == TPM_SUCCESS) { + if (verificationKey.algorithmParms.algorithmID != TPM_ALG_RSA) { + printf("TPM_Process_CMK_CreateTicket: Error, incorrect algorithmID %08x\n", + verificationKey.algorithmParms.algorithmID); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* b. Validate that verificationKey -> algorithmParms ->encScheme == TPM_ES_NONE */ + if (returnCode == TPM_SUCCESS) { + if (verificationKey.algorithmParms.encScheme != TPM_ES_NONE) { + printf("TPM_Process_CMK_CreateTicket: Error, incorrect encScheme %04hx\n", + verificationKey.algorithmParms.encScheme); + returnCode = TPM_INAPPROPRIATE_ENC; + } + } + /* c. Validate that verificationKey ->algorithmParms ->sigScheme is + TPM_SS_RSASSAPKCS1v15_SHA1 or TPM_SS_RSASSAPKCS1v15_INFO */ + if (returnCode == TPM_SUCCESS) { + if ((verificationKey.algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (verificationKey.algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_CMK_CreateTicket: Error, incorrect sigScheme %04hx\n", + verificationKey.algorithmParms.sigScheme); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Use verificationKey to verify that signatureValue is a valid signature on signedData, and + return error TPM_BAD_SIGNATURE on mismatch */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateTicket: Verifying signature\n"); + returnCode = TPM_RSAVerifyH(&signatureValue, /* signature */ + signedData, /* data that was signed */ + TPM_DIGEST_SIZE, /* size of signed data */ + &verificationKey); /* TPM_PUBKEY public key */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateTicket: Error verifying signature\n"); + } + } + /* 4. Create M2 a TPM_CMK_SIGTICKET */ + /* NOTE Done by TPM_CmkSigticket_Init() */ + /* a. Set M2 -> verKeyDigest to the SHA-1 (verificationKey) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(m2CmkSigticket.verKeyDigest, &verificationKey, + (TPM_STORE_FUNCTION_T)TPM_Pubkey_Store); + } + if (returnCode == TPM_SUCCESS) { + /* b. Set M2 -> signedData to signedData */ + TPM_Digest_Copy(m2CmkSigticket.signedData, signedData); + /* 5. Set sigTicket = HMAC(M2) signed by using tpmProof as the secret */ + returnCode = TPM_HMAC_GenerateStructure + (sigTicket, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkSigticket, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_CmkSigticket_Store); /* store function */ + } + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_CreateTicket: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return sigTicket */ + returnCode = TPM_Digest_Store(response, sigTicket); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_Pubkey_Delete(&verificationKey); /* @1 */ + TPM_SizedBuffer_Delete(&signatureValue); /* @2 */ + TPM_CmkSigticket_Delete(&m2CmkSigticket); /* @3 */ + return rcf; +} + + +/* 11.9 TPM_CMK_CreateBlob rev 114 + + 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; (3) produces a wrapped + key blob whose migrationAuth is independent of tpmProof. + + If the destination (parent) public key is the MA, migration is implicitly permitted. Further + checks are required if the MA is not the destination (parent) public key, and merely selects a + migration destination: (1) sigTicket must prove that restrictTicket was signed by the MA; (2) + restrictTicket must vouch that the target public key is approved for migration to the destination + (parent) public key. (Obviously, this more complex method may also be used by an MA to approve + migration to that MA.) In both cases, the MA must be one of the MAs implicitly listed in the + migrationAuth of the target key-to-be-migrated. + + When the migrationType is TPM_MS_RESTRICT_MIGRATE, restrictTicket and sigTicket are unused. The + TPM may test that the corresponding sizes are zero, so the caller should set them to zero for + interoperability. +*/ + +TPM_RESULT TPM_Process_CMK_CreateBlob(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* Handle of the parent key that can decrypt encData. */ + TPM_MIGRATE_SCHEME migrationType; /* The migration type, either TPM_MS_RESTRICT_MIGRATE or + TPM_MS_RESTRICT_APPROVE + NOTE Never used */ + TPM_MIGRATIONKEYAUTH migrationKeyAuth; /* Migration public key and its authorization + session digest. */ + TPM_DIGEST pubSourceKeyDigest; /* The digest of the TPM_PUBKEY of the entity to be migrated + */ + TPM_SIZED_BUFFER msaListBuffer; /* One or more digests of public keys belonging to migration + authorities */ + TPM_SIZED_BUFFER restrictTicketBuffer; /* If migrationType is TPM_MS_RESTRICT_APPROVE, a + TPM_CMK_AUTH structure, containing the digests of + the public keys belonging to the Migration + Authority, the destination parent key and the + key-to-be-migrated. */ + TPM_SIZED_BUFFER sigTicketBuffer; /* If migrationType is TPM_MS_RESTRICT_APPROVE, a TPM_HMAC + structure, generated by the TPM, signaling a valid + signature over restrictTicket */ + TPM_SIZED_BUFFER encData; /* The encrypted entity that is to be modified. */ + TPM_AUTHHANDLE parentAuthHandle; /* The authorization handle used for the parent key. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with + parentAuthHandle */ + TPM_BOOL continueAuthSession; /* Continue use flag for parent session */ + TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and + parentHandle. HMAC key: parentKey.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_KEY *parentKey; + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + unsigned char *d1Decrypt; /* decryption of encData */ + uint32_t d1DecryptLength = 0; /* actual valid data */ + TPM_STORE_ASYMKEY d1AsymKey; /* structure from decrypted encData */ + unsigned char *stream; /* for deserializing structures */ + uint32_t stream_size; + TPM_STORE_BUFFER mka_sbuffer; /* serialized migrationKeyAuth.migrationKey */ + const unsigned char *mka_buffer; + uint32_t mka_length; + TPM_DIGEST migrationKeyDigest; /* digest of migrationKeyAuth.migrationKey */ + TPM_DIGEST pHash; + TPM_CMK_MIGAUTH m2CmkMigauth; + TPM_BOOL valid; + TPM_MSA_COMPOSITE msaList; + TPM_DIGEST sigTicket; + TPM_CMK_AUTH restrictTicket; + TPM_CMK_SIGTICKET v1CmkSigticket; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER random; /* String used for xor encryption */ + TPM_SIZED_BUFFER outData; /* The modified, encrypted entity. */ + + printf("TPM_Process_CMK_CreateBlob: Ordinal Entry\n"); + d1Decrypt = NULL; /* freed @1 */ + TPM_Migrationkeyauth_Init(&migrationKeyAuth); /* freed @2 */ + TPM_SizedBuffer_Init(&msaListBuffer); /* freed @3 */ + TPM_SizedBuffer_Init(&restrictTicketBuffer); /* freed @4 */ + TPM_SizedBuffer_Init(&sigTicketBuffer); /* freed @5 */ + TPM_SizedBuffer_Init(&encData); /* freed @6 */ + TPM_SizedBuffer_Init(&random); /* freed @7 */ + TPM_SizedBuffer_Init(&outData); /* freed @8 */ + TPM_Sbuffer_Init(&mka_sbuffer); /* freed @9 */ + TPM_StoreAsymkey_Init(&d1AsymKey); /* freed @10 */ + TPM_MsaComposite_Init(&msaList); /* freed @11 */ + TPM_CmkAuth_Init(&restrictTicket); /* freed @12 */ + TPM_CmkMigauth_Init(&m2CmkMigauth); /* freed @13 */ + TPM_CmkSigticket_Init(&v1CmkSigticket); /* freed @14 */ + /* + get inputs + */ + /* get parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get migrationType */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&migrationType, &command, ¶mSize); + } + /* get migrationKeyAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Migrationkeyauth_Load(&migrationKeyAuth, &command, ¶mSize); + } + /* get pubSourceKeyDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(pubSourceKeyDigest, &command, ¶mSize); + } + /* get msaListBuffer */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&msaListBuffer, &command, ¶mSize); + } + /* deserialize to msaList */ + if (returnCode == TPM_SUCCESS) { + stream = msaListBuffer.buffer; + stream_size = msaListBuffer.size; + returnCode = TPM_MsaComposite_Load(&msaList, &stream, &stream_size); + } + /* get restrictTicket */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&restrictTicketBuffer, &command, ¶mSize); + } + /* get sigTicket */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&sigTicketBuffer, &command, ¶mSize); + } + /* get encData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&encData, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&parentAuthHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_CreateBlob: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* + The TPM does not check the PCR values when migrating values locked to a PCR. */ + /* get the key associated with parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* do not check PCR's */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get parentHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + parentAuthHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate that parentAuth authorizes the use of the key pointed to by parentHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* 2.The TPM MAY verify that migrationType == migrationKeyAuth -> migrationScheme and return + TPM_BAD_MODE on error. + a.The TPM MAY ignore migrationType. */ + /* 3. Verify that parentHandle-> keyFlags-> migratable == FALSE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_CMK_CreateBlob: Error, parent migratable\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* Validate that parentHandle -> keyUsage is TPM_KEY_STORAGE, if not return the error code + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_CMK_CreateBlob: Error, keyUsage %04hx is invalid\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Create d1 by decrypting encData using the key pointed to by parentHandle. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: Decrypting encData\n"); + /* decrypt with the parent key to a stream */ + returnCode = TPM_RSAPrivateDecryptMalloc(&d1Decrypt, /* decrypted data, freed @1 */ + &d1DecryptLength, /* actual size of d1 data */ + encData.buffer,/* encrypted data */ + encData.size, /* encrypted data size */ + parentKey); + } + /* deserialize the stream to a TPM_STORE_ASYMKEY d1AsymKey */ + if (returnCode == TPM_SUCCESS) { + stream = d1Decrypt; + stream_size = d1DecryptLength; + returnCode = TPM_StoreAsymkey_Load(&d1AsymKey, FALSE, + &stream, &stream_size, + NULL, /* TPM_KEY_PARMS */ + NULL); /* TPM_SIZED_BUFFER pubKey */ + } + /* 5. Verify that the digest within migrationKeyAuth is legal for this TPM and public key */ + /* NOTE Presumably, this reverses the steps from TPM_AuthorizeMigrationKey */ + /* create h1 by concatenating (migrationKey || migrationScheme || TPM_PERMANENT_DATA -> + tpmProof) */ + /* first serialize the TPM_PUBKEY migrationKeyAuth -> migrationKey */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: Verifying migrationKeyAuth\n"); + returnCode = TPM_Pubkey_Store(&mka_sbuffer, &(migrationKeyAuth.migrationKey)); + } + if (returnCode == TPM_SUCCESS) { + /* get the serialization result */ + TPM_Sbuffer_Get(&mka_sbuffer, &mka_buffer, &mka_length); + /* then create the hash. tpmProof indicates that the input knew ownerAuth in + TPM_AuthorizeMigrationKey */ + /* compare to migrationKeyAuth -> digest */ + returnCode = TPM_SHA1_Check(migrationKeyAuth.digest, + mka_length, mka_buffer, /* serialized migrationKey */ + sizeof(TPM_MIGRATE_SCHEME), &(migrationKeyAuth.migrationScheme), + TPM_SECRET_SIZE, tpm_state->tpm_permanent_data.tpmProof, + 0, NULL); + } + /* 6. Verify that d1 -> payload == TPM_PT_MIGRATE_RESTRICTED or TPM_PT_MIGRATE_EXTERNAL */ + if (returnCode == TPM_SUCCESS) { + if ((d1AsymKey.payload != TPM_PT_MIGRATE_RESTRICTED) && + (d1AsymKey.payload != TPM_PT_MIGRATE_EXTERNAL)) { + printf("TPM_Process_CMK_CreateBlob: Error, invalid payload %02x\n", d1AsymKey.payload); + returnCode = TPM_INVALID_STRUCTURE; + } + } + /* 7. Verify that the migration authorities in msaList are authorized to migrate this key */ + /* a. Create M2 a TPM_CMK_MIGAUTH structure */ + /* NOTE Done by TPM_CmkMigauth_Init() */ + /* i. Set M2 -> msaDigest to SHA-1[msaList] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(m2CmkMigauth.msaDigest, &msaList, + (TPM_STORE_FUNCTION_T)TPM_MsaComposite_Store); + } + if (returnCode == TPM_SUCCESS) { + /* ii. Set M2 -> pubKeyDigest to pubSourceKeyDigest */ + TPM_Digest_Copy(m2CmkMigauth.pubKeyDigest, pubSourceKeyDigest); + /* b. Verify that d1 -> migrationAuth == HMAC(M2) using tpmProof as the secret and return + error TPM_MA_AUTHORITY on mismatch */ + returnCode = TPM_CmkMigauth_CheckHMAC(&valid, + d1AsymKey.migrationAuth, /* expected */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key*/ + &m2CmkMigauth); + if (!valid) { + printf("TPM_Process_CMK_CreateBlob: Error validating migrationAuth\n"); + returnCode = TPM_MA_AUTHORITY; + } + } + /* SHA-1[migrationKeyAuth -> migrationKey] is required below */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(migrationKeyDigest, + mka_length, mka_buffer, /* serialized migrationKey */ + 0, NULL); + } + /* 8. If migrationKeyAuth -> migrationScheme == TPM_MS_RESTRICT_MIGRATE */ + if ((returnCode == TPM_SUCCESS) && + (migrationKeyAuth.migrationScheme == TPM_MS_RESTRICT_MIGRATE)) { + /* a. Verify that intended migration destination is an MA: */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: migrationScheme is TPM_MS_RESTRICT_MIGRATE\n"); + /* i. For one of n=1 to n=(msaList -> MSAlist), verify that SHA-1[migrationKeyAuth -> + migrationKey] == msaList -> migAuthDigest[n] */ + returnCode = TPM_MsaComposite_CheckMigAuthDigest(migrationKeyDigest, &msaList); + } + /* b. Validate that the MA key is the correct type */ + /* i. Validate that migrationKeyAuth -> migrationKey -> algorithmParms -> algorithmID == + TPM_ALG_RSA */ + if (returnCode == TPM_SUCCESS) { + if (migrationKeyAuth.migrationKey.algorithmParms.algorithmID != TPM_ALG_RSA) { + printf("TPM_Process_CMK_CreateBlob: Error, algorithmID %08x not TPM_ALG_RSA\n", + migrationKeyAuth.migrationKey.algorithmParms.algorithmID); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* ii. Validate that migrationKeyAuth -> migrationKey -> algorithmParms -> encScheme is an + encryption scheme supported by the TPM */ + if (returnCode == TPM_SUCCESS) { + if (migrationKeyAuth.migrationKey.algorithmParms.encScheme != + TPM_ES_RSAESOAEP_SHA1_MGF1) { + + printf("TPM_Process_CMK_CreateBlob: Error, " + "encScheme %04hx not TPM_ES_RSAESOAEP_SHA1_MGF1\n", + migrationKeyAuth.migrationKey.algorithmParms.encScheme ); + returnCode = TPM_INAPPROPRIATE_ENC; + } + } + /* iii. Validate that migrationKeyAuth -> migrationKey ->algorithmParms -> sigScheme is + TPM_SS_NONE */ + if (returnCode == TPM_SUCCESS) { + if (migrationKeyAuth.migrationKey.algorithmParms.sigScheme != TPM_SS_NONE) { + printf("TPM_Process_CMK_CreateBlob: Error, sigScheme %04hx not TPM_SS_NONE\n", + migrationKeyAuth.migrationKey.algorithmParms.sigScheme); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* c. The TPM MAY validate that restrictTicketSize is zero. */ + if (returnCode == TPM_SUCCESS) { + if (restrictTicketBuffer.size != 0) { + printf("TPM_Process_CMK_CreateBlob: Error, " + "TPM_MS_RESTRICT_MIGRATE and restrictTicketSize %u not zero\n", + restrictTicketBuffer.size); + returnCode = TPM_BAD_PARAMETER; + } + } + /* d. The TPM MAY validate that sigTicketSize is zero. */ + if (returnCode == TPM_SUCCESS) { + if (sigTicketBuffer.size != 0) { + printf("TPM_Process_CMK_CreateBlob: Error, " + "TPM_MS_RESTRICT_MIGRATE and sigTicketSize %u not zero\n", + sigTicketBuffer.size); + returnCode = TPM_BAD_PARAMETER; + } + } + } + /* 9. If migrationKeyAuth -> migrationScheme == TPM_MS_RESTRICT_APPROVE */ + else if ((returnCode == TPM_SUCCESS) && + (migrationKeyAuth.migrationScheme == TPM_MS_RESTRICT_APPROVE)) { + /* a. Verify that the intended migration destination has been approved by the MSA: */ + /* i. Verify that for one of the n=1 to n=(msaList -> MSAlist) values of msaList -> + migAuthDigest[n], sigTicket == HMAC (V1) using tpmProof as the secret where V1 is a + TPM_CMK_SIGTICKET structure such that: */ + /* (1) V1 -> verKeyDigest = msaList -> migAuthDigest[n] */ + /* (2) V1 -> signedData = SHA-1[restrictTicket] */ + printf("TPM_Process_CMK_CreateBlob: migrationScheme is TPM_MS_RESTRICT_APPROVE_DOUBLE\n"); + /* deserialize the sigTicket TPM_HMAC */ + if (returnCode == TPM_SUCCESS) { + stream = sigTicketBuffer.buffer; + stream_size = sigTicketBuffer.size; + returnCode = TPM_Digest_Load(sigTicket, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(v1CmkSigticket.signedData, + restrictTicketBuffer.size, restrictTicketBuffer.buffer, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_MsaComposite_CheckSigTicket(sigTicket, + tpm_state->tpm_permanent_data.tpmProof, + &msaList, + &v1CmkSigticket); + } + /* ii. If [restrictTicket -> destinationKeyDigest] != SHA-1[migrationKeyAuth -> + migrationKey], return error TPM_MA_DESTINATION */ + /* deserialize the restrictTicket structure */ + if (returnCode == TPM_SUCCESS) { + stream = restrictTicketBuffer.buffer; + stream_size = restrictTicketBuffer.size; + returnCode = TPM_CmkAuth_Load(&restrictTicket, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(migrationKeyDigest, + restrictTicket.destinationKeyDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: Error, no match to destinationKeyDigest\n"); + returnCode = TPM_MA_DESTINATION; + } + } + /* iii. If [restrictTicket -> sourceKeyDigest] != pubSourceKeyDigest, return error + TPM_MA_SOURCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(pubSourceKeyDigest, restrictTicket.sourceKeyDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: Error, no match to sourceKeyDigest\n"); + returnCode = TPM_MA_SOURCE; + } + } + } + /* 10. Else return with error TPM_BAD_PARAMETER. */ + else if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_CreateBlob: Error, Illegal migrationScheme %04hx\n", + migrationKeyAuth.migrationScheme); + returnCode = TPM_BAD_PARAMETER; + } + /* 11. Build two bytes array, K1 and K2, using d1: */ + /* a. K1 = TPM_STORE_ASYMKEY.privKey[0..19] (TPM_STORE_ASYMKEY.privKey.keyLength + 16 bytes of + TPM_STORE_ASYMKEY.privKey.key), sizeof(K1) = 20 */ + /* b. K2 = TPM_STORE_ASYMKEY.privKey[20..131] (position 16-127 of + TPM_STORE_ASYMKEY.privKey.key), sizeof(K2) = 112 */ + /* 12. Build M1 a TPM_MIGRATE_ASYMKEY structure */ + /* a. TPM_MIGRATE_ASYMKEY.payload = TPM_PT_CMK_MIGRATE */ + /* b. TPM_MIGRATE_ASYMKEY.usageAuth = TPM_STORE_ASYMKEY.usageAuth */ + /* c. TPM_MIGRATE_ASYMKEY.pubDataDigest = TPM_STORE_ASYMKEY.pubDataDigest */ + /* d. TPM_MIGRATE_ASYMKEY.partPrivKeyLen = 112 - 127. */ + /* e. TPM_MIGRATE_ASYMKEY.partPrivKey = K2 */ + /* 13. Create o1 (which SHALL be 198 bytes for a 2048 bit RSA key) by performing the OAEP + encoding of m using OAEP parameters m, pHash, and seed */ + /* a. m is the previously created M1 */ + /* b. pHash = SHA-1( SHA-1[msaList] || pubSourceKeyDigest) */ + /* c. seed = s1 = the previously created K1 */ + /* 14. Create r1 a random value from the TPM RNG. The size of r1 MUST be the size of o1. Return + r1 in the */ + /* random parameter */ + /* 15. Create x1 by XOR of o1 with r1 */ + /* 16. Copy r1 into the output field "random" */ + /* 17. Encrypt x1 with the migrationKeyAuth-> migrationKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(pHash, + TPM_DIGEST_SIZE, m2CmkMigauth.msaDigest, + TPM_DIGEST_SIZE, pubSourceKeyDigest, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CreateBlobCommon(&outData, + &d1AsymKey, + pHash, + TPM_PT_CMK_MIGRATE, + &random, + &(migrationKeyAuth.migrationKey)); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_CreateBlob: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return random */ + returnCode = TPM_SizedBuffer_Store(response, &random); + } + if (returnCode == TPM_SUCCESS) { + /* return outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, + parentAuthHandle); + } + /* + cleanup + */ + free(d1Decrypt); /* @1 */ + TPM_Migrationkeyauth_Delete(&migrationKeyAuth); /* @2 */ + TPM_SizedBuffer_Delete(&msaListBuffer); /* @3 */ + TPM_SizedBuffer_Delete(&restrictTicketBuffer); /* @4 */ + TPM_SizedBuffer_Delete(&sigTicketBuffer); /* @5 */ + TPM_SizedBuffer_Delete(&encData); /* @6 */ + TPM_SizedBuffer_Delete(&random); /* @7 */ + TPM_SizedBuffer_Delete(&outData); /* @8 */ + TPM_Sbuffer_Delete(&mka_sbuffer); /* @9 */ + TPM_StoreAsymkey_Delete(&d1AsymKey); /* @10 */ + TPM_MsaComposite_Delete(&msaList); /* @11 */ + TPM_CmkAuth_Delete(&restrictTicket); /* @12 */ + TPM_CmkMigauth_Delete(&m2CmkMigauth); /* @13 */ + TPM_CmkSigticket_Delete(&v1CmkSigticket); /* @14 */ + return rcf; +} + +/* 11.7 TPM_CMK_SetRestrictions rev 96 + + This command is used by the Owner to dictate the usage of a certified-migration key with + delegated authorisation (authorisation other than actual Owner authorisation). + + This command is provided for privacy reasons and must not itself be delegated, because a + certified-migration-key may involve a contractual relationship between the Owner and an external + entity. + + Since restrictions are validated at DSAP session use, there is no need to invalidate DSAP + sessions when the restriction value changes. +*/ + +TPM_RESULT TPM_Process_CMK_SetRestrictions(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_CMK_DELEGATE restriction; /* The bit mask of how to set the restrictions on CMK keys + */ + TPM_AUTHHANDLE authHandle; /* The authorization handle TPM Owner authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest. HMAC key: TPM Owner Auth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_CMK_SetRestrictions: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get restriction */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&restriction, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_SetRestrictions: restriction %08x\n", restriction); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_SetRestrictions: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the ordinal and parameters using TPM Owner authorization, return TPM_AUTHFAIL on + error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CMK_SetRestrictions: ownerAuth secret", *hmacKey); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Set TPM_PERMANENT_DATA -> TPM_CMK_DELEGATE -> restrictDelegate = restriction */ + if (returnCode == TPM_SUCCESS) { + /* only update NVRAM if the value is changing */ + if (tpm_state->tpm_permanent_data.restrictDelegate != restriction) { + tpm_state->tpm_permanent_data.restrictDelegate = restriction; + /* Store the permanent data back to NVRAM */ + printf("TPM_Process_CMK_SetRestrictions: Storing permanent data\n"); + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } + else { + printf("TPM_Process_CMK_SetRestrictions: No change to value\n"); + } + } + /* 3. Return TPM_SUCCESS */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_SetRestrictions: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 11.6 TPM_CMK_ApproveMA 87 + + This command creates an authorization ticket, to allow the TPM owner to specify which Migration + Authorities they approve and allow users to create certified-migration-keys without further + involvement with the TPM owner. + + It is the responsibility of the TPM Owner to determine whether a particular Migration Authority is + suitable to control migration. +*/ + +TPM_RESULT TPM_Process_CMK_ApproveMA(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_DIGEST migrationAuthorityDigest; /* A digest of a TPM_MSA_COMPOSITE structure (itself + one or more digests of public keys belonging to + migration authorities) */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* Authorization HMAC, key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_CMK_MA_APPROVAL m2CmkMaApproval; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_HMAC outData; /* HMAC of migrationAuthorityDigest */ + + printf("TPM_Process_CMK_ApproveMA: Ordinal Entry\n"); + TPM_CmkMaApproval_Init(&m2CmkMaApproval); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get migrationAuthorityDigest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(migrationAuthorityDigest, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_ApproveMA: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the AuthData to use the TPM by the TPM Owner */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + /* 2. Create M2 a TPM_CMK_MA_APPROVAL structure */ + /* NOTE Done by TPM_CmkMaApproval_Init() */ + /* a. Set M2 ->migrationAuthorityDigest to migrationAuthorityDigest */ + TPM_Digest_Copy(m2CmkMaApproval.migrationAuthorityDigest, migrationAuthorityDigest); + /* 3. Set outData = HMAC(M2) using tpmProof as the secret */ + returnCode = TPM_HMAC_GenerateStructure + (outData, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkMaApproval, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_CmkMaApproval_Store); /* store function */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_ApproveMA: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the outData */ + returnCode = TPM_Digest_Store(response, outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_CmkMaApproval_Delete(&m2CmkMaApproval); /* @1 */ + return rcf; +} + +/* 11.10 TPM_CMK_ConvertMigration rev 106 + + TPM_CMK_ConvertMigration completes the migration of certified migration blobs. + + This command takes a certified migration blob and creates a normal wrapped blob with payload type + TPM_PT_MIGRATE_EXTERNAL. The migrated blob must be loaded into the TPM using the normal + TPM_LoadKey function. + + Note that the command migrates private keys, only. The migration of the associated public keys is + not specified by TPM because they are not security sensitive. Migration of the associated public + keys may be specified in a platform specific specification. A TPM_KEY structure must be recreated + before the migrated key can be used by the target TPM in a LoadKey command. + + TPM_CMK_ConvertMigration checks that one of the MAs implicitly listed in the migrationAuth of the + target key has approved migration of the target key to the destination (parent) key, and that the + settings (flags etc.) in the target key are those of a CMK. +*/ + +TPM_RESULT TPM_Process_CMK_ConvertMigration(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* Handle of a loaded key that can decrypt keys. */ + TPM_CMK_AUTH restrictTicket; /* The digests of public keys belonging to the Migration + Authority, the destination parent key and the + key-to-be-migrated. */ + TPM_HMAC sigTicket; /* A signature ticket, generated by the TPM, signaling a + valid signature over restrictTicket */ + TPM_KEY migratedKey; /* The public key of the key-to-be-migrated. The private + portion MUST be TPM_MIGRATE_ASYMKEY properly XOR'd */ + TPM_SIZED_BUFFER msaListBuffer; /* One or more digests of public keys belonging to migration + authorities */ + TPM_SIZED_BUFFER random; /* Random value used to hide key data. */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA parentAuth; /* Authorization HMAC: parentKey.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_KEY *parentKey; + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + unsigned char *d1Decrypt; + uint32_t d1DecryptLength = 0; /* actual valid data */ + BYTE *o1Oaep; + unsigned char *stream; /* for deserializing structures */ + uint32_t stream_size; + TPM_MSA_COMPOSITE msaList; + TPM_DIGEST msaListDigest; + TPM_DIGEST migratedPubKeyDigest; + TPM_STORE_ASYMKEY d2AsymKey; + TPM_STORE_BUFFER d2_sbuffer; + TPM_DIGEST parentPubKeyDigest; + TPM_CMK_SIGTICKET v1CmkSigticket; + TPM_CMK_MIGAUTH m2CmkMigauth; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER outData; /* The encrypted private key that can be loaded with + TPM_LoadKey */ + + printf("TPM_Process_CMK_ConvertMigration: Ordinal Entry\n"); + TPM_CmkAuth_Init(&restrictTicket); /* freed @1 */ + TPM_Key_Init(&migratedKey); /* freed @2 */ + TPM_SizedBuffer_Init(&msaListBuffer); /* freed @3 */ + TPM_SizedBuffer_Init(&random); /* freed @4 */ + TPM_SizedBuffer_Init(&outData); /* freed @5 */ + d1Decrypt = NULL; /* freed @6 */ + TPM_MsaComposite_Init(&msaList); /* freed @7 */ + TPM_StoreAsymkey_Init(&d2AsymKey); /* freed @8 */ + TPM_Sbuffer_Init(&d2_sbuffer); /* freed @9 */ + TPM_CmkSigticket_Init(&v1CmkSigticket); /* freed @10 */ + o1Oaep = NULL; /* freed @11 */ + TPM_CmkMigauth_Init(&m2CmkMigauth); /* freed @12 */ + /* + get inputs + */ + /* get parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get restrictTicket */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: parentHandle %08x\n", parentHandle); + returnCode = TPM_CmkAuth_Load(&restrictTicket, &command, ¶mSize); + } + /* get sigTicket */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(sigTicket, &command, ¶mSize); + } + /* get migratedKey */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&migratedKey, &command, ¶mSize); + } + /* get msaListBuffer */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&msaListBuffer, &command, ¶mSize); + } + /* get random */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&random, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CMK_ConvertMigration: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the AuthData to use the key in parentHandle */ + /* get the key associated with parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using private key */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get parentHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate the authorization to use the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* 2. If the keyUsage field of the key referenced by parentHandle does not have the value + TPM_KEY_STORAGE, the TPM must return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_CMK_ConvertMigration: Error, " + "parentHandle -> keyUsage should be TPM_KEY_STORAGE, is %04x\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Create d1 by decrypting the migratedKey -> encData area using the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Decrypting encData\n"); + TPM_PrintFour("TPM_Process_CMK_ConvertMigration: encData", migratedKey.encData.buffer); + returnCode = TPM_RSAPrivateDecryptMalloc(&d1Decrypt, /* decrypted data */ + &d1DecryptLength, /* actual size of d1 data */ + migratedKey.encData.buffer, /* encrypted data */ + migratedKey.encData.size, + parentKey); + } + /* the random input parameter must be the same length as the decrypted data */ + if (returnCode == TPM_SUCCESS) { + if (d1DecryptLength != random.size) { + printf("TPM_Process_CMK_ConvertMigration: Error " + "decrypt data length %u random size %u\n", + d1DecryptLength, random.size); + returnCode = TPM_BAD_PARAMETER; + } + } + /* allocate memory for o1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&o1Oaep, d1DecryptLength); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: d1 length %u\n", d1DecryptLength); + TPM_PrintFour("TPM_Process_CMK_ConvertMigration: d1 -", d1Decrypt); + /* 4. Create o1 by XOR d1 and random parameter */ + TPM_XOR(o1Oaep, d1Decrypt, random.buffer, d1DecryptLength); + /* 5. Create m1 a TPM_MIGRATE_ASYMKEY, seed and pHash by OAEP decoding o1 */ + /* 7. Create k1 by combining seed and the TPM_MIGRATE_ASYMKEY -> partPrivKey */ + /* 8. Create d2 a TPM_STORE_ASYMKEY structure */ + /* a. Set the TPM_STORE_ASYMKEY -> privKey field to k1 */ + /* b. Set d2 -> usageAuth to m1 -> usageAuth */ + /* c. Set d2 -> pubDataDigest to m1 -> pubDataDigest */ + returnCode = TPM_StoreAsymkey_LoadO1(&d2AsymKey, o1Oaep, d1DecryptLength); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Checking pHash\n"); + /* 6. Create migratedPubKey a TPM_PUBKEY structure corresponding to migratedKey */ + /* NOTE this function goes directly to the SHA1 digest */ + returnCode = TPM_Key_GeneratePubkeyDigest(migratedPubKeyDigest, &migratedKey); + } + /* 6.a. Verify that pHash == SHA-1( SHA-1[msaList] || SHA-1(migratedPubKey ) */ + /* deserialize to msaListBuffer to msaList */ + if (returnCode == TPM_SUCCESS) { + stream = msaListBuffer.buffer; + stream_size = msaListBuffer.size; + returnCode = TPM_MsaComposite_Load(&msaList, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(msaListDigest, &msaList, + (TPM_STORE_FUNCTION_T)TPM_MsaComposite_Store); + } + /* pHash is returned in TPM_STORE_ASYMKEY -> migrationAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_Check(d2AsymKey.migrationAuth, + TPM_DIGEST_SIZE, msaListDigest, + TPM_DIGEST_SIZE, migratedPubKeyDigest, + 0, NULL); + } + /* 9. Verify that parentHandle-> keyFlags -> migratable == FALSE and parentHandle-> encData -> + migrationAuth == tpmProof */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Checking parent key\n"); + if (parentKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_CMK_ConvertMigration: Error, parent migratable\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 10. Verify that m1 -> payload == TPM_PT_CMK_MIGRATE, then set d2-> payload = + TPM_PT_MIGRATE_EXTERNAL */ + /* NOTE TPM_StoreAsymkey_LoadO1() copied TPM_MIGRATE_ASYMKEY -> payload to TPM_STORE_ASYMKEY -> + payload */ + if (returnCode == TPM_SUCCESS) { + if (d2AsymKey.payload != TPM_PT_CMK_MIGRATE) { + printf("TPM_Process_CMK_ConvertMigration: Error, invalid payload %02x\n", + d2AsymKey.payload); + returnCode = TPM_BAD_MIGRATION; + } + else { + d2AsymKey.payload = TPM_PT_MIGRATE_EXTERNAL; + } + } + /* 11. Verify that for one of the n=1 to n=(msaList -> MSAlist) values of msaList -> + migAuthDigest[n], sigTicket == HMAC (V1) using tpmProof as the secret where V1 is a + TPM_CMK_SIGTICKET structure such that: */ + /* a. V1 -> verKeyDigest = msaList -> migAuthDigest[n] */ + /* b. V1 -> signedData = SHA-1[restrictTicket] */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Checking sigTicket\n"); + /* generate SHA1[restrictTicket] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(v1CmkSigticket.signedData, &restrictTicket, + (TPM_STORE_FUNCTION_T)TPM_CmkAuth_Store); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour(" TPM_Process_CMK_ConvertMigration: TPM_CMK_SIGTICKET -> sigTicket", + v1CmkSigticket.signedData); + returnCode = TPM_MsaComposite_CheckSigTicket(sigTicket, + tpm_state->tpm_permanent_data.tpmProof, + &msaList, + &v1CmkSigticket); + } + } + /* 12. Create parentPubKey, a TPM_PUBKEY structure corresponding to parenthandle */ + if (returnCode == TPM_SUCCESS) { + /* NOTE this function goes directly to the SHA1 digest */ + returnCode = TPM_Key_GeneratePubkeyDigest(parentPubKeyDigest, parentKey); + } + /* 13. If [restrictTicket -> destinationKeyDigest] != SHA-1(parentPubKey), return error + TPM_MA_DESTINATION */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(restrictTicket.destinationKeyDigest, + parentPubKeyDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Error checking destinationKeyDigest\n"); + returnCode = TPM_MA_DESTINATION; + } + } + /* 14. Verify that migratedKey is corresponding to d2 */ + /* NOTE check the private key against the public key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StorePrivkey_Convert(&d2AsymKey, + &(migratedKey.algorithmParms), + &(migratedKey.pubKey)); + } + /* 15. If migratedKey -> keyFlags -> migratable is FALSE, and return error TPM_INVALID_KEYUSAGE + */ + if (returnCode == TPM_SUCCESS) { + if (!(migratedKey.keyFlags & TPM_MIGRATABLE)) { + printf("TPM_Process_CMK_ConvertMigration: Error, migratedKey migratable is FALSE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 16. If migratedKey -> keyFlags -> migrateAuthority is FALSE, return error + TPM_INVALID_KEYUSAGE + */ + if (returnCode == TPM_SUCCESS) { + if (!(migratedKey.keyFlags & TPM_MIGRATEAUTHORITY)) { + printf("TPM_Process_CMK_ConvertMigration: Error, " + "migratedKey migrateauthority is FALSE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 17. If [restrictTicket -> sourceKeyDigest] != SHA-1(migratedPubKey), return error + TPM_MA_SOURCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Compare(restrictTicket.sourceKeyDigest, migratedPubKeyDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_CMK_ConvertMigration: Error checking sourceKeyDigest\n"); + returnCode = TPM_MA_SOURCE; + } + } + /* 18. Create M2 a TPM_CMK_MIGAUTH structure */ + /* NOTE Done by TPM_CmkMigauth_Init() */ + /* a. Set M2 -> msaDigest to SHA-1[msaList] */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(m2CmkMigauth.msaDigest, &msaList, + (TPM_STORE_FUNCTION_T)TPM_MsaComposite_Store); + } + if (returnCode == TPM_SUCCESS) { + /* b. Set M2 -> pubKeyDigest to SHA-1[migratedPubKey] */ + TPM_Digest_Copy(m2CmkMigauth.pubKeyDigest, migratedPubKeyDigest); + /* 19. Set d2 -> migrationAuth = HMAC(M2) using tpmProof as the secret */ + returnCode = TPM_HMAC_GenerateStructure + (d2AsymKey.migrationAuth, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &m2CmkMigauth, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_CmkMigauth_Store); /* store function */ + } + /* 21. Create outData using the key in parentHandle to perform the encryption */ + if (returnCode == TPM_SUCCESS) { + /* serialize d2Asymkey to d2_sbuffer */ + returnCode = TPM_StoreAsymkey_Store(&d2_sbuffer, FALSE, &d2AsymKey); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPublicEncryptSbuffer_Key(&outData, &d2_sbuffer, parentKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CMK_ConvertMigration: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the outData */ + returnCode = TPM_SizedBuffer_Store(response, &outData); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_CmkAuth_Delete(&restrictTicket); /* @1 */ + TPM_Key_Delete(&migratedKey); /* @2 */ + TPM_SizedBuffer_Delete(&msaListBuffer); /* @3 */ + TPM_SizedBuffer_Delete(&random); /* @4 */ + TPM_SizedBuffer_Delete(&outData); /* @5 */ + free(d1Decrypt); /* @6 */ + TPM_MsaComposite_Delete(&msaList); /* @7 */ + TPM_StoreAsymkey_Delete(&d2AsymKey); /* @8 */ + TPM_Sbuffer_Delete(&d2_sbuffer); /* @9 */ + TPM_CmkSigticket_Delete(&v1CmkSigticket); /* @10 */ + free(o1Oaep); /* @11 */ + TPM_CmkMigauth_Delete(&m2CmkMigauth); /* @12 */ + return rcf; +} diff --git a/src/tpm_migration.h b/src/tpm_migration.h new file mode 100644 index 00000000..91f9fa30 --- /dev/null +++ b/src/tpm_migration.h @@ -0,0 +1,218 @@ +/********************************************************************************/ +/* */ +/* Migration */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_migration.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_MIGRATION_H +#define TPM_MIGRATION_H + +#include "tpm_global.h" + +/* + TPM_MIGRATIONKEYAUTH +*/ + +void TPM_Migrationkeyauth_Init(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth); +TPM_RESULT TPM_Migrationkeyauth_Load(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Migrationkeyauth_Store(TPM_STORE_BUFFER *sbuffer, + TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth); +void TPM_Migrationkeyauth_Delete(TPM_MIGRATIONKEYAUTH *tpm_migrationkeyauth); + +/* + TPM_MSA_COMPOSITE +*/ + +void TPM_MsaComposite_Init(TPM_MSA_COMPOSITE *tpm_msa_composite); +TPM_RESULT TPM_MsaComposite_Load(TPM_MSA_COMPOSITE *tpm_msa_composite, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_MsaComposite_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_MSA_COMPOSITE *tpm_msa_composite); +void TPM_MsaComposite_Delete(TPM_MSA_COMPOSITE *tpm_msa_composite); + +TPM_RESULT TPM_MsaComposite_CheckMigAuthDigest(TPM_DIGEST tpm_digest, + TPM_MSA_COMPOSITE *tpm_msa_composite); +TPM_RESULT TPM_MsaComposite_CheckSigTicket(TPM_DIGEST sigTicket, + TPM_SECRET tpmProof, + TPM_MSA_COMPOSITE *tpm_msa_composite, + TPM_CMK_SIGTICKET *tpm_cmk_sigticket); + +/* + TPM_CMK_AUTH +*/ + +void TPM_CmkAuth_Init(TPM_CMK_AUTH *tpm_cmk_auth); +TPM_RESULT TPM_CmkAuth_Load(TPM_CMK_AUTH *tpm_cmk_auth, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CmkAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_AUTH *tpm_cmk_auth); +void TPM_CmkAuth_Delete(TPM_CMK_AUTH *tpm_cmk_auth); + +/* + TPM_CMK_MIGAUTH +*/ + +void TPM_CmkMigauth_Init(TPM_CMK_MIGAUTH *tpm_cmk_migauth); +TPM_RESULT TPM_CmkMigauth_Load(TPM_CMK_MIGAUTH *tpm_cmk_migauth, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CmkMigauth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_MIGAUTH *tpm_cmk_migauth); +void TPM_CmkMigauth_Delete(TPM_CMK_MIGAUTH *tpm_cmk_migauth); + +TPM_RESULT TPM_CmkMigauth_CheckHMAC(TPM_BOOL *valid, + TPM_HMAC tpm_hmac, + TPM_SECRET tpm_hmac_key, + TPM_CMK_MIGAUTH *tpm_cmk_migauth); + +/* + TPM_CMK_SIGTICKET +*/ + +void TPM_CmkSigticket_Init(TPM_CMK_SIGTICKET *tpm_cmk_sigticket); +TPM_RESULT TPM_CmkSigticket_Load(TPM_CMK_SIGTICKET *tpm_cmk_sigticket, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CmkSigticket_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_SIGTICKET *tpm_cmk_sigticket); +void TPM_CmkSigticket_Delete(TPM_CMK_SIGTICKET *tpm_cmk_sigticket); + +/* + TPM_CMK_MA_APPROVAL +*/ + +void TPM_CmkMaApproval_Init(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval); +TPM_RESULT TPM_CmkMaApproval_Load(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CmkMaApproval_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval); +void TPM_CmkMaApproval_Delete(TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval); + +TPM_RESULT TPM_CmkMaApproval_CheckHMAC(TPM_BOOL *valid, + TPM_HMAC tpm_hmac, + TPM_SECRET tpm_hmac_key, + TPM_CMK_MA_APPROVAL *tpm_cmk_ma_approval); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_CreateBlobCommon(TPM_SIZED_BUFFER *outData, + TPM_STORE_ASYMKEY *d1Key, + TPM_DIGEST pHash, + TPM_PAYLOAD_TYPE payload_type, + TPM_SIZED_BUFFER *random, + TPM_PUBKEY *migrationKey); + +TPM_RESULT TPM_Process_CreateMigrationBlob(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ConvertMigrationBlob(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_AuthorizeMigrationKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_MigrateKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_CMK_CreateKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_CMK_CreateTicket(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_CMK_CreateBlob(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_CMK_SetRestrictions(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_CMK_ApproveMA(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_CMK_ConvertMigration(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + + +#endif diff --git a/src/tpm_nonce.c b/src/tpm_nonce.c new file mode 100644 index 00000000..115bef6e --- /dev/null +++ b/src/tpm_nonce.c @@ -0,0 +1,157 @@ +/********************************************************************************/ +/* */ +/* Nonce Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nonce.c 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_structures.h" + +#include "tpm_nonce.h" + +/* TPM_Nonce_Init resets a nonce structure to zeros */ + +void TPM_Nonce_Init(TPM_NONCE tpm_nonce) +{ + size_t i; + + printf(" TPM_Nonce_Init:\n"); + for (i = 0 ; i < TPM_NONCE_SIZE ; i++) { + tpm_nonce[i] = 0; + } + return; +} + +/* TPM_Nonce_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + + +TPM_RESULT TPM_Nonce_Load(TPM_NONCE tpm_nonce, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Nonce_Load:\n"); + rc = TPM_Loadn(tpm_nonce, TPM_NONCE_SIZE, stream, stream_size); + return rc; +} + +/* TPM_Nonce_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + After use, call TPM_Sbuffer_Delete() to free memory +*/ + +TPM_RESULT TPM_Nonce_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NONCE tpm_nonce) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Nonce_Store:\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_nonce, TPM_NONCE_SIZE); + return rc; +} + +/* TPM_Nonce_Copy() copies the source to the destination + */ + +void TPM_Nonce_Copy(TPM_NONCE destination, const TPM_NONCE source) +{ + printf(" TPM_Nonce_Copy:\n"); + memcpy(destination, source, TPM_NONCE_SIZE); + return; +} + +/* TPM_Nonce_Compare() compares the source to the destination. + + Returns TPM_AUTHFAIL if the nonces are not equal +*/ + +TPM_RESULT TPM_Nonce_Compare(TPM_NONCE expect, const TPM_NONCE actual) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Nonce_Compare:\n"); + rc = memcmp(expect, actual, TPM_NONCE_SIZE); + if (rc != 0) { + printf("TPM_Nonce_Compare: Error comparing nonce\n"); + TPM_PrintFour(" TPM_Nonce_Compare: Expect", expect); + TPM_PrintFour(" TPM_Nonce_Compare: Actual", actual); + rc = TPM_AUTHFAIL; + } + return rc; +} + +/* TPM_Nonce_Generate() generates a new nonce from the random number generator + */ + +TPM_RESULT TPM_Nonce_Generate(TPM_NONCE tpm_nonce) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Nonce_Generate:\n"); + rc = TPM_Random(tpm_nonce, TPM_NONCE_SIZE); + return rc; +} + +/* TPM_Nonce_IsZero() returns 'isZero' TRUE is all bytes 'tpm_nonce' are 0x00 + */ + +void TPM_Nonce_IsZero(TPM_BOOL *isZero, TPM_NONCE tpm_nonce) +{ + size_t i; + + printf(" TPM_Nonce_IsZero:\n"); + for (i = 0, *isZero = TRUE ; (i < TPM_NONCE_SIZE) && *isZero ; i++) { + if (tpm_nonce[i] != 0) { + *isZero = FALSE; + } + } + return; +} + diff --git a/src/tpm_nonce.h b/src/tpm_nonce.h new file mode 100644 index 00000000..a2113f8a --- /dev/null +++ b/src/tpm_nonce.h @@ -0,0 +1,60 @@ +/********************************************************************************/ +/* */ +/* Nonce Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nonce.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_NONCE_H +#define TPM_NONCE_H + +#include "tpm_store.h" +#include "tpm_structures.h" + +void TPM_Nonce_Init(TPM_NONCE tpm_nonce); + +TPM_RESULT TPM_Nonce_Generate(TPM_NONCE tpm_nonce); + +void TPM_Nonce_Copy(TPM_NONCE destination, + const TPM_NONCE source); +TPM_RESULT TPM_Nonce_Load(TPM_NONCE tpm_nonce, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Nonce_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NONCE tpm_nonce); +TPM_RESULT TPM_Nonce_Compare(TPM_NONCE expect, const TPM_NONCE actual); +void TPM_Nonce_IsZero(TPM_BOOL *isZero, TPM_NONCE tpm_nonce); + +#endif diff --git a/src/tpm_nvfile.c b/src/tpm_nvfile.c new file mode 100644 index 00000000..e0fe711d --- /dev/null +++ b/src/tpm_nvfile.c @@ -0,0 +1,385 @@ +/********************************************************************************/ +/* */ +/* NVRAM File Abstraction Layer */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nvfile.c 4664 2012-01-03 22:15:08Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +/* This module abstracts out all NVRAM read and write operations. + + This implementation uses standard, portable C files. + + The basic high level abstractions are: + + TPM_NVRAM_LoadData(); + TPM_NVRAM_StoreData(); + TPM_NVRAM_DeleteName(); + + They take a 'name' that is mapped to a rooted file name. +*/ + +#include +#include +#include +#include + +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_memory.h" +#include "tpm_nvram.h" + +#include "tpm_nvfile.h" + +#ifdef TPM_LIBTPMS_CALLBACKS +#include "tpm_library_intern.h" +#endif + + +/* local prototypes */ + +static void TPM_NVRAM_GetFilenameForName(char *filename, + uint32_t tpm_number, + const char *name); + + +/* A file name in NVRAM is composed of 3 parts: + + 1 - 'state_directory' is the rooted path to the TPM state home directory + 2 = 'tpm_number' is the TPM instance, 00 for a single TPM + 2 - the file name + + For the IBM cryptographic coprocessor version, the root path is hard coded. + + For the Linux and Windows versions, the path comes from an environment variable. This variable is + used once in TPM_NVRAM_Init(). + + One root path is used for all virtual TPM's, so it can be a static variable. +*/ + +char state_directory[FILENAME_MAX]; + +/* TPM_NVRAM_Init() is called once at startup. It does any NVRAM required initialization. + + This function sets some static variables that are used by all TPM's. +*/ + +TPM_RESULT TPM_NVRAM_Init(void) +{ + TPM_RESULT rc = 0; + char *tpm_state_path; + size_t length; + +#ifdef TPM_LIBTPMS_CALLBACKS + struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); + + /* call user-provided function if available, otherwise execute + default behavior */ + if (cbs->tpm_nvram_init) { + rc = cbs->tpm_nvram_init(); + return rc; + } +#endif + + printf(" TPM_NVRAM_Init:\n"); +#ifdef TPM_NV_DISK + /* TPM_NV_DISK TPM emulation stores in local directory determined by environment variable. */ + if (rc == 0) { + tpm_state_path = getenv("TPM_PATH"); + if (tpm_state_path == NULL) { + printf("TPM_NVRAM_Init: Error (fatal), TPM_PATH environment variable not set\n"); + rc = TPM_FAIL; + } + } +#endif + /* check that the directory name plus a file name will not overflow FILENAME_MAX */ + if (rc == 0) { + length = strlen(tpm_state_path); + if ((length + TPM_FILENAME_MAX) > FILENAME_MAX) { + printf("TPM_NVRAM_Init: Error (fatal), TPM state path name %s too large\n", + tpm_state_path); + rc = TPM_FAIL; + } + } + if (rc == 0) { + strcpy(state_directory, tpm_state_path); + printf("TPM_NVRAM_Init: Rooted state path %s\n", state_directory); + } + return rc; +} + +/* Load 'data' of 'length' from the 'name'. + + 'data' must be freed after use. + + Returns + 0 on success. + TPM_RETRY and NULL,0 on non-existent file (non-fatal, first time start up) + TPM_FAIL on failure to load (fatal), since it should never occur +*/ + +TPM_RESULT TPM_NVRAM_LoadData(unsigned char **data, /* freed by caller */ + uint32_t *length, + uint32_t tpm_number, + const char *name) +{ + TPM_RESULT rc = 0; + long lrc; + size_t src; + int irc; + FILE *file = NULL; + char filename[FILENAME_MAX]; /* rooted file name from name */ + +#ifdef TPM_LIBTPMS_CALLBACKS + struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); + + /* call user-provided function if available, otherwise execute + default behavior */ + if (cbs->tpm_nvram_loaddata) { + rc = cbs->tpm_nvram_loaddata(data, length, tpm_number, name); + return rc; + } +#endif + + printf(" TPM_NVRAM_LoadData: From file %s\n", name); + *data = NULL; + *length = 0; + /* open the file */ + if (rc == 0) { + /* map name to the rooted filename */ + TPM_NVRAM_GetFilenameForName(filename, tpm_number, name); + printf(" TPM_NVRAM_LoadData: Opening file %s\n", filename); + file = fopen(filename, "rb"); /* closed @1 */ + if (file == NULL) { /* if failure, determine cause */ + if (errno == ENOENT) { + printf("TPM_NVRAM_LoadData: No such file %s\n", filename); + rc = TPM_RETRY; /* first time start up */ + } + else { + printf("TPM_NVRAM_LoadData: Error (fatal) opening %s for read, %s\n", + filename, strerror(errno)); + rc = TPM_FAIL; + } + } + } + /* determine the file length */ + if (rc == 0) { + irc = fseek(file, 0L, SEEK_END); /* seek to end of file */ + if (irc == -1L) { + printf("TPM_NVRAM_LoadData: Error (fatal) fseek'ing %s, %s\n", + filename, strerror(errno)); + rc = TPM_FAIL; + } + } + if (rc == 0) { + lrc = ftell(file); /* get position in the stream */ + if (lrc == -1L) { + printf("TPM_NVRAM_LoadData: Error (fatal) ftell'ing %s, %s\n", + filename, strerror(errno)); + rc = TPM_FAIL; + } + else { + *length = (uint32_t)lrc; /* save the length */ + } + } + if (rc == 0) { + irc = fseek(file, 0L, SEEK_SET); /* seek back to the beginning of the file */ + if (irc == -1L) { + printf("TPM_NVRAM_LoadData: Error (fatal) fseek'ing %s, %s\n", + filename, strerror(errno)); + rc = TPM_FAIL; + } + } + /* allocate a buffer for the actual data */ + if ((rc == 0) && *length != 0) { + printf(" TPM_NVRAM_LoadData: Reading %u bytes of data\n", *length); + rc = TPM_Malloc(data, *length); + if (rc != 0) { + printf("TPM_NVRAM_LoadData: Error (fatal) allocating %u bytes\n", *length); + rc = TPM_FAIL; + } + } + /* read the contents of the file into the data buffer */ + if ((rc == 0) && *length != 0) { + src = fread(*data, 1, *length, file); + if (src != *length) { + printf("TPM_NVRAM_LoadData: Error (fatal), data read of %u only read %lu\n", + *length, (unsigned long)src); + rc = TPM_FAIL; + } + } + /* close the file */ + if (file != NULL) { + printf(" TPM_NVRAM_LoadData: Closing file %s\n", filename); + irc = fclose(file); /* @1 */ + if (irc != 0) { + printf("TPM_NVRAM_LoadData: Error (fatal) closing file %s\n", filename); + rc = TPM_FAIL; + } + else { + printf(" TPM_NVRAM_LoadData: Closed file %s\n", filename); + } + } + return rc; +} + +/* TPM_NVRAM_StoreData stores 'data' of 'length' to the rooted 'filename' + + Returns + 0 on success + TPM_FAIL for other fatal errors +*/ + +TPM_RESULT TPM_NVRAM_StoreData(const unsigned char *data, + uint32_t length, + uint32_t tpm_number, + const char *name) +{ + TPM_RESULT rc = 0; + uint32_t lrc; + int irc; + FILE *file = NULL; + char filename[FILENAME_MAX]; /* rooted file name from name */ + +#ifdef TPM_LIBTPMS_CALLBACKS + struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); + + /* call user-provided function if available, otherwise execute + default behavior */ + if (cbs->tpm_nvram_storedata) { + rc = cbs->tpm_nvram_storedata(data, length, tpm_number, name); + return rc; + } +#endif + + printf(" TPM_NVRAM_StoreData: To name %s\n", name); + if (rc == 0) { + /* map name to the rooted filename */ + TPM_NVRAM_GetFilenameForName(filename, tpm_number, name); + /* open the file */ + printf(" TPM_NVRAM_StoreData: Opening file %s\n", filename); + file = fopen(filename, "wb"); /* closed @1 */ + if (file == NULL) { + printf("TPM_NVRAM_StoreData: Error (fatal) opening %s for write failed, %s\n", + filename, strerror(errno)); + rc = TPM_FAIL; + } + } + /* write the data to the file */ + if (rc == 0) { + printf(" TPM_NVRAM_StoreData: Writing %u bytes of data\n", length); + lrc = fwrite(data, 1, length, file); + if (lrc != length) { + printf("TPM_NVRAM_StoreData: Error (fatal), data write of %u only wrote %u\n", + length, lrc); + rc = TPM_FAIL; + } + } + if (file != NULL) { + printf(" TPM_NVRAM_StoreData: Closing file %s\n", filename); + irc = fclose(file); /* @1 */ + if (irc != 0) { + printf("TPM_NVRAM_StoreData: Error (fatal) closing file\n"); + rc = TPM_FAIL; + } + else { + printf(" TPM_NVRAM_StoreData: Closed file %s\n", filename); + } + } + return rc; +} + + +/* TPM_NVRAM_GetFilenameForName() constructs a rooted file name from the name. + + The filename is of the form: + + state_directory/tpm_number.name +*/ + +static void TPM_NVRAM_GetFilenameForName(char *filename, /* output: rooted filename */ + uint32_t tpm_number, + const char *name) /* input: abstract name */ +{ + printf(" TPM_NVRAM_GetFilenameForName: For name %s\n", name); + sprintf(filename, "%s/%02lx.%s", state_directory, (unsigned long)tpm_number, name); + printf(" TPM_NVRAM_GetFilenameForName: File name %s\n", filename); + return; +} + +/* TPM_NVRAM_DeleteName() deletes the 'name' from NVRAM + + Returns: + 0 on success, or if the file does not exist and mustExist is FALSE + TPM_FAIL if the file could not be removed, since this should never occur and there is + no recovery + + NOTE: Not portable code, but supported by Linux and Windows +*/ + +TPM_RESULT TPM_NVRAM_DeleteName(uint32_t tpm_number, + const char *name, + TPM_BOOL mustExist) +{ + TPM_RESULT rc = 0; + int irc; + char filename[FILENAME_MAX]; /* rooted file name from name */ + +#ifdef TPM_LIBTPMS_CALLBACKS + struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); + + /* call user-provided function if available, otherwise execute + default behavior */ + if (cbs->tpm_nvram_deletename) { + rc = cbs->tpm_nvram_deletename(tpm_number, name, mustExist); + return rc; + } +#endif + + printf(" TPM_NVRAM_DeleteName: Name %s\n", name); + /* map name to the rooted filename */ + TPM_NVRAM_GetFilenameForName(filename, tpm_number, name); + if (rc == 0) { + irc = remove(filename); + if ((irc != 0) && /* if the remove failed */ + (mustExist || /* if any error is a failure, or */ + (errno != ENOENT))) { /* if error other than no such file */ + printf("TPM_NVRAM_DeleteName: Error, (fatal) file remove failed, errno %d\n", + errno); + rc = TPM_FAIL; + } + } + return rc; +} + diff --git a/src/tpm_nvfile.h b/src/tpm_nvfile.h new file mode 100644 index 00000000..69b5823a --- /dev/null +++ b/src/tpm_nvfile.h @@ -0,0 +1,71 @@ +/********************************************************************************/ +/* */ +/* NVRAM Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nvfile.h 4623 2011-09-28 15:15:09Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_NVFILE_H +#define TPM_NVFILE_H + +#include "tpm_types.h" + +/* characters in the TPM base file name, 14 for file name, slash, NUL terminator, etc. + + This macro is used once during initialization to ensure that the TPM_PATH environment variable + length will not cause the rooted file name to overflow file name buffers. +*/ + +#define TPM_FILENAME_MAX 20 + +TPM_RESULT TPM_NVRAM_Init(void); + +/* + Basic abstraction for read and write +*/ + +TPM_RESULT TPM_NVRAM_LoadData(unsigned char **data, + uint32_t *length, + uint32_t tpm_number, + const char *name); +TPM_RESULT TPM_NVRAM_StoreData(const unsigned char *data, + uint32_t length, + uint32_t tpm_number, + const char *name); +TPM_RESULT TPM_NVRAM_DeleteName(uint32_t tpm_number, + const char *name, + TPM_BOOL mustExist); + +#endif diff --git a/src/tpm_nvram.c b/src/tpm_nvram.c new file mode 100644 index 00000000..9e7ceaac --- /dev/null +++ b/src/tpm_nvram.c @@ -0,0 +1,3740 @@ +/********************************************************************************/ +/* */ +/* NVRAM Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nvram.c 4621 2011-09-09 20:19:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_memory.h" +#include "tpm_nvfile.h" +#include "tpm_pcr.h" +#include "tpm_permanent.h" +#include "tpm_platform.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_storage.h" +#include "tpm_structures.h" + +#include "tpm_nvram.h" + +/* + NV Defined Space Utilities +*/ + +/* + TPM_NV_ATTRIBUTES +*/ + +/* TPM_NVAttributes_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_NVAttributes_Init(TPM_NV_ATTRIBUTES *tpm_nv_attributes) +{ + printf(" TPM_NVAttributes_Init:\n"); + tpm_nv_attributes->attributes = 0; + return; +} + +/* TPM_NVAttributes_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_NVAttributes_Init() + After use, call TPM_NVAttributes_Delete() to free memory +*/ + +TPM_RESULT TPM_NVAttributes_Load(TPM_NV_ATTRIBUTES *tpm_nv_attributes, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVAttributes_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_NV_ATTRIBUTES, stream, stream_size); + } + /* load attributes */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_nv_attributes->attributes), stream, stream_size); + } + return rc; +} + +/* TPM_NVAttributes_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_NVAttributes_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_ATTRIBUTES *tpm_nv_attributes) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVAttributes_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_ATTRIBUTES); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_nv_attributes->attributes); + } + return rc; +} + +/* TPM_NVAttributes_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the nv_attributes + sets pointers to NULL + calls TPM_NVAttributes_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_NVAttributes_Delete(TPM_NV_ATTRIBUTES *tpm_nv_attributes) +{ + printf(" TPM_NVAttributes_Delete:\n"); + if (tpm_nv_attributes != NULL) { + TPM_NVAttributes_Init(tpm_nv_attributes); + } + return; +} + +void TPM_NVAttributes_Copy(TPM_NV_ATTRIBUTES *tpm_nv_attributes_dest, + TPM_NV_ATTRIBUTES *tpm_nv_attributes_src) +{ + tpm_nv_attributes_dest->attributes = tpm_nv_attributes_src->attributes; + return; +} + +/* + TPM_NV_DATA_PUBLIC +*/ + +/* TPM_NVDataPublic_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_NVDataPublic_Init(TPM_NV_DATA_PUBLIC *tpm_nv_data_public) +{ + printf(" TPM_NVDataPublic_Init:\n"); + tpm_nv_data_public->nvIndex = TPM_NV_INDEX_LOCK; /* mark unused */ + TPM_PCRInfoShort_Init(&(tpm_nv_data_public->pcrInfoRead)); + TPM_PCRInfoShort_Init(&(tpm_nv_data_public->pcrInfoWrite)); + TPM_NVAttributes_Init(&(tpm_nv_data_public->permission)); + tpm_nv_data_public->bReadSTClear = FALSE; + tpm_nv_data_public->bWriteSTClear = FALSE; + tpm_nv_data_public->bWriteDefine = FALSE; + tpm_nv_data_public->dataSize = 0; + return; +} + +/* TPM_NVDataPublic_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_NVDataPublic_Init() + After use, call TPM_NVDataPublic_Delete() to free memory +*/ + +TPM_RESULT TPM_NVDataPublic_Load(TPM_NV_DATA_PUBLIC *tpm_nv_data_public, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL optimize) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVDataPublic_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_NV_DATA_PUBLIC, stream, stream_size); + } + /* load nvIndex */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_nv_data_public->nvIndex), stream, stream_size); + } + /* load pcrInfoRead */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Load(&(tpm_nv_data_public->pcrInfoRead), stream, stream_size, optimize); + } + /* load pcrInfoWrite */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Load(&(tpm_nv_data_public->pcrInfoWrite), stream, stream_size, optimize); + } + /* load permission */ + if (rc == 0) { + rc = TPM_NVAttributes_Load(&(tpm_nv_data_public->permission), stream, stream_size); + } + /* load bReadSTClear */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_nv_data_public->bReadSTClear), stream, stream_size); + } + /* load bWriteSTClear */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_nv_data_public->bWriteSTClear), stream, stream_size); + } + /* load bWriteDefine */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_nv_data_public->bWriteDefine), stream, stream_size); + } + /* load dataSize */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_nv_data_public->dataSize), stream, stream_size); + } + return rc; +} + +/* TPM_NVDataPublic_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_NVDataPublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_DATA_PUBLIC *tpm_nv_data_public, + TPM_BOOL optimize) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVDataPublic_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_DATA_PUBLIC); + } + /* store nvIndex */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_nv_data_public->nvIndex); + } + /* store pcrInfoRead */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_nv_data_public->pcrInfoRead), optimize); + } + /* store pcrInfoWrite */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_nv_data_public->pcrInfoWrite), optimize); + } + /* store permission */ + if (rc == 0) { + rc = TPM_NVAttributes_Store(sbuffer, &(tpm_nv_data_public->permission)); + } + /* store bReadSTClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_nv_data_public->bReadSTClear), sizeof(TPM_BOOL)); + } + /* store bWriteSTClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_nv_data_public->bWriteSTClear), sizeof(TPM_BOOL)); + } + /* store bWriteDefine */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_nv_data_public->bWriteDefine), sizeof(TPM_BOOL)); + } + /* store dataSize */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_nv_data_public->dataSize); + } + return rc; +} + +/* TPM_NVDataPublic_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_NVDataPublic_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_NVDataPublic_Delete(TPM_NV_DATA_PUBLIC *tpm_nv_data_public) +{ + printf(" TPM_NVDataPublic_Delete:\n"); + if (tpm_nv_data_public != NULL) { + TPM_PCRInfoShort_Delete(&(tpm_nv_data_public->pcrInfoRead)); + TPM_PCRInfoShort_Delete(&(tpm_nv_data_public->pcrInfoWrite)); + TPM_NVAttributes_Delete(&(tpm_nv_data_public->permission)); + TPM_NVDataPublic_Init(tpm_nv_data_public); + } + return; +} + +/* + TPM_NV_DATA_SENSITIVE +*/ + +/* TPM_NVDataSensitive_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_NVDataSensitive_Init(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive) +{ + printf(" TPM_NVDataSensitive_Init:\n"); + TPM_NVDataPublic_Init(&(tpm_nv_data_sensitive->pubInfo)); + TPM_Secret_Init(tpm_nv_data_sensitive->authValue); + tpm_nv_data_sensitive->data = NULL; + TPM_Digest_Init(tpm_nv_data_sensitive->digest); + return; +} + +/* TPM_NVDataSensitive_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_NVDataSensitive_Init() + After use, call TPM_NVDataSensitive_Delete() to free memory +*/ + +TPM_RESULT TPM_NVDataSensitive_Load(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive, + TPM_TAG nvEntriesVersion, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_BOOL optimize; + TPM_BOOL isGPIO; + + printf(" TPM_NVDataSensitive_Load: nvEntriesVersion %04hx\n", nvEntriesVersion); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_NV_DATA_SENSITIVE, stream, stream_size); + } + /* load pubInfo */ + if (rc == 0) { + /* versions after V1 optimise the serialization */ + optimize = (nvEntriesVersion != TPM_TAG_NVSTATE_NV_V1); + rc = TPM_NVDataPublic_Load(&(tpm_nv_data_sensitive->pubInfo), + stream, stream_size, + optimize); /* optimize digestAtRelease */ + } + /* load authValue */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_nv_data_sensitive->authValue, stream, stream_size); + } + /* is the nvIndex GPIO space */ + if (rc == 0) { + rc = TPM_NVDataSensitive_IsGPIO(&isGPIO, tpm_nv_data_sensitive->pubInfo.nvIndex); + } + /* allocate memory for data */ + if ((rc == 0) && !isGPIO) { + rc = TPM_Malloc(&(tpm_nv_data_sensitive->data), + tpm_nv_data_sensitive->pubInfo.dataSize); + } + /* load data */ + if ((rc == 0) && !isGPIO) { + rc = TPM_Loadn(tpm_nv_data_sensitive->data, tpm_nv_data_sensitive->pubInfo.dataSize, + stream, stream_size); + } + /* create digest. The digest is not stored to save NVRAM space */ + if (rc == 0) { + rc = TPM_SHA1(tpm_nv_data_sensitive->digest, + sizeof(TPM_NV_INDEX), + (unsigned char *)&tpm_nv_data_sensitive->pubInfo.nvIndex, + TPM_AUTHDATA_SIZE, tpm_nv_data_sensitive->authValue, + 0, NULL); + } + return rc; +} + +/* TPM_NVDataSensitive_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + nvWrite TRUE indicates a write command, not a command to define the space. +*/ + +TPM_RESULT TPM_NVDataSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive) +{ + TPM_RESULT rc = 0; + TPM_BOOL isGPIO; + + printf(" TPM_NVDataSensitive_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_DATA_SENSITIVE); + } + /* store pubInfo */ + if (rc == 0) { + rc = TPM_NVDataPublic_Store(sbuffer, &(tpm_nv_data_sensitive->pubInfo), + TRUE); /* optimize digestAtRelease */ + } + /* store authValue */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_nv_data_sensitive->authValue); + } + /* is the nvIndex GPIO space */ + if (rc == 0) { + rc = TPM_NVDataSensitive_IsGPIO(&isGPIO, tpm_nv_data_sensitive->pubInfo.nvIndex); + } + /* store data */ + if ((rc == 0) && !isGPIO) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_nv_data_sensitive->data, + tpm_nv_data_sensitive->pubInfo.dataSize); + } + return rc; +} + +/* TPM_NVDataSensitive_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_NVDataSensitive_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_NVDataSensitive_Delete(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive) +{ + printf(" TPM_NVDataSensitive_Delete:\n"); + if (tpm_nv_data_sensitive != NULL) { + TPM_NVDataPublic_Delete(&(tpm_nv_data_sensitive->pubInfo)); + TPM_Secret_Delete(tpm_nv_data_sensitive->authValue); + free(tpm_nv_data_sensitive->data); + TPM_NVDataSensitive_Init(tpm_nv_data_sensitive); + } + return; +} + +/* TPM_NVDataSensitive_IsValidIndex() determines if 'nvIndex' is permissible for an NV defined space + TPM_NV_DATA_SENSITIVE structure. + + Some values have special meaning, so they are allowed for the TPM_NV_DefineSpace command but will + not actually define a space. +*/ + +TPM_RESULT TPM_NVDataSensitive_IsValidIndex(TPM_NV_INDEX nvIndex) +{ + TPM_RESULT rc = 0; + TPM_BOOL isGPIO; + + printf(" TPM_NVDataSensitive_IsValidIndex: nvIndex %08x\n", nvIndex); + if (rc == 0) { + if ((nvIndex == TPM_NV_INDEX_LOCK) || + (nvIndex == TPM_NV_INDEX0) || + (nvIndex == TPM_NV_INDEX_DIR)) { + printf("TPM_NVDataSensitive_IsValidIndex: Error, illegal special index\n"); + rc = TPM_BADINDEX; + } + } + if (rc == 0) { + if ((nvIndex & TPM_NV_INDEX_RESVD) != 0) { + printf("TPM_NVDataSensitive_IsValidIndex: Error, illegal reserved index\n"); + rc = TPM_BADINDEX; + } + } + if (rc == 0) { + rc = TPM_NVDataSensitive_IsValidPlatformIndex(nvIndex); + } + /* The GPIO range validity is platform dependent */ + if (rc == 0) { + rc = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); + } + return rc; +} + +/* TPM_NVDataSensitive_IsGPIO() determines if 'nvIndex' is in the GPIO range and is valid. + + Returns: + + TPM_SUCCESS , FALSE if 'nvIndex' is not in the GPIO range + TPM_SUCCESS , TRUE if 'nvIndex' is in the GPIO range and the platform allows GPIO defined space + TPM_BADINDEX, FALSE if 'nvIndex' is in the GPIO range and the platform does not allow GPIO + defined space +*/ + +TPM_RESULT TPM_NVDataSensitive_IsGPIO(TPM_BOOL *isGPIO, TPM_NV_INDEX nvIndex) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVDataSensitive_IsGPIO: nvIndex %08x\n", nvIndex); + *isGPIO = FALSE; +#if defined TPM_PCCLIENT + if (rc == 0) { + /* GPIO space allowed for PC Client */ + if ((nvIndex >= TPM_NV_INDEX_GPIO_START) && + (nvIndex <= TPM_NV_INDEX_GPIO_END)) { + printf(" TPM_NVDataSensitive_IsGPIO: nvIndex is GPIO space\n"); + *isGPIO = TRUE; + } + } + /* #elif */ +#else + if (rc == 0) { + /* GPIO space cannot be defined in platforms with no GPIO */ + if ((nvIndex >= TPM_NV_INDEX_GPIO_START) && + (nvIndex <= TPM_NV_INDEX_GPIO_END)) { + printf("TPM_NVDataSensitive_IsGPIO: Error, illegal index\n"); + rc = TPM_BADINDEX; + } + } +#endif + return rc; +} + +TPM_RESULT TPM_NVDataSensitive_IsValidPlatformIndex(TPM_NV_INDEX nvIndex) +{ + TPM_RESULT rc = 0; + + printf(" TPM_NVDataSensitive_IsValidPlatformIndex: nvIndex %08x\n", nvIndex); +#ifndef TPM_PCCLIENT + if (rc == 0) { + if (((nvIndex & TPM_NV_INDEX_PURVIEW_MASK) >> TPM_NV_INDEX_PURVIEW_BIT) == TPM_PC) { + printf(" TPM_NVDataSensitive_IsValidPlatformIndex: Error, PC Client index\n"); + rc = TPM_BADINDEX; + } + } +#endif + return rc; +} + +/* + NV Index Entries + + This handles the in-memory copy of NV defined space +*/ + +/* + TPM_NVIndexEntries_Init() initializes the TPM_NV_INDEX_ENTRIES array +*/ + +void TPM_NVIndexEntries_Init(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + printf(" TPM_NVIndexEntries_Init:\n"); + tpm_nv_index_entries->nvIndexCount = 0; + tpm_nv_index_entries->tpm_nvindex_entry = NULL; + return; +} + +/* + TPM_NVIndexEntries_Delete() iterates through the entire TPM_NV_INDEX_ENTRIES array, deleting any + used entries. + + It then frees and reinitializes the array. +*/ + + +void TPM_NVIndexEntries_Delete(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + size_t i; + + printf(" TPM_NVIndexEntries_Delete: Deleting from %u slots\n", + tpm_nv_index_entries->nvIndexCount); + /* free the entries */ + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + TPM_NVDataSensitive_Delete(&(tpm_nv_index_entries->tpm_nvindex_entry[i])); + } + /* free the array */ + free(tpm_nv_index_entries->tpm_nvindex_entry); + TPM_NVIndexEntries_Init(tpm_nv_index_entries); + return; +} + +/* TPM_NVIndexEntries_Trace() traces the TPM_NV_INDEX_ENTRIES array. + + Edit and call as required for debugging. +*/ + +void TPM_NVIndexEntries_Trace(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + uint32_t i; + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; + + printf("\tTPM_NVIndexEntries_Trace: %u slots\n", tpm_nv_index_entries->nvIndexCount); + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + printf("\tTPM_NVIndexEntries_Trace: TPM_NV_DATA_SENSITIVE.data %p\n", + tpm_nv_data_sensitive->data); + } + return; +} + +/* + TPM_NVIndexEntries_Load() loads the TPM_NV_INDEX_ENTRIES array from a stream. + + The first data in the stream must be a uint32_t count of the number of entries to follow. +*/ + +TPM_RESULT TPM_NVIndexEntries_Load(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t i; + TPM_TAG nvEntriesVersion; + + printf(" TPM_NVIndexEntries_Load:\n"); + /* get the NV entries version number */ + if (rc == 0) { + rc = TPM_Load16(&nvEntriesVersion, stream, stream_size); + } + /* check tag */ + if (rc == 0) { + switch (nvEntriesVersion) { + case TPM_TAG_NVSTATE_NV_V1: + case TPM_TAG_NVSTATE_NV_V2: + break; + default: + printf("TPM_NVIndexEntries_Load: Error (fatal), version %04x unsupported\n", + nvEntriesVersion); + rc = TPM_FAIL; + break; + } + } + /* nvIndexCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_nv_index_entries->nvIndexCount), stream, stream_size); + } + /* allocate memory for the array, nvIndexCount TPM_NV_DATA_SENSITIVE structures */ + if ((rc == 0) && (tpm_nv_index_entries->nvIndexCount > 0)) { + printf(" TPM_NVIndexEntries_Load: Loading %u slots\n", tpm_nv_index_entries->nvIndexCount); + rc = TPM_Malloc((unsigned char **)&(tpm_nv_index_entries->tpm_nvindex_entry), + sizeof(TPM_NV_DATA_SENSITIVE) * tpm_nv_index_entries->nvIndexCount); + } + /* immediately after allocating, initialize so that _Delete is safe even on a _Load error */ + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + TPM_NVDataSensitive_Init(&(tpm_nv_index_entries->tpm_nvindex_entry[i])); + } + /* tpm_nvindex_entry array */ + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + printf(" TPM_NVIndexEntries_Load: Loading slot %u\n", i); + if (rc == 0) { + rc = TPM_NVDataSensitive_Load(&(tpm_nv_index_entries->tpm_nvindex_entry[i]), + nvEntriesVersion, stream, stream_size); + } + /* should never load an unused entry */ + if (rc == 0) { + printf(" TPM_NVIndexEntries_Load: Loaded NV index %08x\n", + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); + if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex == TPM_NV_INDEX_LOCK) { + printf("TPM_NVIndexEntries_Load: Error (fatal) Entry %u bad NV index %08x\n", + i, tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); + rc = TPM_FAIL; + } + } + } + return rc; +} + +/* + TPM_NVIndexEntries_Store() serializes the TPM_NV_INDEX_ENTRIES array into a stream. Only used + entries are serialized. + + The first data in the stream is the used count, obtained by iterating through the array. +*/ + +TPM_RESULT TPM_NVIndexEntries_Store(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + uint32_t count; /* number of used entries to store */ + size_t i; + + printf(" TPM_NVIndexEntries_Store: Storing from %u slots\n", + tpm_nv_index_entries->nvIndexCount); + /* append the NV entries version number to the stream */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_NV_V2); + } + /* count the number of used entries */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetUsedCount(&count, tpm_nv_index_entries); + } + /* store the actual used count, not the number of array entries */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, count); + } + /* tpm_nvindex_entry array */ + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + /* if the entry is used */ + if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { + printf(" TPM_NVIndexEntries_Store: Storing slot %lu NV index %08x\n", + (unsigned long)i, tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); + rc = TPM_NVDataSensitive_Store(sbuffer, &(tpm_nv_index_entries->tpm_nvindex_entry[i])); + } + else { + printf(" TPM_NVIndexEntries_Store: Skipping unused slot %lu\n", (unsigned long)i); + } + } + return rc; +} + +/* TPM_NVIndexEntries_StClear() steps through each entry in the NV TPM_NV_INDEX_ENTRIES array, + setting the volatile flags to FALSE. +*/ + +void TPM_NVIndexEntries_StClear(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + size_t i; + + printf(" TPM_NVIndexEntries_StClear: Clearing %u slots\n", tpm_nv_index_entries->nvIndexCount); + /* bReadSTClear and bWriteSTClear are volatile, in that they are set FALSE at + TPM_Startup(ST_Clear) */ + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bReadSTClear = FALSE; + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bWriteSTClear = FALSE; + } + return; +} + +/* TPM_NVIndexEntries_LoadVolatile() deserializes the stream into the volatile members of the + TPM_NV_INDEX_ENTRIES array. +*/ + +TPM_RESULT TPM_NVIndexEntries_LoadVolatile(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t usedCount; + uint32_t entryIndex; + TPM_NV_DATA_PUBLIC *tpm_nv_data_public; + + printf(" TPM_NVIndexEntries_LoadVolatile:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_NV_INDEX_ENTRIES_VOLATILE_V1, stream, stream_size); + } + /* Get the number of used slots. This should be equal to the total number of slots. */ + if (rc == 0) { + rc = TPM_Load32(&usedCount, stream, stream_size); + } + if (rc == 0) { + printf(" TPM_NVIndexEntries_LoadVolatile: usedCount %u\n", usedCount); + if (usedCount != tpm_nv_index_entries->nvIndexCount) { + printf("TPM_NVIndexEntries_LoadVolatile: Error (fatal), " + "usedCount %u does not equal slot count %u\n", + usedCount, tpm_nv_index_entries->nvIndexCount); + rc = TPM_FAIL; + } + } + /* deserialize the stream into the TPM_NV_INDEX_ENTRIES array */ + for (entryIndex = 0 ; + (rc == 0) && (entryIndex < tpm_nv_index_entries->nvIndexCount) ; + entryIndex++) { + + tpm_nv_data_public = &(tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo); + printf(" TPM_NVIndexEntries_LoadVolatile: Loading index %08x\n", + tpm_nv_data_public->nvIndex); + /* load bReadSTClear */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_nv_data_public->bReadSTClear), stream, stream_size); + } + /* load bWriteSTClear */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_nv_data_public->bWriteSTClear), stream, stream_size); + } + } + return rc; +} + +/* TPM_NVIndexEntries_StoreVolatile() serializes the volatile members of the + TPM_NV_INDEX_ENTRIES array into the TPM_STORE_BUFFER. +*/ + +TPM_RESULT TPM_NVIndexEntries_StoreVolatile(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + uint32_t usedCount; + uint32_t entryIndex; + TPM_NV_DATA_PUBLIC *tpm_nv_data_public; + + printf(" TPM_NVIndexEntries_StoreVolatile: %u slots\n", tpm_nv_index_entries->nvIndexCount); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NV_INDEX_ENTRIES_VOLATILE_V1); + } + /* Get the number of used slots. If indexes were deleted since the last TPM_Init, there can be + some unused slots. */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetUsedCount(&usedCount, tpm_nv_index_entries); + } + /* store usedCount */ + if (rc == 0) { + printf(" TPM_NVIndexEntries_StoreVolatile: usedCount %u\n", usedCount); + rc = TPM_Sbuffer_Append32(sbuffer, usedCount); + } + /* save entries into the array */ + for (entryIndex = 0 ; + (rc == 0) && (entryIndex < tpm_nv_index_entries->nvIndexCount) ; + entryIndex++) { + /* Only save used slots. During a rollback, slots are deleted and recreated. At that time, + unused slots will be reclaimed. */ + if (tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex != + TPM_NV_INDEX_LOCK) { + + tpm_nv_data_public = &(tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo); + printf(" TPM_NVIndexEntries_StoreVolatile: Storing index %08x\n", + tpm_nv_data_public->nvIndex); + /* store bReadSTClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_nv_data_public->bReadSTClear), sizeof(TPM_BOOL)); + } + /* store bWriteSTClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_nv_data_public->bWriteSTClear), sizeof(TPM_BOOL)); + } + } + } + return rc; +} + +/* TPM_NVIndexEntries_GetVolatile() saves an array of the NV defined space volatile flags. + + The array is used during a rollback, since the volatile flags are not stored in NVRAM +*/ + +TPM_RESULT TPM_NVIndexEntries_GetVolatile(TPM_NV_DATA_ST **tpm_nv_data_st, /* freed by caller */ + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + uint32_t usedCount; + uint32_t entryIndex; + uint32_t usedIndex; + + printf(" TPM_NVIndexEntries_GetVolatile: %u slots\n", tpm_nv_index_entries->nvIndexCount); + /* Get the number of used slots. If indexes were deleted since the last TPM_Init, there can be + some unused slots. */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetUsedCount(&usedCount, tpm_nv_index_entries); + } + /* allocate memory for the array, nvIndexCount TPM_NV_DATA_SENSITIVE structures */ + if ((rc == 0) && (usedCount > 0)) { + printf(" TPM_NVIndexEntries_GetVolatile: Aloocating for %u used slots\n", usedCount); + rc = TPM_Malloc((unsigned char **)tpm_nv_data_st, + sizeof(TPM_NV_DATA_ST) * usedCount); + } + /* save entries into the array */ + for (entryIndex = 0 , usedIndex = 0 ; + (rc == 0) && (entryIndex < tpm_nv_index_entries->nvIndexCount) && (usedCount > 0) ; + entryIndex++) { + /* Only save used slots. During a rollback, slots are deleted and recreated. At that time, + unused slots will be reclaimed. */ + if (tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex != + TPM_NV_INDEX_LOCK) { + + printf(" TPM_NVIndexEntries_GetVolatile: Saving slot %u at used %u NV index %08x\n", + entryIndex, usedIndex, + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex); + + printf(" TPM_NVIndexEntries_GetVolatile: bReadSTClear %u bWriteSTClear %u\n", + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bReadSTClear, + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bWriteSTClear); + (*tpm_nv_data_st)[usedIndex].nvIndex = + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.nvIndex; + (*tpm_nv_data_st)[usedIndex].bReadSTClear = + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bReadSTClear; + (*tpm_nv_data_st)[usedIndex].bWriteSTClear = + tpm_nv_index_entries->tpm_nvindex_entry[entryIndex].pubInfo.bWriteSTClear; + usedIndex++; + } + } + return rc; +} + +/* TPM_NVIndexEntries_SetVolatile() restores an array of the NV defined space volatile flags. + + The array is used during a rollback, since the volatile flags are not stored in NVRAM +*/ + +TPM_RESULT TPM_NVIndexEntries_SetVolatile(TPM_NV_DATA_ST *tpm_nv_data_st, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + uint32_t usedCount; + uint32_t i; + + printf(" TPM_NVIndexEntries_SetVolatile: %u slots\n", tpm_nv_index_entries->nvIndexCount); + /* Get the number of used slots. This should be equal to the total number of slots. */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetUsedCount(&usedCount, tpm_nv_index_entries); + } + if (rc == 0) { + if (usedCount != tpm_nv_index_entries->nvIndexCount) { + printf("TPM_NVIndexEntries_SetVolatile: Error (fatal), " + "usedCount %u does not equal slot count %u\n", + usedCount, tpm_nv_index_entries->nvIndexCount); + rc = TPM_FAIL; + } + } + /* if the used count is non-zero, the volatile array should not be NULL */ + if (rc == 0) { + if ((usedCount > 0) && (tpm_nv_data_st == NULL)) { + printf("TPM_NVIndexEntries_SetVolatile: Error (fatal), " + "usedCount %u unconsistant with volatile array NULL\n", usedCount); + rc = TPM_FAIL; + } + } + /* copy entries into the array */ + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + printf(" TPM_NVIndexEntries_SetVolatile: slot %u index %08x\n", + i, tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); + /* sanity check on a mismatch of entries between the save and restore */ + if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != + tpm_nv_data_st[i].nvIndex) { + + printf("TPM_NVIndexEntries_SetVolatile: Error (fatal), " + "mismatch NV entry %08x, saved %08x\n", + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex, + tpm_nv_data_st[i].nvIndex); + rc = TPM_FAIL; + } + /* restore entries from the array */ + else { + printf(" TPM_NVIndexEntries_SetVolatile: bReadSTClear %u bWriteSTClear %u\n", + tpm_nv_data_st[i].bReadSTClear, tpm_nv_data_st[i].bWriteSTClear); + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bReadSTClear = + tpm_nv_data_st[i].bReadSTClear; + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.bWriteSTClear = + tpm_nv_data_st[i].bWriteSTClear; + } + } + return rc; +} + +/* TPM_NVIndexEntries_GetFreeEntry() gets a free entry in the TPM_NV_INDEX_ENTRIES array. + + If a free entry exists, it it returned. It should already be initialized. + + If a free entry does not exist, it it created and initialized. + + If a slot cannot be created, tpm_nv_data_sensitive returns NULL, so a subsequent free is safe. +*/ + +TPM_RESULT TPM_NVIndexEntries_GetFreeEntry(TPM_NV_DATA_SENSITIVE **tpm_nv_data_sensitive, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + size_t i; + + printf(" TPM_NVIndexEntries_GetFreeEntry: Searching %u slots\n", + tpm_nv_index_entries->nvIndexCount); + /* for debug - trace the entire TPM_NV_INDEX_ENTRIES array */ + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + printf(" TPM_NVIndexEntries_GetFreeEntry: slot %lu entry %08x\n", + (unsigned long)i, (*tpm_nv_data_sensitive)->pubInfo.nvIndex); + } + /* search the existing array for a free entry */ + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) && !done ; i++) { + *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + /* if the entry is not used */ + if ((*tpm_nv_data_sensitive)->pubInfo.nvIndex == TPM_NV_INDEX_LOCK) { + printf(" TPM_NVIndexEntries_GetFreeEntry: Found free slot %lu\n", (unsigned long)i); + done = TRUE; + } + } + /* need to expand the array */ + if ((rc == 0) && !done) { + *tpm_nv_data_sensitive = NULL; + rc = TPM_Realloc((unsigned char **)&(tpm_nv_index_entries->tpm_nvindex_entry), + sizeof(TPM_NV_DATA_SENSITIVE) * (i + 1)); + } + /* initialize the new entry in the array */ + if ((rc == 0) && !done) { + printf(" TPM_NVIndexEntries_GetFreeEntry: Created new slot at index %lu\n", + (unsigned long)i); + *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + TPM_NVDataSensitive_Init(*tpm_nv_data_sensitive); + tpm_nv_index_entries->nvIndexCount++; + } + return rc; +} + +/* TPM_NVIndexEntries_GetEntry() gets the TPM_NV_DATA_SENSITIVE entry corresponding to nvIndex. + + Returns TPM_BADINDEX on non-existent nvIndex +*/ + +TPM_RESULT TPM_NVIndexEntries_GetEntry(TPM_NV_DATA_SENSITIVE **tpm_nv_data_sensitive, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_NV_INDEX nvIndex) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_NVIndexEntries_GetEntry: Getting NV index %08x in %u slots\n", + nvIndex, tpm_nv_index_entries->nvIndexCount); + /* for debug tracing */ + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + printf(" TPM_NVIndexEntries_GetEntry: slot %lu entry %08x\n", + (unsigned long)i, (*tpm_nv_data_sensitive)->pubInfo.nvIndex); + } + /* check for the special index that indicates an empty entry */ + if (rc == 0) { + if (nvIndex == TPM_NV_INDEX_LOCK) { + rc = TPM_BADINDEX; + } + } + for (i = 0 , found = FALSE ; + (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) && !found ; + i++) { + + *tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + if ((*tpm_nv_data_sensitive)->pubInfo.nvIndex == nvIndex) { + printf(" TPM_NVIndexEntries_GetEntry: Found NV index at slot %lu\n", (unsigned long)i); + printf(" TPM_NVIndexEntries_GetEntry: permission %08x dataSize %u\n", + (*tpm_nv_data_sensitive)->pubInfo.permission.attributes, + (*tpm_nv_data_sensitive)->pubInfo.dataSize); + printf(" TPM_NVIndexEntries_GetEntry: " + "bReadSTClear %02x bWriteSTClear %02x bWriteDefine %02x\n", + (*tpm_nv_data_sensitive)->pubInfo.bReadSTClear, + (*tpm_nv_data_sensitive)->pubInfo.bWriteSTClear, + (*tpm_nv_data_sensitive)->pubInfo.bWriteDefine); + found = TRUE; + } + } + if (rc == 0) { + if (!found) { + printf(" TPM_NVIndexEntries_GetEntry: NV index not found\n"); + rc = TPM_BADINDEX; + } + } + return rc; +} + +/* TPM_NVIndexEntries_GetUsedCount() returns the number of used entries in the TPM_NV_INDEX_ENTRIES + array. + + At startup, all entries will be used. If an NV index is deleted, the entryis marked unused, but + the TPM_NV_INDEX_ENTRIES space is not reclaimed until the next startup. +*/ + +TPM_RESULT TPM_NVIndexEntries_GetUsedCount(uint32_t *count, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + size_t i; + + *count = 0; + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + /* if the entry is used */ + if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { + (*count)++; + } + } + printf(" TPM_NVIndexEntries_GetUsedCount: Used count %d in %u slots\n", + *count, tpm_nv_index_entries->nvIndexCount); + return rc; +} + +/* TPM_NVIndexEntries_GetNVList() serializes a list of the used NV indexes into the + TPM_STORE_BUFFER +*/ + +TPM_RESULT TPM_NVIndexEntries_GetNVList(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_NVIndexEntries_GetNVList: Creating list from %u slots\n", + tpm_nv_index_entries->nvIndexCount); + + for (i = 0 ; (rc == 0) && (i < tpm_nv_index_entries->nvIndexCount) ; i++) { + /* if the entry is used */ + if (tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { + rc = TPM_Sbuffer_Append32(sbuffer, + tpm_nv_index_entries->tpm_nvindex_entry[i].pubInfo.nvIndex); + } + } + return rc; +} + +/* TPM_NVIndexEntries_GetUsedSpace() gets the NV space consumed by NV defined space indexes. + + It does it inefficiently but reliably by serializing the structure with the same function used + when writing to NV storage. +*/ + +TPM_RESULT TPM_NVIndexEntries_GetUsedSpace(uint32_t *usedSpace, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + const unsigned char *buffer; + + printf(" TPM_NVIndexEntries_GetUsedSpace:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize NV defined space */ + if (rc == 0) { + rc = TPM_NVIndexEntries_Store(&sbuffer, tpm_nv_index_entries); + } + /* get the serialized buffer and its length */ + if (rc == 0) { + TPM_Sbuffer_Get(&sbuffer, &buffer, usedSpace); + printf(" TPM_NVIndexEntries_GetUsedSpace: Used space %u\n", *usedSpace); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_NVIndexEntries_GetFreeSpace() gets the total free NV defined space. + + When defining an index, not all can be used for data, as some is consumed by metadata such as + authorization and the index number. +*/ + +TPM_RESULT TPM_NVIndexEntries_GetFreeSpace(uint32_t *freeSpace, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries) +{ + TPM_RESULT rc = 0; + uint32_t usedSpace; + + printf(" TPM_NVIndexEntries_GetFreeSpace:\n"); + /* get the used space */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetUsedSpace(&usedSpace, tpm_nv_index_entries); + } + /* sanity check */ + if (rc == 0) { + if (usedSpace > TPM_MAX_NV_DEFINED_SIZE) { + printf("TPM_NVIndexEntries_GetFreeSpace: used %u greater than max %u\n", + usedSpace, TPM_MAX_NV_DEFINED_SIZE); + rc = TPM_NOSPACE; + } + } + /* calculate the free space */ + if (rc == 0) { + *freeSpace = TPM_MAX_NV_DEFINED_SIZE - usedSpace; + printf(" TPM_NVIndexEntries_GetFreeSpace: Free space %u\n", *freeSpace); + } + return rc; +} + +/* TPM_OwnerClear: rev 99 + 12. The TPM MUST deallocate all defined NV storage areas where + a. TPM_NV_PER_OWNERWRITE is TRUE if nvIndex does not have the "D" bit set + b. TPM_NV_PER_OWNERREAD is TRUE if nvIndex does not have the "D" bit set + c. The TPM MUST NOT deallocate any other currently defined NV storage areas. + + TPM_RevokeTrust: a. NV items with the pubInfo -> nvIndex D value set MUST be deleted. This + changes the TPM_OwnerClear handling of the same NV areas + + If deleteAllNvram is TRUE, all NVRAM is deleted. If it is FALSE, indexes with the D bit set are + not cleared. + + The write to NV space is done bu the caller. +*/ + +TPM_RESULT TPM_NVIndexEntries_DeleteOwnerAuthorized(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_BOOL deleteAllNvram) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; /* an entry in the array */ + + printf(" TPM_NVIndexEntries_DeleteOwnerAuthorized: Deleting from %u slots\n", + tpm_nv_index_entries->nvIndexCount); + for (i = 0 ; i < tpm_nv_index_entries->nvIndexCount ; i++) { + /* get an entry in the array */ + tpm_nv_data_sensitive = &(tpm_nv_index_entries->tpm_nvindex_entry[i]); + + /* if the index is in use */ + if (tpm_nv_data_sensitive->pubInfo.nvIndex != TPM_NV_INDEX_LOCK) { + /* if TPM_NV_PER_OWNERWRITE or TPM_NV_PER_OWNERREAD and nvIndex does not have the "D" + bit set */ + if ((tpm_nv_data_sensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE) || + (tpm_nv_data_sensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD)) { + if (!(tpm_nv_data_sensitive->pubInfo.nvIndex & TPM_NV_INDEX_D_BIT) || + deleteAllNvram) { + /* delete the index */ + printf(" TPM_NVIndexEntries_DeleteOwnerAuthorized: Deleting NV index %08x\n", + tpm_nv_data_sensitive->pubInfo.nvIndex); + TPM_NVDataSensitive_Delete(tpm_nv_data_sensitive); + } + } + } + } + return rc; +} + +/* TPM_NVIndexEntries_GetDataPublic() returns the TPM_NV_DATA_PUBLIC corresponding to the nvIndex + */ + +TPM_RESULT TPM_NVIndexEntries_GetDataPublic(TPM_NV_DATA_PUBLIC **tpm_nv_data_public, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_NV_INDEX nvIndex) +{ + TPM_RESULT rc = 0; + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; + + printf(" TPM_NVIndexEntries_GetDataPublic: Getting data at NV index %08x\n", nvIndex); + if (rc == 0) { + rc = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive, + tpm_nv_index_entries, + nvIndex); + } + if (rc == 0) { + *tpm_nv_data_public = &(tpm_nv_data_sensitive->pubInfo); + } + return rc; +} + +/* + Command Processing Functions +*/ + +/* 20.4 TPM_NV_ReadValue rev 114 + + Read a value from the NV store. This command uses optional owner authorization. + + Action 1 indicates that if the NV area is not locked then reading of the NV area continues + without ANY authorization. This is intentional, and allows a platform manufacturer to set the NV + areas, read them back, and then lock them all without having to install a TPM owner. +*/ + +TPM_RESULT TPM_Process_NVReadValue(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NV_INDEX nvIndex; /* The index of the area to set */ + uint32_t offset = 0; /* The offset into the area */ + uint32_t dataSize = 0; /* The size of the data area */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for TPM Owner + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by caller */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* HMAC key: TPM Owner authorization */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL ignore_auth = FALSE; + TPM_BOOL dir = FALSE; + TPM_BOOL physicalPresence; + TPM_BOOL isGPIO; + BYTE *gpioData = NULL; + TPM_NV_DATA_SENSITIVE *d1NvdataSensitive; + uint32_t s1Last; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER data; /* The data to set the area to */ + + printf("TPM_Process_NVReadValue: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&data); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get nvIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); + } + /* get offset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&offset, &command, ¶mSize); + } + /* get dataSize parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&dataSize, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT | + TPM_CHECK_NV_NOAUTH)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_NVReadValue: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. If TPM_PERMANENT_FLAGS -> nvLocked is FALSE then all authorization checks are + ignored */ + /* a. Ignored checks include physical presence, owner authorization, PCR, bReadSTClear, + locality, TPM_NV_PER_OWNERREAD, disabled and deactivated */ + /* b. TPM_NV_PER_AUTHREAD is not ignored. */ + /* c. If ownerAuth is present, the TPM MAY check the authorization HMAC. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVReadValue: index %08x offset %u dataSize %u\n", + nvIndex, offset, dataSize); + if (!(tpm_state->tpm_permanent_flags.nvLocked)) { + printf("TPM_Process_NVReadValue: nvLocked FALSE, ignoring authorization\n"); + ignore_auth = TRUE; + } + /* determine whether the nvIndex is legal GPIO space */ + if (returnCode == 0) { + returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); + } + } + /* 2. Set D1 a TPM_NV_DATA_AREA structure to the area pointed to by nvIndex, if not found + return TPM_BADINDEX */ + if (returnCode == TPM_SUCCESS) { + /* a. If nvIndex = TPM_NV_INDEX_DIR, set D1 to TPM_PERMANENT_DATA -> authDir[0] */ + if (nvIndex == TPM_NV_INDEX_DIR) { + printf("TPM_Process_NVReadValue: Reading DIR\n"); + dir = TRUE; + } + else { + printf("TPM_Process_NVReadValue: Loading data from NVRAM\n"); + returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, + &(tpm_state->tpm_nv_index_entries), + nvIndex); + if (returnCode != 0) { + printf("TPM_Process_NVReadValue: Error, NV index %08x not found\n", nvIndex); + } + } + } + /* Do not check permission for DIR, DIR is no-auth */ + if ((returnCode == TPM_SUCCESS) && !dir) { + /* 3. If TPM_PERMANENT_FLAGS -> nvLocked is TRUE */ + if (tpm_state->tpm_permanent_flags.nvLocked) { + /* a. If D1 -> permission -> TPM_NV_PER_OWNERREAD is TRUE */ + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD) { + /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, return TPM_DISABLED */ + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_Process_NVReadValue: Error, disabled\n"); + return TPM_DISABLED; + } + /* ii. If TPM_STCLEAR_FLAGS -> deactivated is TRUE, return TPM_DEACTIVATED */ + else if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_Process_NVReadValue: Error, deactivated\n"); + return TPM_DEACTIVATED;; + } + } + /* NOTE: Intel software requires NV access disabled and deactivated */ + /* b. If D1 -> permission -> TPM_NV_PER_OWNERREAD is FALSE */ + /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, the TPM MAY return TPM_DISABLED */ + /* ii. If TPM_STCLEAR_FLAGS -> deactivated is TRUE, the TPM MAY return + TPM_DEACTIVATED */ + } + } + /* 4. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ + /* NOTE: This is optional if ignore_auth is TRUE */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !dir) { + /* a. If D1 -> TPM_NV_PER_OWNERREAD is FALSE return TPM_AUTH_CONFLICT */ + if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD)) { + printf("TPM_Process_NVReadValue: Error, " + "owner authorization conflict, attributes %08x\n", + d1NvdataSensitive->pubInfo.permission.attributes); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* b. Validate command and parameters using TPM Owners authorization on error return + TPM_AUTHFAIL */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !ignore_auth) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 5. Else */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !dir) { + /* a. If D1 -> TPM_NV_PER_AUTHREAD is TRUE return TPM_AUTH_CONFLICT */ + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHREAD) { + printf("TPM_Process_NVReadValue: Error, authorization conflict TPM_NV_PER_AUTHREAD\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* b. If D1 -> TPM_NV_PER_OWNERREAD is TRUE return TPM_AUTH_CONFLICT */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !ignore_auth && !dir) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERREAD) { + printf("TPM_Process_NVReadValue: Error, authorization conflict TPM_NV_PER_OWNERREAD\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* 6. Check that D1 -> pcrInfoRead -> localityAtRelease for TPM_STANY_DATA -> localityModifier + is TRUE */ + /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* b. On error return TPM_BAD_LOCALITY */ + /* NOTE Done by TPM_PCRInfoShort_CheckDigest() */ + /* 7. If D1 -> attributes specifies TPM_NV_PER_PPREAD then validate physical presence is + asserted if not return TPM_BAD_PRESENCE */ + if ((returnCode == TPM_SUCCESS) && !ignore_auth && !dir) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPREAD) { + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_NVReadValue: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + } + } + if ((returnCode == TPM_SUCCESS) && !ignore_auth && !dir) { + /* 8. If D1 -> TPM_NV_PER_READ_STCLEAR then */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_READ_STCLEAR) && + /* a. If D1 -> bReadSTClear is TRUE return TPM_DISABLED_CMD */ + (d1NvdataSensitive->pubInfo.bReadSTClear)) { + printf("TPM_Process_NVReadValue: Error, area locked by bReadSTClear\n"); + returnCode = TPM_DISABLED_CMD; + } + } + /* 9. If D1 -> pcrInfoRead -> pcrSelection specifies a selection of PCR */ + /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoRead */ + /* b. Compare P1 to D1 -> pcrInfoRead -> digestAtRelease return TPM_WRONGPCRVAL on + mismatch */ + if ((returnCode == TPM_SUCCESS) && !ignore_auth && !dir) { + returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoRead), + tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.localityModifier); + } + if (returnCode == TPM_SUCCESS && !dir) { + /* 10. If dataSize is 0 then */ + if (dataSize == 0) { + printf("TPM_Process_NVReadValue: dataSize 0, setting bReadSTClear\n"); + /* a. Set D1 -> bReadSTClear to TRUE */ + d1NvdataSensitive->pubInfo.bReadSTClear = TRUE; + /* b. Set data to NULL (output parameter dataSize to 0) */ + /* NOTE Done by TPM_SizedBuffer_Init */ + } + /* 11. Else (if dataSize is not 0) */ + else { + if (returnCode == TPM_SUCCESS) { + /* a. Set S1 to offset + dataSize */ + s1Last = offset + dataSize; /* set to last data point */ + /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ + if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { + printf("TPM_Process_NVReadValue: Error, NVRAM dataSize %u\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOSPACE; + } + } + /* c. Set data to area pointed to by offset */ + if ((returnCode == TPM_SUCCESS) && !isGPIO) { + TPM_PrintFour("TPM_Process_NVReadValue: read data", + d1NvdataSensitive->data + offset); + returnCode = TPM_SizedBuffer_Set(&data, + dataSize, d1NvdataSensitive->data + offset); + } + /* GPIO */ + if ((returnCode == TPM_SUCCESS) && isGPIO) { + returnCode = TPM_Malloc(&gpioData, dataSize); /* freed @2 */ + } + if ((returnCode == TPM_SUCCESS) && isGPIO) { + printf("TPM_Process_NVReadValue: Reading GPIO\n"); + returnCode = TPM_IO_GPIO_Read(nvIndex, + dataSize, + gpioData, + tpm_state->tpm_number); + } + if ((returnCode == TPM_SUCCESS) && isGPIO) { + returnCode = TPM_SizedBuffer_Set(&data, + dataSize, gpioData); + } + } + } + /* DIR read */ + if (returnCode == TPM_SUCCESS && dir) { + /* DIR is hard coded as a TPM_DIRVALUE array */ + if (returnCode == TPM_SUCCESS) { + s1Last = offset + dataSize; /* set to last data point */ + if (s1Last > TPM_DIGEST_SIZE) { + printf("TPM_Process_NVReadValue: Error, NVRAM dataSize %u too small\n", + TPM_DIGEST_SIZE); + returnCode = TPM_NOSPACE; + } + } + /* i.This includes partial reads of TPM_NV_INDEX_DIR. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVReadValue: Copying data\n"); + returnCode = TPM_SizedBuffer_Set(&data, dataSize, + tpm_state->tpm_permanent_data.authDIR + offset); + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_NVReadValue: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return data */ + returnCode = TPM_SizedBuffer_Store(response, &data); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&data); /* @1 */ + free(gpioData); /* @2 */ + return rcf; +} + +/* 20.5 TPM_NV_ReadValueAuth rev 87 + + This command requires that the read be authorized by a value set with the blob. +*/ + +TPM_RESULT TPM_Process_NVReadValueAuth(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NV_INDEX nvIndex; /* The index of the area to set */ + uint32_t offset = 0; /* The offset from the data area */ + uint32_t dataSize = 0; /* The size of the data area */ + TPM_AUTHHANDLE authHandle; /* The auth handle for the NV element authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA authHmac; /* HMAC key: nv element authorization */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_NV_DATA_SENSITIVE *d1NvdataSensitive; + uint32_t s1Last; + TPM_BOOL physicalPresence; + TPM_BOOL isGPIO; + BYTE *gpioData = NULL; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_SIZED_BUFFER data; /* The data */ + + printf("TPM_Process_NVReadValueAuth: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&data); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get nvIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); + } + /* get offset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&offset, &command, ¶mSize); + } + /* get dataSize parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&dataSize, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + authHmac, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_NVReadValueAuth: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* determine whether the nvIndex is legal GPIO space */ + if (returnCode == 0) { + returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); + } + /* 1. Locate and set D1 to the TPM_NV_DATA_AREA that corresponds to nvIndex, on error return + TPM_BAD_INDEX */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVReadValueAuth: index %08x offset %u dataSize %u\n", + nvIndex, offset, dataSize); + printf("TPM_Process_NVReadValueAuth: Loading data from NVRAM\n"); + returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, + &(tpm_state->tpm_nv_index_entries), + nvIndex); + if (returnCode != 0) { + printf("TPM_Process_NVReadValueAuth: Error, NV index %08x not found\n", nvIndex); + } + } + /* 2. If D1 -> TPM_NV_PER_AUTHREAD is FALSE return TPM_AUTH_CONFLICT */ + if (returnCode == TPM_SUCCESS) { + if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHREAD)) { + printf("TPM_Process_NVReadValueAuth: Error, authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* 3. Validate authHmac using D1 -> authValue on error return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_NV, + ordinal, + NULL, + &(d1NvdataSensitive->authValue), /* OIAP */ + d1NvdataSensitive->digest); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + authHmac); /* Authorization digest for input */ + } + /* 4. If D1 -> attributes specifies TPM_NV_PER_PPREAD then validate physical presence is + asserted if not return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPREAD) { + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_NVReadValueAuth: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + } + } + /* 5. Check that D1 -> pcrInfoRead -> localityAtRelease for TPM_STANY_DATA -> localityModifier + is TRUE */ + /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* b. On error return TPM_BAD_LOCALITY */ + /* 6. If D1 -> pcrInfoRead -> pcrSelection specifies a selection of PCR */ + /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoRead */ + /* b. Compare P1 to D1 -> pcrInfoRead -> digestAtRelease return TPM_WRONGPCRVAL on + mismatch */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoRead), + tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.localityModifier); + } + if (returnCode == TPM_SUCCESS) { + /* 7. If D1 specifies TPM_NV_PER_READ_STCLEAR then */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_READ_STCLEAR) && + /* a. If D1 -> bReadSTClear is TRUE return TPM_DISABLED_CMD */ + (d1NvdataSensitive->pubInfo.bReadSTClear)) { + printf("TPM_Process_NVReadValueAuth: Error, area locked by bReadSTClear\n"); + returnCode = TPM_DISABLED_CMD; + } + } + if (returnCode == TPM_SUCCESS) { + /* 8. If dataSize is 0 then */ + if (dataSize == 0) { + printf("TPM_Process_NVReadValueAuth: dataSize 0, setting bReadSTClear\n"); + /* a. Set D1 -> bReadSTClear to TRUE */ + d1NvdataSensitive->pubInfo.bReadSTClear = TRUE; + /* b. Set data to NULL */ + /* NOTE Done by TPM_SizedBuffer_Init */ + } + /* 9. Else (if dataSize is not 0) */ + else { + if (returnCode == TPM_SUCCESS) { + /* a. Set S1 to offset + dataSize */ + s1Last = offset + dataSize; /* set to last data point */ + /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ + if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { + printf("TPM_Process_NVReadValueAuth: Error, NVRAM dataSize %u too small\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOSPACE; + } + } + /* c. Set data to area pointed to by offset */ + if ((returnCode == TPM_SUCCESS) && !isGPIO) { + TPM_PrintFour("TPM_Process_NVReadValueAuth: read data", + d1NvdataSensitive->data + offset); + returnCode = TPM_SizedBuffer_Set(&data, dataSize, d1NvdataSensitive->data + offset); + } + /* GPIO */ + if ((returnCode == TPM_SUCCESS) && isGPIO) { + returnCode = TPM_Malloc(&gpioData, dataSize); /* freed @2 */ + } + if ((returnCode == TPM_SUCCESS) && isGPIO) { + printf("TPM_Process_NVReadValueAuth: Reading GPIO\n"); + returnCode = TPM_IO_GPIO_Read(nvIndex, + dataSize, + gpioData, + tpm_state->tpm_number); + } + if ((returnCode == TPM_SUCCESS) && isGPIO) { + returnCode = TPM_SizedBuffer_Set(&data, + dataSize, gpioData); + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_NVReadValueAuth: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return data */ + returnCode = TPM_SizedBuffer_Store(response, &data); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&data); /* @1 */ + return rcf; +} + +/* 20.2 TPM_NV_WriteValue rev 117 + + This command writes the 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. + + The action setting bGlobalLock to TRUE is intentionally before the action checking the + owner authorization. This allows code (e.g., a BIOS) to lock NVRAM without knowing the + owner authorization. + + The DIR (TPM_NV_INDEX_DIR) has the attributes TPM_NV_PER_OWNERWRITE and TPM_NV_WRITEALL. + + FIXME: A simpler way to do DIR might be to create the DIR as NV defined space at first + initialization and remove the special casing here. +*/ + +TPM_RESULT TPM_Process_NVWriteValue(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + int irc; + + /* input parameters */ + TPM_NV_INDEX nvIndex; /* The index of the area to set */ + uint32_t offset = 0; /* The offset into the NV Area */ + TPM_SIZED_BUFFER data; /* The data to set the area to */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for TPM Owner */ + TPM_NONCE nonceOdd; /* Nonce generated by caller */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest HMAC key: TPM Owner auth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey = NULL; + TPM_BOOL ignore_auth = FALSE; + TPM_BOOL index0 = FALSE; + TPM_BOOL done = FALSE; + TPM_BOOL dir = FALSE; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_NV_DATA_SENSITIVE *d1NvdataSensitive; + uint32_t s1Last; + TPM_BOOL physicalPresence; + TPM_BOOL isGPIO; + uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* temp for noOwnerNVWrite, initialize to + silence compiler */ + TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_NVWriteValue: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&data); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get nvIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&offset, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&data, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT | + TPM_CHECK_NV_NOAUTH)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_NVWriteValue: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVWriteValue: index %08x offset %u dataSize %u\n", + nvIndex, offset, data.size); + TPM_PrintFour("TPM_Process_NVWriteValue: data", data.buffer); + /* 1. If TPM_PERMANENT_FLAGS -> nvLocked is FALSE then all authorization checks except for + the max NV writes are ignored */ + /* a. Ignored checks include physical presence, owner authorization, TPM_NV_PER_OWNERWRITE, + PCR, bWriteDefine, bGlobalLock, bWriteSTClear, locality, disabled and deactivated */ + /* b. TPM_NV_PER_AUTHWRITE is not ignored. */ + /* a.If ownerAuth is present, the TPM MAY check the authorization HMAC. */ + if (!(tpm_state->tpm_permanent_flags.nvLocked)) { + printf("TPM_Process_NVWriteValue: nvLocked FALSE, ignoring authorization\n"); + ignore_auth = TRUE; + } + if (nvIndex == TPM_NV_INDEX0) { + index0 = TRUE; + } + /* determine whether the nvIndex is legal GPIO space */ + if (returnCode == 0) { + returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); + } + } + /* 2. Locate and set D1 to the TPM_NV_DATA_AREA that corresponds to nvIndex, return TPM_BADINDEX + on error */ + if ((returnCode == TPM_SUCCESS) && !index0) { + /* a. If nvIndex = TPM_NV_INDEX_DIR, set D1 to TPM_PERMANENT_DATA -> authDir[0] */ + if (nvIndex == TPM_NV_INDEX_DIR) { + printf("TPM_Process_NVWriteValue: Writing DIR\n"); + dir = TRUE; + } + else { + printf("TPM_Process_NVWriteValue: Loading data space from NVRAM\n"); + returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, + &(tpm_state->tpm_nv_index_entries), + nvIndex); + if (returnCode != 0) { + printf("TPM_Process_NVWriteValue: Error, NV index %08x not found\n", nvIndex); + } + } + } + if ((returnCode == TPM_SUCCESS) && !index0) { + /* 3. If TPM_PERMANENT_FLAGS -> nvLocked is TRUE */ + if (tpm_state->tpm_permanent_flags.nvLocked) { + /* a. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is TRUE */ + if (dir || /* DIR always has TPM_NV_PER_OWNERWRITE */ + (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE)) { + /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, return TPM_DISABLED */ + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_Process_NVWriteValue: Error, disabled\n"); + return TPM_DISABLED; + } + /* ii.If TPM_STCLEAR_FLAGS -> deactivated is TRUE, return TPM_DEACTIVATED */ + else if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_Process_NVWriteValue: Error, deactivated\n"); + return TPM_DEACTIVATED;; + } + } + /* NOTE: Intel software requires NV access disabled and deactivated */ + /* b. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is FALSE */ + /* i. If TPM_PERMANENT_FLAGS -> disable is TRUE, the TPM MAY return TPM_DISABLED */ + /* ii. If TPM_STCLEAR_FLAGS -> deactivated is TRUE, the TPM MAY return + TPM_DEACTIVATED */ + } + } + /* 4. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !dir && !index0) { + /* a. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is FALSE return TPM_AUTH_CONFLICT */ + /* i. This check is ignored if nvIndex is TPM_NV_INDEX0. */ + if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE)) { + printf("TPM_Process_NVWriteValue: Error, owner authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* b. Validate command and parameters using ownerAuth HMAC with TPM Owner authentication as the + secret, return TPM_AUTHFAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + /* NOTE: This is optional if ignore_auth is TRUE */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 5. Else */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !ignore_auth && !index0) { + /* a. If D1 -> permission -> TPM_NV_PER_OWNERWRITE is TRUE return TPM_AUTH_CONFLICT */ + if (dir || /* DIR always has TPM_NV_PER_OWNERWRITE */ + (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_OWNERWRITE)) { + printf("TPM_Process_NVWriteValue: Error, no owner authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !index0) { + /* b. If no TPM Owner validate max NV writes without an owner */ + /* i. Set NV1 to TPM_PERMANENT_DATA -> noOwnerNVWrite */ + nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* ii. Increment NV1 by 1 */ + nv1++; + /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */ + if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) { + printf("TPM_Process_NVWriteValue: Error, max NV writes %d w/o owner reached\n", + tpm_state->tpm_permanent_data.noOwnerNVWrite); + returnCode = TPM_MAXNVWRITES; + } + /* iv. Set NV1_INCREMENTED to TRUE */ + else { + nv1Incremented = TRUE; + } + } + if (returnCode == TPM_SUCCESS) { + /* 6. If nvIndex = 0 then */ + if (nvIndex == 0) { + /* a. If dataSize is not 0, the TPM MAY return TPM_BADINDEX. */ + if (data.size != 0) { + printf("TPM_Process_NVWriteValue: Error, index 0 size %u\n", data.size); + returnCode = TPM_BADINDEX; + } + else { + /* b. Set TPM_STCLEAR_FLAGS -> bGlobalLock to TRUE */ + printf("TPM_Process_NVWriteValue: nvIndex 0, setting bGlobalLock\n"); + tpm_state->tpm_stclear_flags.bGlobalLock = TRUE; + /* c. Return TPM_SUCCESS */ + done = TRUE; + } + } + } + /* 7. If D1 -> permission -> TPM_NV_PER_AUTHWRITE is TRUE return TPM_AUTH_CONFLICT */ + if ((returnCode == TPM_SUCCESS) && !done && !dir) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHWRITE) { + printf("TPM_Process_NVWriteValue: Error, authorization conflict, attributes %08x \n", + d1NvdataSensitive->pubInfo.permission.attributes); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* 8. Check that D1 -> pcrInfoWrite -> localityAtRelease for TPM_STANY_DATA -> localityModifier + is TRUE */ + /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* b. On error return TPM_BAD_LOCALITY */ + /* NOTE Done by TPM_PCRInfoShort_CheckDigest() */ + /* 9. If D1 -> attributes specifies TPM_NV_PER_PPWRITE then validate physical presence is + asserted if not return TPM_BAD_PRESENCE */ + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPWRITE) { + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_NVWriteValue: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + } + } + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { + /* 10. If D1 -> attributes specifies TPM_NV_PER_WRITEDEFINE */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEDEFINE) && + /* a. If D1 -> bWriteDefine is TRUE return TPM_AREA_LOCKED */ + (d1NvdataSensitive->pubInfo.bWriteDefine)) { + printf("TPM_Process_NVWriteValue: Error, area locked by bWriteDefine\n"); + returnCode = TPM_AREA_LOCKED; + } + } + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { + /* 11. If D1 -> attributes specifies TPM_NV_PER_GLOBALLOCK */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) && + /* a. If TPM_STCLEAR_FLAGS -> bGlobalLock is TRUE return TPM_AREA_LOCKED */ + (tpm_state->tpm_stclear_flags.bGlobalLock)) { + printf("TPM_Process_NVWriteValue: Error, area locked by bGlobalLock\n"); + returnCode = TPM_AREA_LOCKED; + } + } + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { + /* 12. If D1 -> attributes specifies TPM_NV_PER_WRITE_STCLEAR */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) && + /* a. If D1 ->bWriteSTClear is TRUE return TPM_AREA_LOCKED */ + (d1NvdataSensitive->pubInfo.bWriteSTClear)) { + printf("TPM_Process_NVWriteValue: Error, area locked by bWriteSTClear\n"); + returnCode = TPM_AREA_LOCKED; + } + } + /* 13. If D1 -> pcrInfoWrite -> pcrSelection specifies a selection of PCR */ + /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoWrite */ + /* b. Compare P1 to D1 -> pcrInfoWrite -> digestAtRelease return TPM_WRONGPCRVAL on mismatch + */ + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && !dir) { + returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoWrite), + tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.localityModifier); + } + if ((returnCode == TPM_SUCCESS) && !done && !dir) { + /* 14. If dataSize = 0 then */ + if (data.size == 0) { + printf("TPM_Process_NVWriteValue: dataSize 0, setting bWriteSTClear, bWriteDefine\n"); + /* a. Set D1 -> bWriteSTClear to TRUE */ + d1NvdataSensitive->pubInfo.bWriteSTClear = TRUE; + /* b. Set D1 -> bWriteDefine */ + if (!d1NvdataSensitive->pubInfo.bWriteDefine) { /* save wearout, only write if + FALSE */ + d1NvdataSensitive->pubInfo.bWriteDefine = TRUE; + /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after strucuture is + written */ + writeAllNV = TRUE; + } + } + /* 15. Else (if dataSize is not 0) */ + else { + if (returnCode == TPM_SUCCESS) { + /* a. Set S1 to offset + dataSize */ + s1Last = offset + data.size; /* set to last data point */ + /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ + if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { + printf("TPM_Process_NVWriteValue: Error, NVRAM dataSize %u too small\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOSPACE; + } + } + if (returnCode == TPM_SUCCESS) { + /* c. If D1 -> attributes specifies TPM_NV_PER_WRITEALL */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEALL) && + /* i. If dataSize != D1 -> dataSize return TPM_NOT_FULLWRITE */ + (data.size != d1NvdataSensitive->pubInfo.dataSize)) { + printf("TPM_Process_NVWriteValue: Error, Must write full %u\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOT_FULLWRITE; + } + } + if (returnCode == TPM_SUCCESS) { + /* not GPIO */ + if (!isGPIO) { + /* wearout optimization, don't write if the data is the same */ + irc = memcmp((d1NvdataSensitive->data) + offset, data.buffer, data.size); + if (irc != 0) { + printf("TPM_Process_NVWriteValue: Copying data\n"); + /* d. Write the new value into the NV storage area */ + memcpy((d1NvdataSensitive->data) + offset, data.buffer, data.size); + /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after + strucuture is written */ + writeAllNV = TRUE; + } + else { + printf("TPM_Process_NVWriteValue: Same data, no copy\n"); + } + } + /* GPIO */ + else { + printf("TPM_Process_NVWriteValue: Writing GPIO\n"); + returnCode = TPM_IO_GPIO_Write(nvIndex, + data.size, + data.buffer, + tpm_state->tpm_number); + } + } + } + } + /* DIR write */ + if ((returnCode == TPM_SUCCESS) && !done && dir) { + /* For TPM_NV_INDEX_DIR, the ordinal MUST NOT set an error code for the "if dataSize = 0" + action. However, the flags set in this case are not applicable to the DIR. */ + if (data.size != 0) { + /* DIR is hard coded as a TPM_DIRVALUE array, TPM_NV_WRITEALL is implied */ + if (returnCode == TPM_SUCCESS) { + if ((offset != 0) || (data.size != TPM_DIGEST_SIZE)) { + printf("TPM_Process_NVWriteValue: Error, Must write full DIR %u\n", + TPM_DIGEST_SIZE); + returnCode = TPM_NOT_FULLWRITE; + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVWriteValue: Copying data\n"); + memcpy(tpm_state->tpm_permanent_data.authDIR, data.buffer, TPM_DIGEST_SIZE); + writeAllNV = TRUE; + } + } + } + if ((returnCode == TPM_SUCCESS) && !done && !dir) { + /* 16. Set D1 -> bReadSTClear to FALSE (unlocked by a successful write) */ + d1NvdataSensitive->pubInfo.bReadSTClear = FALSE; + } + /* 15.d Write the new value into the NV storage area */ + if (writeAllNV) { + printf("TPM_Process_NVWriteValue: Writing data to NVRAM\n"); + /* NOTE Don't do this step until just before the serialization */ + /* e. If NV1_INCREMENTED is TRUE */ + if (nv1Incremented) { + /* i. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ + tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1; + } + } + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_NVWriteValue: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&data); /* @1 */ + return rcf; +} + +/* 20.3 TPM_NV_WriteValueAuth rev 87 + + 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. Otherwise, you should use TPM_NV_WriteValue +*/ + +TPM_RESULT TPM_Process_NVWriteValueAuth(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + int irc; + + /* input parameters */ + TPM_NV_INDEX nvIndex; /* The index of the area to set */ + uint32_t offset = 0; /* The offset into the chunk */ + TPM_SIZED_BUFFER data; /* The data to set the area to */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for NV element + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA authValue; /* HMAC key: NV element auth value */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey = NULL; + TPM_NV_DATA_SENSITIVE *d1NvdataSensitive; + uint32_t s1Last; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL physicalPresence; + TPM_BOOL isGPIO; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_NVWriteValueAuth: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&data); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get nvIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&nvIndex, &command, ¶mSize); + } + /* get offset parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&offset, &command, ¶mSize); + } + /* get data parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&data, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + authValue, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_NVWriteValueAuth: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* determine whether the nvIndex is legal GPIO space */ + if (returnCode == 0) { + returnCode = TPM_NVDataSensitive_IsGPIO(&isGPIO, nvIndex); + } + /* 1. Locate and set D1 to the TPM_NV_DATA_AREA that corresponds to nvIndex, return TPM_BADINDEX + on error */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVWriteValueAuth: index %08x offset %u dataSize %u\n", + nvIndex, offset, data.size); + TPM_PrintFour("TPM_Process_NVWriteValueAuth: data", data.buffer); + printf("TPM_Process_NVWriteValueAuth: Loading data from NVRAM\n"); + returnCode = TPM_NVIndexEntries_GetEntry(&d1NvdataSensitive, + &(tpm_state->tpm_nv_index_entries), + nvIndex); + if (returnCode != 0) { + printf("TPM_Process_NVWriteValueAuth: Error, NV index %08x not found\n", nvIndex); + } + } + /* 2. If D1 -> attributes does not specify TPM_NV_PER_AUTHWRITE then return TPM_AUTH_CONFLICT */ + if (returnCode == TPM_SUCCESS) { + if (!(d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_AUTHWRITE)) { + printf("TPM_Process_NVWriteValueAuth: Error, authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* 3. Validate authValue using D1 -> authValue, return TPM_AUTHFAIL on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_NV, + ordinal, + NULL, + &(d1NvdataSensitive->authValue), /* OIAP */ + d1NvdataSensitive->digest); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + authValue); /* Authorization digest for input */ + } + /* 4. Check that D1 -> pcrInfoWrite -> localityAtRelease for TPM_STANY_DATA -> localityModifier + is TRUE */ + /* a. For example if TPM_STANY_DATA -> localityModifier was 2 then D1 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* b. On error return TPM_BAD_LOCALITY */ + /* NOTE Done by TPM_PCRInfoShort_CheckDigest() */ + /* 5. If D1 -> attributes specifies TPM_NV_PER_PPWRITE then validate physical presence is + asserted if not return TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + if (d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_PPWRITE) { + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_NVWriteValueAuth: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + } + } + /* 6. If D1 -> pcrInfoWrite -> pcrSelection specifies a selection of PCR */ + /* a. Create P1 a composite hash of the PCR specified by D1 -> pcrInfoWrite */ + /* b. Compare P1 to digestAtRelease return TPM_WRONGPCRVAL on mismatch */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoShort_CheckDigest(&(d1NvdataSensitive->pubInfo.pcrInfoWrite), + tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.localityModifier); + } + if (returnCode == TPM_SUCCESS) { + /* 7. If D1 -> attributes specifies TPM_NV_PER_WRITEDEFINE */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEDEFINE) && + /* a. If D1 -> bWriteDefine is TRUE return TPM_AREA_LOCKED */ + (d1NvdataSensitive->pubInfo.bWriteDefine)) { + printf("TPM_Process_NVWriteValueAuth: Error, area locked by bWriteDefine\n"); + returnCode = TPM_AREA_LOCKED; + } + } + if (returnCode == TPM_SUCCESS) { + /* 8. If D1 -> attributes specifies TPM_NV_PER_GLOBALLOCK */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) && + /* a. If TPM_STCLEAR_FLAGS -> bGlobalLock is TRUE return TPM_AREA_LOCKED */ + (tpm_state->tpm_stclear_flags.bGlobalLock)) { + printf("TPM_Process_NVWriteValueAuth: Error, area locked by bGlobalLock\n"); + returnCode = TPM_AREA_LOCKED; + } + } + if (returnCode == TPM_SUCCESS) { + /* 9. If D1 -> attributes specifies TPM_NV_PER_WRITE_STCLEAR */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) && + /* a. If D1 -> bWriteSTClear is TRUE return TPM_AREA_LOCKED */ + (d1NvdataSensitive->pubInfo.bWriteSTClear)) { + printf("TPM_Process_NVWriteValueAuth: Error, area locked by bWriteSTClear\n"); + returnCode = TPM_AREA_LOCKED; + } + } + if (returnCode == TPM_SUCCESS) { + /* 10. If dataSize = 0 then */ + if (data.size == 0) { + printf("TPM_Process_NVWriteValueAuth: " + "dataSize 0, setting bWriteSTClear, bWriteDefine\n"); + /* a. Set D1 -> bWriteSTClear to TRUE */ + d1NvdataSensitive->pubInfo.bWriteSTClear = TRUE; + /* b. Set D1 -> bWriteDefine to TRUE */ + if (!d1NvdataSensitive->pubInfo.bWriteDefine) { /* save wearout, only write if + FALSE */ + d1NvdataSensitive->pubInfo.bWriteDefine = TRUE; + /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after strucuture is + written */ + writeAllNV = TRUE; + } + } + /* 11. Else (if dataSize is not 0) */ + else { + if (returnCode == TPM_SUCCESS) { + /* a. Set S1 to offset + dataSize */ + s1Last = offset + data.size; /* set to last data point */ + /* b. If S1 > D1 -> dataSize return TPM_NOSPACE */ + if (s1Last > d1NvdataSensitive->pubInfo.dataSize) { + printf("TPM_Process_NVWriteValueAuth: Error, NVRAM dataSize %u\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOSPACE; + } + } + if (returnCode == TPM_SUCCESS) { + /* c. If D1 -> attributes specifies TPM_PER_WRITEALL */ + if ((d1NvdataSensitive->pubInfo.permission.attributes & TPM_NV_PER_WRITEALL) && + /* i. If dataSize != D1 -> dataSize return TPM_NOT_FULLWRITE */ + (data.size != d1NvdataSensitive->pubInfo.dataSize)) { + printf("TPM_Process_NVWriteValueAuth: Error, Must write all %u\n", + d1NvdataSensitive->pubInfo.dataSize); + returnCode = TPM_NOT_FULLWRITE; + } + } + if (returnCode == TPM_SUCCESS) { + /* not GPIO */ + if (!isGPIO) { + /* wearout optimization, don't write if the data is the same */ + irc = memcmp((d1NvdataSensitive->data) + offset, data.buffer, data.size); + if (irc != 0) { + /* d. Write the new value into the NV storage area */ + printf("TPM_Process_NVWriteValueAuth: Copying data\n"); + memcpy((d1NvdataSensitive->data) + offset, data.buffer, data.size); + /* must write TPM_PERMANENT_DATA back to NVRAM, set this flag after + strucuture is written */ + writeAllNV = TRUE; + } + else { + printf("TPM_Process_NVWriteValueAuth: Same data, no copy\n"); + } + } + /* GPIO */ + else { + printf("TPM_Process_NVWriteValueAuth: Writing GPIO\n"); + returnCode = TPM_IO_GPIO_Write(nvIndex, + data.size, + data.buffer, + tpm_state->tpm_number); + } + } + } + } + /* 12. Set D1 -> bReadSTClear to FALSE */ + if (returnCode == TPM_SUCCESS) { + d1NvdataSensitive->pubInfo.bReadSTClear = FALSE; + printf("TPM_Process_NVWriteValueAuth: Writing data to NVRAM\n"); + } + /* write back TPM_PERMANENT_DATA if required */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_NVWriteValueAuth: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&data); /* @1 */ + return rcf; +} + +/* 20.1 TPM_NV_DefineSpace rev 109 + + This establishes the space necessary for the indicated index. The definition will include the + access requirements for writing and reading the area. + + Previously defined space at the index and new size is non-zero (and space is available, + etc.) -> redefine the index + + No previous space at the index and new size is non-zero (and space is available, etc.)-> + define the index + + Previously defined space at the index and new size is 0 -> delete the index + + No previous space at the index and new size is 0 -> error + + The space definition size does not include the area needed to manage the space. + + Setting TPM_PERMANENT_FLAGS -> nvLocked TRUE when it is already TRUE is not an error. + + For the case where pubInfo -> dataSize is 0, pubInfo -> pcrInfoRead and pubInfo -> pcrInfoWrite + are not used. However, since the general principle is to validate parameters before changing + state, the TPM SHOULD parse pubInfo completely before invalidating the data area. +*/ + +TPM_RESULT TPM_Process_NVDefineSpace(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_NV_INDEX newNVIndex = TPM_NV_INDEX_LOCK; /* from input TPM_NV_DATA_PUBLIC, initialize + to silence compiler */ + TPM_ENCAUTH encAuth; /* The encrypted AuthData, only valid if the attributes + require subsequent authorization */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for ownerAuth */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest HMAC key: ownerAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey = NULL; + TPM_BOOL ignore_auth = FALSE; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + TPM_BOOL done = FALSE; /* processing is done */ + TPM_DIGEST a1Auth; + TPM_NV_DATA_SENSITIVE *d1_old; /* possibly old data */ + TPM_NV_DATA_SENSITIVE *d1_new = NULL; /* new data */ + TPM_NV_DATA_PUBLIC *pubInfo = NULL; /* new, initialize to silence + compiler */ + uint32_t freeSpace; /* free space after allocating new + index */ + TPM_BOOL writeLocalities = FALSE; + TPM_BOOL physicalPresence; + TPM_BOOL foundOld = TRUE; /* index already exists, initialize + to silence compiler */ + uint32_t nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* temp for noOwnerNVWrite, initialize to silence + compiler */ + TPM_BOOL nv1Incremented = FALSE; /* flag that nv1 was incremented */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_NVDefineSpace: Ordinal Entry\n"); + /* This design gets a slot in the TPM_NV_INDEX_ENTRIES array, either an existing empty one or a + newly re'allocated one. The incoming parameters are deserialized directly into the slot. + + On success, the slot remains. On failure, the slot is deleted. There is no need to remove + the slot from the array. It can remain for the next call. + */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get or create a free index in the TPM_NV_INDEX_ENTRIES array */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_NVIndexEntries_GetFreeEntry(&d1_new, &(tpm_state->tpm_nv_index_entries)); + } + /* get pubInfo parameter */ + if (returnCode == TPM_SUCCESS) { + pubInfo = &(d1_new->pubInfo); /* pubInfo is an input parameter */ + returnCode = TPM_NVDataPublic_Load(pubInfo, + &command, ¶mSize, + FALSE); /* not optimized for digestAtRelease */ + /* The NV index cannot be immediately deserialized in the slot, or the function will think + that the index already exists. Therefore, the nvIndex parameter is saved and temporarily + set to empty until the old slot is deleted. */ + newNVIndex = pubInfo->nvIndex; /* save the possibly new index */ + pubInfo->nvIndex = TPM_NV_INDEX_LOCK; /* temporarily mark unused */ + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVDefineSpace: index %08x permission %08x dataSize %08x\n", + newNVIndex, pubInfo->permission.attributes, pubInfo->dataSize); + TPM_PCRInfo_Trace("TPM_Process_NVDefineSpace: pcrInfoRead", + pubInfo->pcrInfoRead.pcrSelection, + pubInfo->pcrInfoRead.digestAtRelease); + TPM_PCRInfo_Trace("TPM_Process_NVDefineSpace: pcrInfoWrite", + pubInfo->pcrInfoWrite.pcrSelection, + pubInfo->pcrInfoWrite.digestAtRelease); + /* get encAuth parameter */ + returnCode = TPM_Secret_Load(encAuth, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER | TPM_CHECK_NV_NOAUTH); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_NVDefineSpace: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. If pubInfo -> nvIndex == TPM_NV_INDEX_LOCK and tag = TPM_TAG_RQU_COMMAND */ + if ((returnCode == TPM_SUCCESS) && + (newNVIndex == TPM_NV_INDEX_LOCK) && + (tag == TPM_TAG_RQU_COMMAND)) { + /* a. If pubInfo -> dataSize is not 0, the command MAY return TPM_BADINDEX. */ + if (pubInfo->dataSize != 0) { + printf("TPM_Process_NVDefineSpace: Error, TPM_NV_INDEX_LOCK dataSize %u\n", + pubInfo->dataSize); + returnCode = TPM_BADINDEX; + } + else { + /* b. Set TPM_PERMANENT_FLAGS -> nvLocked to TRUE */ + /* writeAllNV set to TRUE if nvLocked is beng set, not if already set */ + printf("TPM_Process_NVDefineSpace: Setting nvLocked\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.nvLocked ), /* flag */ + TRUE); /* value */ + } + /* c. Return TPM_SUCCESS */ + done = TRUE; + } + /* 2. If TPM_PERMANENT_FLAGS -> nvLocked is FALSE then all authorization checks except for the + Max NV writes are ignored */ + /* a. Ignored checks include physical presence, owner authorization, 'D' bit check, bGlobalLock, + no authorization with a TPM owner present, bWriteSTClear, the check that pubInfo -> dataSize + is 0 in Action 5.c. (the no-authorization case), disabled and deactivated. */ + /* NOTE: The disabled and deactivated flags are conditionally checked by TPM_CheckState() using + the TPM_CHECK_NV_NOAUTH flag */ + /* ii. The check that pubInfo -> dataSize is 0 is still enforced in Action 6.f. (returning after + deleting a previously defined storage area) and Action 9.f. (not allowing a space of size 0 + to be defined). */ + /* i.If ownerAuth is present, the TPM MAY check the authorization HMAC. */ + if (returnCode == TPM_SUCCESS) { + if (!(tpm_state->tpm_permanent_flags.nvLocked)) { + printf("TPM_Process_NVDefineSpace: nvLocked FALSE, ignoring authorization\n"); + ignore_auth = TRUE; + } + } + /* b.The check for pubInfo -> nvIndex == 0 in Action 3. is not ignored. */ + if ((returnCode == TPM_SUCCESS) && !done) { + if (newNVIndex == TPM_NV_INDEX0) { + printf("TPM_Process_NVDefineSpace: Error, bad index %08x\n", newNVIndex); + returnCode = TPM_BADINDEX; + } + } + /* 3. If pubInfo -> nvIndex has the D bit (bit 28) set to a 1 or pubInfo -> nvIndex == 0 then */ + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth) { + /* b. The D bit specifies an index value that is set in manufacturing and can never be + deleted or added to the TPM */ + if (newNVIndex & TPM_NV_INDEX_D_BIT) { + /* c. Index value of 0 is reserved and cannot be defined */ + /* a. Return TPM_BADINDEX */ + printf("TPM_Process_NVDefineSpace: Error, bad index %08x\n", newNVIndex); + returnCode = TPM_BADINDEX; + } + } + /* 4. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ + /* b. authHandle session type MUST be OSAP */ + /* must get the HMAC key for the response even if ignore_auth is TRUE */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_OWNER, + ordinal, + NULL, + NULL, + tpm_state->tpm_permanent_data.ownerAuth); + } + /* a. The TPM MUST validate the command and parameters using the TPM Owner authentication and + ownerAuth, on error return TPM_AUTHFAIL */ + /* NOTE: This is optional if ignore_auth is TRUE */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !done) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* c. Create A1 by decrypting encAuth according to the ADIP indicated by authHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND) && !done) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + encAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 5. else (not auth1) */ + /* a. Validate the assertion of physical presence. Return TPM_BAD_PRESENCE on error. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done && !ignore_auth) { + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_NVDefineSpace: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + } + /* b. If TPM Owner is present then return TPM_OWNER_SET. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done && !ignore_auth) { + if (tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_NVDefineSpace: Error, no authorization, but owner installed\n"); + returnCode = TPM_OWNER_SET; + } + } + /* c. If pubInfo -> dataSize is 0 then return TPM_BAD_DATASIZE. Setting the size to 0 represents + an attempt to delete the value without TPM Owner authentication. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done && !ignore_auth) { + if (pubInfo->dataSize == 0) { + printf("TPM_Process_NVDefineSpace: Error, no owner authorization and dataSize 0\n"); + returnCode = TPM_BAD_DATASIZE; + } + } + /* d. Validate max NV writes without an owner */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done) { + /* i. Set NV1 to TPM_PERMANENT_DATA -> noOwnerNVWrite */ + nv1 = tpm_state->tpm_permanent_data.noOwnerNVWrite; + /* ii. Increment NV1 by 1 */ + nv1++; + /* iii. If NV1 > TPM_MAX_NV_WRITE_NOOWNER return TPM_MAXNVWRITES */ + if (nv1 > TPM_MAX_NV_WRITE_NOOWNER) { + printf("TPM_Process_NVDefineSpace: Error, max NV writes %d w/o owner reached\n", + tpm_state->tpm_permanent_data.noOwnerNVWrite); + returnCode = TPM_MAXNVWRITES; + } + else { + /* iv. Set NV1_INCREMENTED to TRUE */ + nv1Incremented = TRUE; + } + } + /* e. Set A1 to encAuth. There is no nonce or authorization to create the encryption string, + hence the AuthData value is passed in the clear */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND) && !done) { + TPM_Digest_Copy(a1Auth, encAuth); + } + /* 6. If pubInfo -> nvIndex points to a valid previously defined storage area then */ + /* 6.a. Map D1 a TPM_NV_DATA_SENSITIVE to the storage area */ + if ((returnCode == TPM_SUCCESS) && !done) { + printf("TPM_Process_NVDefineSpace: Loading existing NV index %08x\n", newNVIndex); + returnCode = TPM_NVIndexEntries_GetEntry(&d1_old, + &(tpm_state->tpm_nv_index_entries), + newNVIndex); + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_NVDefineSpace: NV index %08x exists\n", newNVIndex); + foundOld = TRUE; + } + else if (returnCode == TPM_BADINDEX) { + returnCode = TPM_SUCCESS; /* non-existant index is not an error */ + foundOld = FALSE; + printf("TPM_Process_NVDefineSpace: Index %08x is new\n", newNVIndex); + } + } + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && foundOld) { + /* 6.b. If D1 -> attributes specifies TPM_NV_PER_GLOBALLOCK then */ + if (d1_old->pubInfo.permission.attributes & TPM_NV_PER_GLOBALLOCK) { + /* i. If TPM_STCLEAR_FLAGS -> bGlobalLock is TRUE then return TPM_AREA_LOCKED */ + if (tpm_state->tpm_stclear_flags.bGlobalLock) { + printf("TPM_Process_NVDefineSpace: Error, index %08x (bGlobalLock) locked\n", + newNVIndex); + returnCode = TPM_AREA_LOCKED; + } + } + } + if ((returnCode == TPM_SUCCESS) && !done && !ignore_auth && foundOld) { + /* 6.c. If D1 -> attributes specifies TPM_NV_PER_WRITE_STCLEAR */ + if (d1_old->pubInfo.permission.attributes & TPM_NV_PER_WRITE_STCLEAR) { + /* i. If D1 -> pubInfo -> bWriteSTClear is TRUE then return TPM_AREA_LOCKED */ + if (d1_old->pubInfo.bWriteSTClear) { + printf("TPM_Process_NVDefineSpace: Error, area locked by bWriteSTClear\n"); + returnCode = TPM_AREA_LOCKED; + } + } + } + /* NOTE Changed the Action order. Must terminate auth sessions while the old index digest + still exists. + */ + /* 6.f. The TPM invalidates authorization sessions */ + /* i. MUST invalidate all authorization sessions associated with D1 */ + /* ii. MAY invalidate any other authorization session */ + if ((returnCode == TPM_SUCCESS) && !done && foundOld) { + TPM_AuthSessions_TerminateEntity(&continueAuthSession, + authHandle, + tpm_state->tpm_stclear_data.authSessions, + TPM_ET_NV, + &(d1_old->digest)); + } + if ((returnCode == TPM_SUCCESS) && !done && foundOld) { + /* 6.d. Invalidate the data area currently pointed to by D1 and ensure that if the area is + reallocated no residual information is left */ + printf("TPM_Process_NVDefineSpace: Deleting index %08x\n", newNVIndex); + TPM_NVDataSensitive_Delete(d1_old); + /* must write deleted space back to NVRAM */ + writeAllNV = TRUE; + /* 6.e. If NV1_INCREMENTED is TRUE */ + /* i. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ + /* NOTE Don't do this step until just before the serialization */ + } + /* g. If pubInfo -> dataSize is 0 then return TPM_SUCCESS */ + if ((returnCode == TPM_SUCCESS) && !done && foundOld) { + if (pubInfo->dataSize == 0) { + printf("TPM_Process_NVDefineSpace: Size 0, done\n"); + done = TRUE; + } + } + /* 7. Parse pubInfo -> pcrInfoRead */ + /* a. Validate pcrInfoRead structure on error return TPM_INVALID_STRUCTURE */ + /* i. Validation includes proper PCR selections and locality selections */ + /* NOTE: Done by TPM_NVDataPublic_Load() */ + /* 8. Parse pubInfo -> pcrInfoWrite */ + /* a. Validate pcrInfoWrite structure on error return TPM_INVALID_STRUCTURE */ + /* i. Validation includes proper PCR selections and locality selections */ + /* NOTE: Done by TPM_NVDataPublic_Load() */ + if ((returnCode == TPM_SUCCESS) && !done) { + /* b. If pcrInfoWrite -> localityAtRelease disallows some localities */ + if (pubInfo->pcrInfoRead.localityAtRelease != TPM_LOC_ALL) { + /* i. Set writeLocalities to TRUE */ + writeLocalities = TRUE; + } + /* c. Else */ + else { + /* i. Set writeLocalities to FALSE */ + writeLocalities = FALSE; + } + } + /* 9. Validate that the attributes are consistent */ + /* a. The TPM SHALL ignore the bReadSTClear, bWriteSTClear and bWriteDefine attributes during + the execution of this command */ + /* b. If TPM_NV_PER_OWNERWRITE is TRUE and TPM_NV_PER_AUTHWRITE is TRUE return TPM_AUTH_CONFLICT + */ + if ((returnCode == TPM_SUCCESS) && !done) { + if ((pubInfo->permission.attributes & TPM_NV_PER_OWNERWRITE) && + (pubInfo->permission.attributes & TPM_NV_PER_AUTHWRITE)) { + printf("TPM_Process_NVDefineSpace: Error, write authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* c. If TPM_NV_PER_OWNERREAD is TRUE and TPM_NV_PER_AUTHREAD is TRUE return TPM_AUTH_CONFLICT + */ + if ((returnCode == TPM_SUCCESS) && !done) { + if ((pubInfo->permission.attributes & TPM_NV_PER_OWNERREAD) && + (pubInfo->permission.attributes & TPM_NV_PER_AUTHREAD)) { + printf("TPM_Process_NVDefineSpace: Error, read authorization conflict\n"); + returnCode = TPM_AUTH_CONFLICT; + } + } + /* d. If TPM_NV_PER_OWNERWRITE and TPM_NV_PER_AUTHWRITE and TPM_NV_PER_WRITEDEFINE and + TPM_NV_PER_PPWRITE and writeLocalities are all FALSE */ + if ((returnCode == TPM_SUCCESS) && !done) { + if (!(pubInfo->permission.attributes & TPM_NV_PER_OWNERWRITE) && + !(pubInfo->permission.attributes & TPM_NV_PER_AUTHWRITE) && + !(pubInfo->permission.attributes & TPM_NV_PER_WRITEDEFINE) && + !(pubInfo->permission.attributes & TPM_NV_PER_PPWRITE) && + !writeLocalities) { + /* i. Return TPM_PER_NOWRITE */ + printf("TPM_Process_NVDefineSpace: Error, no write\n"); + returnCode = TPM_PER_NOWRITE; + } + } + /* e. Validate pubInfo -> nvIndex */ + /* i. Make sure that the index is applicable for this TPM return TPM_BADINDEX on error */ + if ((returnCode == TPM_SUCCESS) && !done) { + returnCode = TPM_NVDataSensitive_IsValidIndex(newNVIndex); + } + /* f. If dataSize is 0 return TPM_BAD_PARAM_SIZE */ + if ((returnCode == TPM_SUCCESS) && !done) { + if (pubInfo->dataSize == 0) { + printf("TPM_Process_NVDefineSpace: Error, New index data size is zero\n"); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* 10. Create D1 a TPM_NV_DATA_SENSITIVE structure */ + /* NOTE Created and initialized d1_new directly in the TPM_NV_INDEX_ENTRIES array */ + /* a. Set D1 -> pubInfo to pubInfo */ + /* NOTE deserialized in place */ + if ((returnCode == TPM_SUCCESS) && !done) { + /* b. Set D1 -> authValue to A1 */ + TPM_Digest_Copy(d1_new->authValue, a1Auth); + /* c. Set D1 -> pubInfo -> bReadSTClear to FALSE */ + /* d. Set D1 -> pubInfo -> bWriteSTClear to FALSE */ + /* e. Set D1 -> pubInfo -> bWriteDefine to FALSE */ + pubInfo->bReadSTClear = FALSE; + pubInfo->bWriteSTClear = FALSE; + pubInfo->bWriteDefine = FALSE; + } + if ((returnCode == TPM_SUCCESS) && !done) { + /* assign the empty slot to the index now so it will be counted as used space during the + serialization. */ + pubInfo->nvIndex = newNVIndex; + /* 12.a. Reserve NV space for pubInfo -> dataSize + + NOTE: Action is out or order. Must allocate data space now so that the serialization + inherent in TPM_NVIndexEntries_GetFreeSpace() is valid + */ + returnCode = TPM_Malloc(&(d1_new->data), pubInfo->dataSize); + } + /* 11. Validate that sufficient NV is available to store D1 and pubInfo -> dataSize bytes of + data*/ + /* a. return TPM_NOSPACE if pubInfo -> dataSize is not available in the TPM */ + if ((returnCode == TPM_SUCCESS) && !done) { + printf("TPM_Process_NVDefineSpace: Allocated %u data bytes at %p\n", + pubInfo->dataSize, d1_new->data); + printf("TPM_Process_NVDefineSpace: Checking for %u bytes free space\n", pubInfo->dataSize); + returnCode = TPM_NVIndexEntries_GetFreeSpace(&freeSpace, + &(tpm_state->tpm_nv_index_entries)); + } + /* If there is no free space, free the NV index in-memory structure. This implicitly removes + the entry from tpm_nv_index_entries. If pubInfo -> nvIndex is TPM_NV_INDEX_TRIAL, the entry + should also be removed. */ + if ((returnCode != TPM_SUCCESS) || + (newNVIndex == TPM_NV_INDEX_TRIAL)) { + if (newNVIndex == TPM_NV_INDEX_TRIAL) { + printf("TPM_Process_NVDefineSpace: nvIndex is TPM_NV_INDEX_TRIAL, done\n"); + /* don't actually write, just return success or failure */ + done = TRUE; + } + TPM_NVDataSensitive_Delete(d1_new); + } + /* 12. If pubInfo -> nvIndex is not TPM_NV_INDEX_TRIAL */ + if ((returnCode == TPM_SUCCESS) && !done) { + printf("TPM_Process_NVDefineSpace: Creating index %08x\n", newNVIndex); + /* b. Set all bytes in the newly defined area to 0xFF */ + memset(d1_new->data, 0xff, pubInfo->dataSize); + /* must write newly defined space back to NVRAM */ + writeAllNV = TRUE; + } + if (returnCode == TPM_SUCCESS) { + /* c. If NV1_INCREMENTED is TRUE */ + if (nv1Incremented) { + /* i. Set TPM_PERMANENT_DATA -> noOwnerNVWrite to NV1 */ + tpm_state->tpm_permanent_data.noOwnerNVWrite = nv1; + } + /* 13. Ignore continueAuthSession on input and set to FALSE on output */ + continueAuthSession = FALSE; + } + /* write the file to NVRAM */ + /* write back TPM_PERMANENT_DATA and TPM_PERMANENT_FLAGS if required */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_NVDefineSpace: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 27.3 DIR commands rev 87 + + The DIR commands are replaced by the NV storage commands. + + The DIR [0] in 1.1 is now TPM_PERMANENT_DATA -> authDIR[0] and is always available for the TPM to + use. It is accessed by DIR commands using dirIndex 0 and by NV commands using nvIndex + TPM_NV_INDEX_DIR. + + If the TPM vendor supports additional DIR registers, the TPM vendor may return errors or provide + vendor specific mappings for those DIR registers to NV storage locations. + + 1. A dirIndex value of 0 MUST corresponds to an NV storage nvIndex value TPM_NV_INDEX_DIR. + + 2. The TPM vendor MAY return errors or MAY provide vendor specific mappings for DIR dirIndex + values greater than 0 to NV storage locations. +*/ + +/* 27.3.1 TPM_DirWriteAuth rev 87 + + The TPM_DirWriteAuth operation provides write access to the Data Integrity Registers. DIRs are + non-volatile memory registers held in a TPM-shielded location. Owner authentication is required + to authorize this action. + + Access is also provided through the NV commands with nvIndex TPM_NV_INDEX_DIR. Owner + authorization is not required when nvLocked is FALSE. + + Version 1.2 requires only one DIR. If the DIR named does not exist, the TPM_DirWriteAuth + operation returns TPM_BADINDEX. +*/ + +TPM_RESULT TPM_Process_DirWriteAuth(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_DIRINDEX dirIndex; /* Index of the DIR */ + TPM_DIRVALUE newContents; /* New value to be stored in named DIR */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for command. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs. HMAC key: + ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DirWriteAuth: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get dirIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&dirIndex, &command, ¶mSize); + } + /* get newContents parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DirWriteAuth: dirIndex %08x\n", dirIndex); + returnCode = TPM_Digest_Load(newContents, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_DirWriteAuth: newContents", newContents); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DirWriteAuth: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate that authHandle contains a TPM Owner AuthData to execute the TPM_DirWriteAuth + command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Validate that dirIndex points to a valid DIR on this TPM */ + if (returnCode == TPM_SUCCESS) { + if (dirIndex != 0) { /* only one TPM_PERMANENT_DATA -> authDIR */ + printf("TPM_Process_DirWriteAuth: Error, Invalid index %08x\n", dirIndex); + returnCode = TPM_BADINDEX; + } + } + /* 3. Write newContents into the DIR pointed to by dirIndex */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DirWriteAuth: Writing data\n"); + TPM_Digest_Copy(tpm_state->tpm_permanent_data.authDIR, newContents); + /* write back TPM_PERMANENT_DATA */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, + returnCode); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DirWriteAuth: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 27.3.2 TPM_DirRead rev 87 + + The TPM_DirRead operation provides read access to the DIRs. No authentication is required to + perform this action because typically no cryptographically useful AuthData is available early in + boot. TSS implementors may choose to provide other means of authorizing this action. Version 1.2 + requires only one DIR. If the DIR named does not exist, the TPM_DirRead operation returns + TPM_BADINDEX. +*/ + +TPM_RESULT TPM_Process_DirRead(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_DIRINDEX dirIndex; /* Index of the DIR to be read */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DirRead: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get dirIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&dirIndex, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DirRead: dirIndex %08x\n", dirIndex); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DirRead: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that dirIndex points to a valid DIR on this TPM */ + if (returnCode == TPM_SUCCESS) { + if (dirIndex != 0) { /* only one TPM_PERMANENT_DATA -> authDIR */ + printf("TPM_Process_DirRead: Error, Invalid index %08x\n", dirIndex); + returnCode = TPM_BADINDEX; + } + } + /* 2. Return the contents of the DIR in dirContents */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DirRead: Reading data\n"); + TPM_PrintFour("TPM_Process_DirRead:", tpm_state->tpm_permanent_data.authDIR); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DirRead: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append dirContents */ + returnCode = TPM_Digest_Store(response, tpm_state->tpm_permanent_data.authDIR); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} diff --git a/src/tpm_nvram.h b/src/tpm_nvram.h new file mode 100644 index 00000000..4bea9efa --- /dev/null +++ b/src/tpm_nvram.h @@ -0,0 +1,201 @@ +/********************************************************************************/ +/* */ +/* NVRAM Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nvram.h 4528 2011-03-29 22:16:28Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_NVRAM_H +#define TPM_NVRAM_H + +#include + +#include "tpm_global.h" +#include "tpm_types.h" + +/* + NVRAM common functions +*/ + +/* + TPM_NV_ATTRIBUTES +*/ + +void TPM_NVAttributes_Init(TPM_NV_ATTRIBUTES *tpm_nv_attributes); +TPM_RESULT TPM_NVAttributes_Load(TPM_NV_ATTRIBUTES *tpm_nv_attributes, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_NVAttributes_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_ATTRIBUTES *tpm_nv_attributes); +void TPM_NVAttributes_Delete(TPM_NV_ATTRIBUTES *tpm_nv_attributes); + +void TPM_NVAttributes_Copy(TPM_NV_ATTRIBUTES *tpm_nv_attributes_dest, + TPM_NV_ATTRIBUTES *tpm_nv_attributes_src); + +/* + TPM_NV_DATA_PUBLIC +*/ + +void TPM_NVDataPublic_Init(TPM_NV_DATA_PUBLIC *tpm_nv_data_public); +TPM_RESULT TPM_NVDataPublic_Load(TPM_NV_DATA_PUBLIC *tpm_nv_data_public, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL optimize); +TPM_RESULT TPM_NVDataPublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_DATA_PUBLIC *tpm_nv_data_public, + TPM_BOOL optimize); +void TPM_NVDataPublic_Delete(TPM_NV_DATA_PUBLIC *tpm_nv_data_public); + +/* + TPM_NV_DATA_SENSITIVE +*/ + +void TPM_NVDataSensitive_Init(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive); +TPM_RESULT TPM_NVDataSensitive_Load(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive, + TPM_TAG nvEntriesVersion, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_NVDataSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive); +void TPM_NVDataSensitive_Delete(TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive); + +TPM_RESULT TPM_NVDataSensitive_IsValidIndex(TPM_NV_INDEX nvIndex); +TPM_RESULT TPM_NVDataSensitive_IsGPIO(TPM_BOOL *isGPIO, TPM_NV_INDEX nvIndex); +TPM_RESULT TPM_NVDataSensitive_IsValidPlatformIndex(TPM_NV_INDEX nvIndex); + +/* + NV Index Entries +*/ + +void TPM_NVIndexEntries_Init(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +void TPM_NVIndexEntries_Delete(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +void TPM_NVIndexEntries_Trace(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_Load(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_NVIndexEntries_Store(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +void TPM_NVIndexEntries_StClear(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_LoadVolatile(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_NVIndexEntries_StoreVolatile(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetVolatile(TPM_NV_DATA_ST **tpm_nv_data_st, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_SetVolatile(TPM_NV_DATA_ST *tpm_nv_data_st, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetFreeEntry(TPM_NV_DATA_SENSITIVE **tpm_nv_data_sensitive, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetEntry(TPM_NV_DATA_SENSITIVE **tpm_nv_data_sensitive, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_NV_INDEX nvIndex); +TPM_RESULT TPM_NVIndexEntries_GetUsedCount(uint32_t *count, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetNVList(TPM_STORE_BUFFER *sbuffer, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetUsedSpace(uint32_t *usedSpace, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_DeleteOwnerAuthorized(TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_BOOL deleteAllNvram); +TPM_RESULT TPM_NVIndexEntries_GetUsedSpace(uint32_t *usedSpace, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetFreeSpace(uint32_t *freeSpace, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries); +TPM_RESULT TPM_NVIndexEntries_GetDataPublic(TPM_NV_DATA_PUBLIC **tpm_nv_data_public, + TPM_NV_INDEX_ENTRIES *tpm_nv_index_entries, + TPM_NV_INDEX nvIndex); + +/* + Processing Functions +*/ + + +TPM_RESULT TPM_Process_NVReadValue(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_NVReadValueAuth(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_NVWriteValue(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_NVWriteValueAuth(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + +TPM_RESULT TPM_Process_NVDefineSpace(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_DirRead(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_DirWriteAuth(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +#endif diff --git a/src/tpm_nvram_const.h b/src/tpm_nvram_const.h new file mode 100644 index 00000000..68ee97c1 --- /dev/null +++ b/src/tpm_nvram_const.h @@ -0,0 +1,138 @@ +/********************************************************************************/ +/* */ +/* NVRAM Constants */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_nvram_const.h 4528 2011-03-29 22:16:28Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_NVRAM_CONST_H +#define TPM_NVRAM_CONST_H + +/* + These are implementation specific constants +*/ + +/* + TPMS_MAX defines the maximum number of TPM instances. +*/ + +#define TPMS_MAX 1 + +/* + NVRAM storage directory path +*/ + + +#ifdef TPM_NV_DISK +/* TPM_NV_DISK uses the TPM_PATH environment variable */ +#endif + +/* Defines the maximum size of the NV defined space, the NV indexes created by TPM_NV_DefineSpace. + + The PC Client requires 2048 bytes. There is at least (currently) 6 bytes of overhead, a tag and + a count. +*/ + +#ifndef TPM_MAX_NV_DEFINED_SIZE +#define TPM_MAX_NV_DEFINED_SIZE 2100 +#endif + +/* TPM_MAX_NV_SPACE defines the maximum NV space for non-volatile state. + + It does not include the area used for TPM_SaveState. + + See TPM_OWNER_EVICT_KEY_HANDLES, TPM_MIN_COUNTERS, TPM_NUM_FAMILY_TABLE_ENTRY_MIN, + TPM_NUM_DELEGATE_TABLE_ENTRY_MIN, etc. and the platform specific requirements for NV defined + space. +*/ + +#ifndef TPM_MAX_NV_SPACE + + + +#ifdef TPM_NV_DISK +#define TPM_MAX_NV_SPACE 100000 /* arbitrary value */ +#endif + +#endif /* TPM_MAX_NV_SPACE */ + +#ifndef TPM_MAX_NV_SPACE +#error "TPM_MAX_NV_SPACE is not defined" +#endif + +/* TPM_MAX_SAVESTATE_SPACE defines the maximum NV space for TPM saved state. + + It is used by TPM_SaveState + + NOTE This macro is based on the maximum number of loaded keys and session. For example, 3 loaded + keys, 3 OSAP sessions, and 1 transport session consumes about 2500 bytes. + + See TPM_KEY_HANDLES, TPM_NUM_PCR, TPM_MIN_AUTH_SESSIONS, TPM_MIN_TRANS_SESSIONS, + TPM_MIN_DAA_SESSIONS, TPM_MIN_SESSION_LIST, etc. +*/ + +#ifndef TPM_MAX_SAVESTATE_SPACE + + + +#ifdef TPM_NV_DISK +#define TPM_MAX_SAVESTATE_SPACE 100000 /* arbitrary value */ +#endif + +#endif /* TPM_MAX_SAVESTATE_SPACE */ + +#ifndef TPM_MAX_SAVESTATE_SPACE +#error "TPM_MAX_SAVESTATE_SPACE is not defined" +#endif + +/* TPM_MAX_VOLATILESTATE_SPACE defines the maximum NV space for TPM volatile state. + + It is used for applications that save and restore the entire TPM volatile is a non-standard way. +*/ + +#ifndef TPM_MAX_VOLATILESTATE_SPACE + + +#ifdef TPM_NV_DISK +#define TPM_MAX_VOLATILESTATE_SPACE 524288 /* arbitrary value */ +#endif + +#endif /* TPM_MAX_VOLATILESTATE_SPACE */ + +#ifndef TPM_MAX_VOLATILESTATE_SPACE +#error "TPM_MAX_VOLATILESTATE_SPACE is not defined" +#endif + +#endif diff --git a/src/tpm_owner.c b/src/tpm_owner.c new file mode 100644 index 00000000..d0521504 --- /dev/null +++ b/src/tpm_owner.c @@ -0,0 +1,1968 @@ +/********************************************************************************/ +/* */ +/* Ownership Processing */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_owner.c 4620 2011-09-07 21:43:19Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_audit.h" +#include "tpm_auth.h" +#include "tpm_counter.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_delegate.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_nvram.h" +#include "tpm_pcr.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_session.h" +#include "tpm_sizedbuffer.h" +#include "tpm_transport.h" + +#include "tpm_owner.h" + +/* Flags involved with clearing an owner: + + pFlags.disableOwnerClear + set by TPM_DisableOwnerClear + clear by successful owner clear + vFlags.disableForceClear + set by TPM_DisableForceClear + clear by TPM_Init + + TPM_OwnerClear + requires ownerAuth + pFlags.disableOwnerClear == FALSE + TPM_ForceClear + requires physical presence + vFlags.disableForceClear == FALSE +*/ + +/* 6.1 TPM_TakeOwnership rev 114 + + This command inserts the TPM Ownership value into the TPM. +*/ + +TPM_RESULT TPM_Process_TakeOwnership(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, /* bytes left in command */ + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_PROTOCOL_ID protocolID; /* The ownership protocol in use */ + TPM_SIZED_BUFFER encOwnerAuth; /* The owner authorization data encrypted with PUBEK */ + TPM_SIZED_BUFFER encSrkAuth; /* The SRK authorization data encrypted with PUBEK */ + TPM_KEY srkParams; /* Structure containing all parameters of new SRK. + pubKey.keyLength & encSize are both 0. This structure + MAY be TPM_KEY12. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for this command */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization handle */ + TPM_AUTHDATA ownerAuth; /* Authorization digest for input params. HMAC key: the new + ownerAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_SECRET a1Auth; /* decrypt of encOwnerAuth */ + uint32_t a1Auth_length; /* length of decrypted A1 */ + TPM_SECRET a2SrkAuth; /* decrypt of encSrkAuth */ + uint32_t a2SrkAuth_length; /* length of decrypted A2 */ + TPM_RSA_KEY_PARMS *srkRSAKeyParms; + TPM_STORE_ASYMKEY *srkStoreAsymkey; + TPM_STORE_BUFFER asymKeySbuffer; /* serialized SRK asymkey */ + TPM_KEY *srk; /* pointer to SRK in permanent data */ + TPM_SIZED_BUFFER exponent; /* default exponent */ + TPM_BOOL writeAllNV1 = FALSE; /* flags to write back NV */ + TPM_BOOL writeAllNV2 = FALSE; /* flags to write back NV */ + int ver; /* TPM_KEY or TPM_KEY12 */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY srkPub; /* Structure containing all parameters of new SRK, + srkPub.encData is set to 0. */ + + printf("TPM_Process_TakeOwnership: Ordinal Entry\n"); + srk = &(tpm_state->tpm_permanent_data.srk); /* get pointer to SRK in permanent data */ + + /* so that Delete's are safe */ + TPM_SizedBuffer_Init(&encOwnerAuth); /* freed @1 */ + TPM_SizedBuffer_Init(&encSrkAuth); /* freed @2 */ + TPM_Key_Init(&srkParams); /* freed @3 */ + TPM_Key_Init(&srkPub); /* freed @5 */ + TPM_SizedBuffer_Init(&exponent); /* freed @6 */ + TPM_Sbuffer_Init(&asymKeySbuffer); /* freed @7 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get protocolID parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&protocolID, &command, ¶mSize); + } + /* get encOwnerAuth parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: protocolID %04hx\n", protocolID); + returnCode = TPM_SizedBuffer_Load(&encOwnerAuth, &command, ¶mSize); + } + /* get encSrkAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&encSrkAuth, &command, ¶mSize); + } + /* get srkParams parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&srkParams, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_ENABLED | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_TakeOwnership: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. If TPM_PERMANENT_DATA -> ownerAuth is valid return TPM_OWNER_SET */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Checking TPM state\n"); + if (tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_TakeOwnership: Error, owner already installed\n"); + returnCode = TPM_OWNER_SET; + } + } + /* 2. If TPM_PERMANENT_FLAGS -> ownership is FALSE return TPM_INSTALL_DISABLED */ + if (returnCode == TPM_SUCCESS) { + if (!(tpm_state->tpm_permanent_flags.ownership)) { + printf("TPM_Process_TakeOwnership: Error, ownership is false\n"); + returnCode = TPM_INSTALL_DISABLED; + } + } + /* 3. If TPM_PERMANENT_DATA -> endorsementKey is invalid return TPM_NO_ENDORSEMENT */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_permanent_data.endorsementKey.keyUsage == TPM_KEY_UNINITIALIZED) { + printf("TPM_Process_TakeOwnership: Error, endorsement key is invalid\n"); + returnCode = TPM_NO_ENDORSEMENT; + } + } + /* 4. Verify that authHandle is of type OIAP on error return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OIAP, + 0, /* OSAP entity type */ + ordinal, + NULL, + NULL, /* no OIAP authorization */ + NULL); + } + /* 5. If protocolID is not TPM_PID_OWNER, the TPM MAY return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (protocolID != TPM_PID_OWNER) { + printf("TPM_Process_TakeOwnership: Error, bad protocolID\n"); + returnCode = TPM_BAD_PARAMETER; + + } + } + /* 6. Create A1 a TPM_SECRET by decrypting encOwnerAuth using PRIVEK as the key */ + /* a. This requires that A1 was encrypted using the PUBEK */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPrivateDecryptH(a1Auth, /* decrypted data */ + &a1Auth_length, /* actual size of A1 */ + TPM_SECRET_SIZE, /* size of A1 buffer */ + encOwnerAuth.buffer, /* encrypted data */ + encOwnerAuth.size, /* encrypted data size */ + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* b. Validate that A1 is a length of 20 bytes, on error return TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (a1Auth_length != TPM_SECRET_SIZE) { + printf("TPM_Process_TakeOwnership: Error, A1 length %u, should be %u\n", + a1Auth_length, TPM_SECRET_SIZE); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* 7. Validate the command and parameters using A1 and ownerAuth, on error return TPM_AUTHFAIL + */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_TakeOwnership: A1 secret", a1Auth); + returnCode = TPM_Authdata_Check(tpm_state, + a1Auth, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* + 8. Validate srkParams + */ + /* a. If srkParams -> keyUsage is not TPM_KEY_STORAGE return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Validating SRK parameters\n"); + if (srkParams.keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->keyUsage is not TPM_KEY_STORAGE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* b. If srkParams -> migratable is TRUE return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (srkParams.keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_TakeOwnership: Error, srkParams->keyFlags migratable is TRUE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* c. If srkParams -> algorithmParms -> algorithmID is NOT TPM_ALG_RSA return + TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (srkParams.algorithmParms.algorithmID != TPM_ALG_RSA) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->algorithmParms->algorithmID is NOT TPM_ALG_RSA\n"); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* d. If srkParams -> algorithmParms -> encScheme is NOT TPM_ES_RSAESOAEP_SHA1_MGF1 return + TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (srkParams.algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->algorithmParms->encScheme is NOT TPM_ES_RSAESOAEP_SHA1_MGF1\n"); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* e. If srkParams -> algorithmParms -> sigScheme is NOT TPM_SS_NONE return + TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (srkParams.algorithmParms.sigScheme != TPM_SS_NONE) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->algorithmParms->sigScheme is NOT TPM_SS_NONE\n"); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* f. srkParams -> algorithmParms -> parms -> keyLength MUST be greater than or equal to + 2048, on error return TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&srkRSAKeyParms, &(srkParams.algorithmParms)); + } + if (returnCode == TPM_SUCCESS) { + if (srkRSAKeyParms->keyLength < 2048) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->algorithmParms->parms->keyLength " + "MUST be greater than or equal to 2048\n"); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* g .If srkParams -> algorithmParms -> parms -> exponentSize is not 0, return + TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (srkRSAKeyParms->exponent.size != 0) { + printf("TPM_Process_TakeOwnership: Error, " + "srkParams->algorithmParms->parms->exponentSize %u is not zero\n", + srkRSAKeyParms->exponent.size); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* h. If TPM_PERMANENT_FLAGS -> FIPS is TRUE */ + /* i. If srkParams -> authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state -> tpm_permanent_flags.FIPS) { + if (srkParams.authDataUsage == TPM_AUTH_NEVER) { + printf("TPM_Process_TakeOwnership: Error, " + "FIPS and authDataUsage is TPM_AUTH_NEVER\n"); + returnCode = TPM_NOTFIPS; + } + } + } + /* check that srkParams is TPM_KEY or TPM_KEY12 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_CheckStruct(&ver, &srkParams); + } + /* 9. Generate K1 (SRK) according to the srkParams on error return TPM_BAD_KEY_PROPERTY */ + /* a.This includes copying PCRInfo from srkParams to K1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: SRK key length %u\n", srkRSAKeyParms->keyLength); + if (ver == 1) { + if (srkParams.tpm_pcr_info != NULL) { + TPM_PCRInfo_Trace("TPM_Process_TakeOwnership: SRK PCRs", + srkParams.tpm_pcr_info->pcrSelection, + srkParams.tpm_pcr_info->digestAtRelease); + } + else { + printf("TPM_Process_TakeOwnership: No SRK PCRs\n"); + } + } + else { + if (srkParams.tpm_pcr_info_long != NULL) { + TPM_PCRInfo_Trace("TPM_Process_TakeOwnership: SRK PCRs", + srkParams.tpm_pcr_info_long->releasePCRSelection, + srkParams.tpm_pcr_info_long->digestAtRelease); + } + else { + printf("TPM_Process_TakeOwnership: No SRK PCRs\n"); + } + } + printf("TPM_Process_TakeOwnership: Creating SRK, authDataUsage %u\n", + srkParams.authDataUsage); + /* The old keys should already be deleted from an OwnerClear, but it can't hurt to do it + again to prevent memory leaks on errors. */ + TPM_Key_Delete(srk); /* not freed, in permanent store */ + returnCode = TPM_Key_GenerateRSA(srk, + tpm_state, + NULL, /* parent key */ + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + ver, + TPM_KEY_STORAGE, /* keyUsage */ + srkParams.keyFlags, + srkParams.authDataUsage, + &(srkParams.algorithmParms), /* TPM_KEY_PARMS */ + srkParams.tpm_pcr_info, + srkParams.tpm_pcr_info_long); + writeAllNV1 = TRUE; + } + /* 15. Create TPM_PERMANENT_DATA -> tpmProof by using the TPM RNG */ + /* NOTE: Moved here so tpmProof can be inserted into SRK -> migrationAuth */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Creating tpmProof\n"); + returnCode = TPM_Secret_Generate(tpm_state->tpm_permanent_data.tpmProof); + } + /* 10. Create A2 a TPM_SECRET by decrypting encSrkAuth using the PRIVEK */ + /* a. This requires A2 to be encrypted using the PUBEK */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSAPrivateDecryptH(a2SrkAuth, /* decrypted data */ + &a2SrkAuth_length, /* actual size of A2 */ + TPM_SECRET_SIZE, /* size of A2 buffer */ + encSrkAuth.buffer, /* encrypted data */ + encSrkAuth.size, /* encrypted data size */ + &(tpm_state->tpm_permanent_data.endorsementKey)); + } + /* b. Validate that A2 is a length of 20 bytes, on error return TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + if (a2SrkAuth_length != TPM_SECRET_SIZE) { + printf("TPM_Process_TakeOwnership: Error, A2 length %u, should be %u\n", + a2SrkAuth_length, TPM_SECRET_SIZE); + returnCode = TPM_BAD_KEY_PROPERTY; + } + } + /* c. Store A2 in K1 (SRK) -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_TakeOwnership: Insert usageAuth into SRK", a2SrkAuth); + /* get the TPM_STORE_ASYMKEY from the TPM_KEY srk */ + returnCode = TPM_Key_GetStoreAsymkey(&srkStoreAsymkey, srk); + } + if (returnCode == TPM_SUCCESS) { + /* insert the authData into the TPM_STORE_ASYMKEY */ + TPM_Secret_Copy(srkStoreAsymkey->usageAuth, a2SrkAuth); + /* store tpmProof in migrationAuth to indicate that this is a non-migratable key */ + TPM_Secret_Copy(srkStoreAsymkey->migrationAuth, tpm_state->tpm_permanent_data.tpmProof); + /* serialize the TPM_STORE_ASYMKEY object */ + returnCode = TPM_StoreAsymkey_Store(&asymKeySbuffer, FALSE, srkStoreAsymkey); + } + /* store the serialized TPM_STORE_ASYMKEY as encData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(srk->encData), &asymKeySbuffer); + } + /* 11. Store K1 in TPM_PERMANENT_DATA -> srk */ + /* NOTE Generated directly in srk */ + /* 12. Store A1 in TPM_PERMANENT_DATA -> ownerAuth */ + if (returnCode == TPM_SUCCESS) { + TPM_Secret_Copy(tpm_state->tpm_permanent_data.ownerAuth, a1Auth); + tpm_state->tpm_permanent_data.ownerInstalled = TRUE; + } + /* 13. Create TPM_PERMANENT_DATA -> contextKey according to the rules for the algorithm in use + by the TPM to save context blobs */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Creating contextKey\n"); + returnCode = TPM_SymmetricKeyData_GenerateKey(tpm_state->tpm_permanent_data.contextKey); + } + /* 14. Create TPM_PERMANENT_DATA -> delegateKey according to the rules for the algorithm in use + by the TPM to save delegate blobs */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Creating delegateKey\n"); + returnCode = TPM_SymmetricKeyData_GenerateKey(tpm_state->tpm_permanent_data.delegateKey); + } + /* 15. Create TPM_PERMANENT_DATA -> tpmProof by using the TPM RNG */ + /* NOTE: This Action done earlier */ + /* 16. Export TPM_PERMANENT_DATA -> srk as srkPub */ + if (returnCode == TPM_SUCCESS) { + /* copy the srk */ + printf("TPM_Process_TakeOwnership: Creating srkPub for response\n"); + returnCode = TPM_Key_Copy(&srkPub, srk, FALSE); /* don't copy encData */ + } + /* 17. Set TPM_PERMANENT_FLAGS -> readPubek to FALSE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TakeOwnership: Clear readPubek\n"); + TPM_SetCapability_Flag(&writeAllNV2, /* altered */ + &(tpm_state->tpm_permanent_flags.readPubek), /* flag */ + FALSE); /* value */ + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + (TPM_BOOL)(writeAllNV1 || writeAllNV2), + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_TakeOwnership: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append srkPub */ + returnCode = TPM_Key_Store(response, &srkPub); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + /* 18. Calculate resAuth using the newly established TPM_PERMANENT_DATA -> ownerAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_AuthParams_Set(response, + tpm_state->tpm_permanent_data.ownerAuth, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + TPM_SizedBuffer_Delete(&encOwnerAuth); /* @1 */ + TPM_SizedBuffer_Delete(&encSrkAuth); /* @2 */ + TPM_Key_Delete(&srkParams); /* @3 */ + TPM_Key_Delete(&srkPub); /* @5 */ + TPM_SizedBuffer_Delete(&exponent); /* @6 */ + TPM_Sbuffer_Delete(&asymKeySbuffer); /* @7 */ + return rcf; +} + +/* 6.2 TPM_OwnerClear rev 101 + + The OwnerClear command performs the clear operation under authorization. This command is + available until the Owner executes the DisableOwnerClear, at which time any further invocation of + this command returns TPM_CLEAR_DISABLED. +*/ + +TPM_RESULT TPM_Process_OwnerClear(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authorization. HMAC key: permanent_data.ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_SECRET oldOwnerAuth; /* saved copy for response */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back permanent */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_OwnerClear: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OwnerClear: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Verify that the TPM Owner authorizes the command and all of the input, on error return + TPM_AUTHFAIL. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + /* make a copy of the TPM_PERMANENT_DATA.ownerAuth for the response, since it gets + invalidated in step 5. */ + TPM_Secret_Copy(oldOwnerAuth, *hmacKey); + TPM_PrintFour("TPM_Process_OwnerClear: ownerAuth secret", *hmacKey); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. If TPM_PERMANENT_FLAGS -> disableOwnerClear is TRUE then return TPM_CLEAR_DISABLED. */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_permanent_flags.disableOwnerClear) { + printf("TPM_Process_OwnerClear: Error, disableOwnerClear is TRUE\n"); + returnCode = TPM_CLEAR_DISABLED; + } + } + /* owner clear common code */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OwnerClearCommon(tpm_state, + FALSE); /* don't delete if D bit set */ + continueAuthSession = FALSE; /* Fixed value FALSE */ + writeAllNV = TRUE; + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OwnerClear: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + oldOwnerAuth, /* old owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. NOTE: Normally this will fail because all + sessions have been closed. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + return rcf; +} + +/* 6.3 TPM_ForceClear rev 109 + + The ForceClear command performs the Clear operation under physical access. This command is + available until the execution of the DisableForceClear, at which time any further invocation of + this command returns TPM_CLEAR_DISABLED. + + TPM_ForceClear can succeed even if no owner is installed. In that case, it does whatever + TPM_OwnerClear actions that it can. +*/ + +TPM_RESULT TPM_Process_ForceClear(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back data */ + TPM_BOOL physicalPresence; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ForceClear: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ForceClear: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM SHALL check for the assertion of physical presence, if not present return + TPM_BAD_PRESENCE */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&physicalPresence, tpm_state); + } + if (returnCode == TPM_SUCCESS) { + if (!physicalPresence) { + printf("TPM_Process_ForceClear: Error, physicalPresence is FALSE\n"); + returnCode = TPM_BAD_PRESENCE; + } + } + /* 2. If TPM_STCLEAR_FLAGS -> disableForceClear is TRUE return TPM_CLEAR_DISABLED */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_stclear_flags.disableForceClear) { + printf("TPM_Process_ForceClear: Error, disableForceClear is TRUE\n"); + returnCode = TPM_CLEAR_DISABLED; + } + } + /* 3. The TPM SHALL execute the actions of TPM_OwnerClear (except for the TPM Owner + authentication check) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OwnerClearCommon(tpm_state, + FALSE); /* don't delete if D bit set */ + writeAllNV = TRUE; + } + /* Store the permanent data and flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ForceClear: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* TPM_OwnerClearCommon() rev 116 + + Performs owner clear operations common to TPM_OwnerClear, TPM_ForceClear, and TPM_RevokeTrust. + + It assumes that any required authorization is performed by the caller + + If deleteAllNvram is TRUE, all NVRAM is deleted. If it is FALSE, indexes with the D bit set are + not cleared. + + Data is not written back to NV space here. It is written by the caller. +*/ + +TPM_RESULT TPM_OwnerClearCommon(tpm_state_t *tpm_state, + TPM_BOOL deleteAllNvram) +{ + TPM_RESULT rc = 0; + size_t start; + size_t current; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; + + /* 3. Unload all loaded keys. */ + /* a. If TPM_PERMANENT_FLAGS -> FIPS is TRUE, the memory locations containing secret or private + keys MUST be set to all zeros. */ + start = 0; + while ((rc == 0) && + /* returns TPM_RETRY when at the end of the table, terminates loop */ + (TPM_KeyHandleEntries_GetNextEntry(&tpm_key_handle_entry, + ¤t, + tpm_state->tpm_key_handle_entries, + start)) == 0) { + printf("TPM_OwnerClearCommon: Flushing key handle %08x\n", + tpm_key_handle_entry->handle); + rc = TPM_KeyHandleEntry_FlushSpecific(tpm_state, tpm_key_handle_entry); + start = current + 1; + } +#ifdef TPM_V11 + /* 5. The TPM sets all DIR registers to their default value. */ + if (rc == 0) { + TPM_Digest_Init(tpm_state->tpm_permanent_data.authDIR); + } +#endif + /* a.This includes owner evict keys */ + if (rc == 0) { + printf("TPM_OwnerClearCommon: Deleting owner evict keys\n"); + TPM_KeyHandleEntries_OwnerEvictDelete(tpm_state->tpm_key_handle_entries); + } + /* 4. The TPM MUST NOT modify the following TPM_PERMANENT_DATA items + a. endorsementKey + b. revMajor + c. revMinor + d. manuMaintPub + e. auditMonotonicCounter + NOTE: TPMWG email: Don't touch the base value. + f. monotonicCounter + g. pcrAttrib + h. rngState + i. EKReset + j. lastFamilyID + k. tpmDAASeed + l. DIR[1] + m. daaProof + n. daaBlobKey + */ + /* 5. The TPM MUST invalidate the following TPM_PERMANENT_DATA items and + any internal resources associated with these items */ + if (rc == 0) { + printf("TPM_OwnerClearCommon: Invalidate TPM_PERMANENT_DATA items\n"); + /* a. ownerAuth */ + TPM_Secret_Init(tpm_state->tpm_permanent_data.ownerAuth); + tpm_state->tpm_permanent_data.ownerInstalled = FALSE; + /* b. srk */ + TPM_Key_Delete(&(tpm_state->tpm_permanent_data.srk)); + /* c. delegateKey */ + printf("TPM_OwnerClearCommon: Invalidate delegateKey\n"); + TPM_SymmetricKeyData_Init(tpm_state->tpm_permanent_data.delegateKey); + /* d. delegateTable */ + TPM_DelegateTable_Delete(&(tpm_state->tpm_permanent_data.delegateTable)); + /* e. contextKey */ + printf("TPM_OwnerClearCommon: Invalidate contextKey\n"); + TPM_SymmetricKeyData_Init(tpm_state->tpm_permanent_data.contextKey); + /* f. tpmProof */ + TPM_Secret_Init(tpm_state->tpm_permanent_data.tpmProof); + /* g. operatorAuth */ + TPM_Secret_Init(tpm_state->tpm_permanent_data.operatorAuth); + /* 6. The TPM MUST reset to manufacturing defaults the following TPM_PERMANENT_DATA items */ + /* a. noOwnerNVWrite MUST be set to 0 */ + tpm_state->tpm_permanent_data.noOwnerNVWrite = 0; + /* b. ordinalAuditStatus */ + rc = TPM_OrdinalAuditStatus_Init(&(tpm_state->tpm_permanent_data)); + /* c. restrictDelegate */ + tpm_state->tpm_permanent_data.restrictDelegate = 0; + } + if (rc == 0) { + /* 7. The TPM MUST invalidate or reset all fields of TPM_STANY_DATA + a. Nonces SHALL be reset + b. Lists (e.g. contextList) SHALL be invalidated + NOTE This also terminates all sessions + */ + printf("TPM_OwnerClearCommon: Invalidate TPM_STANY_DATA\n"); + TPM_StanyData_Delete(&(tpm_state->tpm_stany_data)); + /* 8. The TPM MUST invalidate all fields of TPM_STCLEAR_DATA except the PCR's + a. Nonces SHALL be reset + b. Lists (e.g. contextList) SHALL be invalidated + c. deferredPhysicalPresence MUST be set to 0 + */ + printf("TPM_OwnerClearCommon: Invalidate TPM_STCLEAR_DATA\n"); + TPM_StclearData_Delete(&(tpm_state->tpm_stclear_data), + tpm_state->tpm_permanent_data.pcrAttrib, + FALSE); /* don't reset the PCR's */ + /* 9. The TPM MUST set the following TPM_PERMANENT_FLAGS to their default values */ + /* a. disable */ + printf("TPM_OwnerClearCommon: Set disable TRUE\n"); + tpm_state->tpm_permanent_flags.disable = TRUE; + /* b. deactivated */ + printf("TPM_OwnerClearCommon: Set deactivated TRUE\n"); + tpm_state->tpm_permanent_flags.deactivated = TRUE; + /* c. readPubek */ + printf("TPM_OwnerClearCommon: Set readPubek TRUE\n"); + tpm_state->tpm_permanent_flags.readPubek = TRUE; + /* d. disableOwnerClear */ + tpm_state->tpm_permanent_flags.disableOwnerClear = FALSE; +#if (TPM_REVISION >= 103) /* added for rev 103 */ + /* e. disableFullDALogicInfo */ + tpm_state->tpm_permanent_flags.disableFullDALogicInfo = FALSE; +#endif + /* f. allowMaintenance */ +#ifdef TPM_NOMAINTENANCE + tpm_state->tpm_permanent_flags.allowMaintenance = FALSE; +#else + tpm_state->tpm_permanent_flags.allowMaintenance = TRUE; +#endif + + /* #if (TPM_REVISION >= 104) This was added in rev 104, but was implemented by vendors + earlier */ + /* g. readSRKPub */ + tpm_state->tpm_permanent_flags.readSRKPub = FALSE; + /* 10. The TPM MUST set the following TPM_PERMANENT_FLAGS */ + /* a. ownership to TRUE */ + tpm_state->tpm_permanent_flags.ownership = TRUE; + /* b. operator to FALSE */ + tpm_state->tpm_permanent_flags.tpmOperator = FALSE; + /* c. maintenanceDone to FALSE */ + tpm_state->tpm_permanent_flags.maintenanceDone = FALSE; + /* 11. The TPM releases all TPM_PERMANENT_DATA -> monotonicCounter settings + + a. This includes invalidating all currently allocated counters. The result will be no + currently allocated counters and the new owner will need to allocate counters. The actual + count value will continue to increase. + */ + rc = TPM_Counters_Release(tpm_state->tpm_permanent_data.monotonicCounter); + /* NOTE: v1.1 says to set all TPM_PERSISTENT_FLAGS to the default value, but I doubt this is + correct. I assume that physicalPresenceLifetimeLock which is a one-way flag, should not + be reset. A similar comment goes for tpmPost and tpmPostLock. */ + } + /* TPM_OwnerClear 12. The TPM MUST deallocate all defined NV storage areas where + a. TPM_NV_PER_OWNERWRITE is TRUE if nvIndex does not have the "D" bit set + b. TPM_NV_PER_OWNERREAD is TRUE if nvIndex does not have the "D" bit set + c. The TPM MUST NOT deallocate any other currently defined NV storage areas. + d.This default behavior MAY be superseded for GPIO indexes by the platform specific + specification. + + TPM_RevokeTrust: a. NV items with the pubInfo -> nvIndex D value set MUST be deleted. This + changes the TPM_OwnerClear handling of the same NV areas + */ + if (rc == 0) { + rc = TPM_NVIndexEntries_DeleteOwnerAuthorized(&(tpm_state->tpm_nv_index_entries), + deleteAllNvram); + } +#if defined TPM_PCCLIENT + /* From the PC Client TIS + + 1.When there is no TPM Owner, the TPM_NV_INDEX_GPIO_00 area MUST be deallocated (see main + specification part 3 on TPM_OwnerClear). + */ + if (rc == 0) { + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; + rc = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive, + &(tpm_state->tpm_nv_index_entries), + TPM_NV_INDEX_GPIO_00); + /* if found, delete */ + if (rc == 0) { + TPM_NVDataSensitive_Delete(tpm_nv_data_sensitive); + } + else if (rc == TPM_BADINDEX) { + rc = TPM_SUCCESS; /* non-existant index is not an error */ + } + } +#endif + /* 13. The TPM MUST invalidate all familyTable entries */ + if (rc == 0) { + TPM_FamilyTable_Delete(&(tpm_state->tpm_permanent_data.familyTable)); + } + /* 14. The TPM MUST terminate all sessions, active or saved. */ + /* NOTE: Done by TPM_StclearData_Delete() */ + /* NOTE The TPM_PERMANENT_DATA and TPM_PERMANENT_FLAGS NVRAM store cannot be factored out here, + since some callers do other functions before the store. */ + return rc; +} + +/* 6.6 TSC_PhysicalPresence rev 87 + + Some TPM operations require the indication of a human's physical presence at the platform. The + presence of the human either provides another indication of platform ownership or a mechanism to + ensure that the execution of the command is not the result of a remote software process. + + This command allows a process on the platform to indicate the assertion of physical presence. As + this command is executable by software there must be protections against the improper invocation + of this command. + + The physicalPresenceHWEnable and physicalPresenceCMDEnable indicate the ability for either SW or + HW to indicate physical presence. These flags can be reset until the physicalPresenceLifetimeLock + is set. The platform manufacturer should set these flags to indicate the capabilities of the + platform the TPM is bound to. The command provides two sets of functionality. The first is to + enable, permanently, either the HW or the SW ability to assert physical presence. The second is + to allow SW, if enabled, to assert physical presence. +*/ + +TPM_RESULT TPM_Process_PhysicalPresence(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_PHYSICAL_PRESENCE physicalPresence; /* The state to set the TPM's Physical Presence + flags */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus = FALSE; /* audit the ordinal */ + TPM_BOOL transportEncrypt = FALSE; /* wrapped in encrypted transport + session */ +#ifdef TPM_V12 + uint16_t a1 = TRUE; /* lifetime settings */ + uint16_t a2 = TRUE; /* assertion settings */ +#endif + TPM_BOOL writeAllNV = FALSE; /* flag to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_PhysicalPresence: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get physicalPresence parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&physicalPresence, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PhysicalPresence: physicalPresence parameter %04x\n", physicalPresence); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PhysicalPresence: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ +#ifdef TPM_V12 + if (returnCode == TPM_SUCCESS) { + if (physicalPresence & TPM_PHYSICAL_PRESENCE_MASK) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresence extra bits\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 1. For documentation ease, the bits break into two categories. The first is the lifetime + settings and the second is the assertion settings. */ + if (returnCode == TPM_SUCCESS) { + /* a. Define A1 to be the lifetime settings: TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK, + TPM_PHYSICAL_PRESENCE_HW_ENABLE, TPM_PHYSICAL_make contingent!!!PRESENCE_CMD_ENABLE, + TPM_PHYSICAL_PRESENCE_HW_DISABLE, and TPM_PHYSICAL_PRESENCE_CMD_DISABLE */ + a1 = physicalPresence & (TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK | + TPM_PHYSICAL_PRESENCE_HW_ENABLE | + TPM_PHYSICAL_PRESENCE_CMD_ENABLE | + TPM_PHYSICAL_PRESENCE_HW_DISABLE | + TPM_PHYSICAL_PRESENCE_CMD_DISABLE); + + /* b. Define A2 to be the assertion settings: TPM_PHYSICAL_PRESENCE_LOCK, + TPM_PHYSICAL_PRESENCE_PRESENT, and TPM_PHYSICAL_PRESENCE_NOTPRESENT */ + a2 = physicalPresence & (TPM_PHYSICAL_PRESENCE_LOCK | + TPM_PHYSICAL_PRESENCE_PRESENT | + TPM_PHYSICAL_PRESENCE_NOTPRESENT); + printf("TPM_Process_PhysicalPresence: a1 %04x a2 %04x\n", a1, a2); + } + /* + Lifetime lock settings + */ + /* 2. If any A1 setting is present */ + if ((returnCode == TPM_SUCCESS) && a1) { + if (returnCode == TPM_SUCCESS) { + /* a. If TPM_PERMANENT_FLAGS -> physicalPresenceLifetimeLock is TRUE, return + TPM_BAD_PARAMETER */ + if (tpm_state->tpm_permanent_flags.physicalPresenceLifetimeLock) { + printf("TPM_Process_PhysicalPresence: Error, " + "physicalPresenceLifetimeLock is TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. If any A2 setting is present return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (a2) { + printf("TPM_Process_PhysicalPresence: Error, a1 and a2 TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* c. If both physicalPresence -> TPM_PHYSICAL_PRESENCE_HW_ENABLE and physicalPresence -> + TPM_PHYSICAL_PRESENCE_HW_DISABLE are TRUE, return TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if ((physicalPresence & TPM_PHYSICAL_PRESENCE_HW_ENABLE) && + (physicalPresence & TPM_PHYSICAL_PRESENCE_HW_DISABLE)) { + printf("TPM_Process_PhysicalPresence: Error, HW enable and disable both TRUE \n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* d. If both physicalPresence -> TPM_PHYSICAL_PRESENCE_CMD_ENABLE and physicalPresence + -> TPM_PHYSICAL_PRESENCE_CMD_DISABLE are TRUE, return TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if ((physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_ENABLE ) && + (physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_DISABLE )) { + printf("TPM_Process_PhysicalPresence: Error, CMD enable and disable both TRUE \n"); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + /* e. If physicalPresence -> TPM_PHYSICAL_PRESENCE_HW_ENABLE is TRUE Set + TPM_PERMANENT_FLAGS -> physicalPresenceHWEnable to TRUE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_HW_ENABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceHWEnable TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceHWEnable), + TRUE); /* value */ + } + /* f. If physicalPresence -> TPM_PHYSICAL_PRESENCE_HW_DISABLE is TRUE Set + TPM_PERMANENT_FLAGS -> physicalPresenceHWEnable to FALSE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_HW_DISABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceHWEnable FALSE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceHWEnable), + FALSE); /* value */ + } + /* g. If physicalPresence -> TPM_PHYSICAL_PRESENCE_CMD_ENABLE is TRUE, Set + TPM_PERMANENT_FLAGS -> physicalPresenceCMDEnable to TRUE. */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_ENABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceCMDEnable TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable), + TRUE); /* value */ + } + /* h. If physicalPresence -> TPM_PHYSICAL_PRESENCE_CMD_DISABLE is TRUE, Set + TPM_PERMANENT_FLAGS -> physicalPresenceCMDEnable to FALSE. */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_DISABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceCMDEnable FALSE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable), + FALSE); /* value */ + } + /* i. If physicalPresence -> TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK is TRUE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK) { + /* i. Set TPM_PERMANENT_FLAGS -> physicalPresenceLifetimeLock to TRUE */ + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceLifetimeLock\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceLifetimeLock), + TRUE); /* value */ + } + } + /* j. Return TPM_SUCCESS */ + } + /* + SW physical presence assertion + */ + /* 3. If any A2 setting is present */ + if ((returnCode == TPM_SUCCESS) && a2) { + /* a. If any A1 setting is present return TPM_BAD_PARAMETER */ + /* i. This check here just for consistency, the prior checks would have already ensured that + this was OK */ + if (returnCode == TPM_SUCCESS) { + if (a1) { + printf("TPM_Process_PhysicalPresence: Error, a1 and a2 TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. If TPM_PERMANENT_FLAGS -> physicalPresenceCMDEnable is FALSE, return TPM_BAD_PARAMETER + */ + if (returnCode == TPM_SUCCESS) { + if (!tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresenceCMDEnable is FALSE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* c. If both physicalPresence -> TPM_PHYSICAL_PRESENCE_LOCK and physicalPresence -> + TPM_PHYSICAL_PRESENCE_PRESENT are TRUE, return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if ((physicalPresence & TPM_PHYSICAL_PRESENCE_LOCK ) && + (physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT)) { + printf("TPM_Process_PhysicalPresence: Error, LOCK and PRESENT both TRUE \n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* d. If both physicalPresence -> TPM_PHYSICAL_PRESENCE_PRESENT and physicalPresence -> + TPM_PHYSICAL_PRESENCE_NOTPRESENT are TRUE, return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if ((physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT) && + (physicalPresence & TPM_PHYSICAL_PRESENCE_NOTPRESENT)) { + printf("TPM_Process_PhysicalPresence: Error, PRESENT and NOT_PRESENT both TRUE \n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* e. If TPM_STCLEAR_FLAGS -> physicalPresenceLock is TRUE, return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_stclear_flags.physicalPresenceLock) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresenceLock is TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + /* f. If physicalPresence -> TPM_PHYSICAL_PRESENCE_LOCK is TRUE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_LOCK) { + /* i. Set TPM_STCLEAR_FLAGS -> physicalPresence to FALSE */ + printf("TPM_Process_PhysicalPresence: Setting physicalPresence FALSE\n"); + tpm_state->tpm_stclear_flags.physicalPresence = FALSE; + /* ii. Set TPM_STCLEAR_FLAGS -> physicalPresenceLock to TRUE */ + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceLock TRUE\n"); + tpm_state->tpm_stclear_flags.physicalPresenceLock = TRUE; + /* iii. Return TPM_SUCCESS */ + } + /* g. If physicalPresence -> TPM_PHYSICAL_PRESENCE_PRESENT is TRUE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT) { + /* i. Set TPM_STCLEAR_FLAGS -> physicalPresence to TRUE */ + printf("TPM_Process_PhysicalPresence: Setting physicalPresence TRUE\n"); + tpm_state->tpm_stclear_flags.physicalPresence = TRUE; + } + /* h. If physicalPresence -> TPM_PHYSICAL_PRESENCE_NOTPRESENT is TRUE */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_NOTPRESENT) { + /* i. Set TPM_STCLEAR_FLAGS -> physicalPresence to FALSE */ + printf("TPM_Process_PhysicalPresence: Setting physicalPresence FALSE\n"); + tpm_state->tpm_stclear_flags.physicalPresence = FALSE; + } + /* i. Return TPM_SUCCESS */ + } + } + /* 4. Else There were no A1 or A2 parameters set */ + if (returnCode == TPM_SUCCESS) { + if (!a1 && !a2) { + /* a. Return TPM_BAD_PARAMETER */ + printf("TPM_Process_PhysicalPresence: Error, a1 and a2 FALSE\n"); + returnCode = TPM_BAD_PARAMETER; + } + } +#else /* TPM v1.1 */ + /* 2. Once the PhysicalPresenceLock flag is set to TRUE, the TPM MUST not modify the + PhysicalPresence flag until a TPM_Init followed by TPM_Startup(stType = TCPA_ST_CLEAR). Upon + a TPM_Init and TPM_Startup(stType = TCPA_ST_STATE) the TPM MUST set the PhysicalPresenceLock + flag to FALSE. */ + /* NOTE: I assume this is a typo, that PhysicalPresenceLock is restored by TPM_ST_STATE and set + false on TPM_ST_CLEAR. Other places in the specification certainly say that. */ + /* 3.If the PhysicalPresenceLock flag is set to TRUE upon any call to this operation, the TPM + MUST cause no action and MUST return the error TCPA_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + if (tpm_state->tpm_stclear_flags.physicalPresenceLock) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresenceLock is TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + /* NOTE: The specification doesn't say what to do if both flags are set. Following the 1.2 + specification seems reasonable. */ + if ((physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT) && + (physicalPresence & TPM_PHYSICAL_PRESENCE_NOTPRESENT)) { + printf("TPM_Process_PhysicalPresence: Error, PRESENT and NOT_PRESENT both TRUE \n"); + returnCode = TPM_BAD_PARAMETER; + } + if ((tpm_state->tpm_permanent_flags.physicalPresenceLifetimeLock) && + (physicalPresence & (TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK | + TPM_PHYSICAL_PRESENCE_HW_ENABLE | + TPM_PHYSICAL_PRESENCE_CMD_ENABLE))) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresenceLifetimeLock is TRUE\n"); + returnCode = TPM_BAD_PARAMETER; + } + if ((!tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable) && + (physicalPresence & (TPM_PHYSICAL_PRESENCE_LOCK | + TPM_PHYSICAL_PRESENCE_PRESENT | + TPM_PHYSICAL_PRESENCE_NOTPRESENT))) { + printf("TPM_Process_PhysicalPresence: Error, physicalPresenceCMDEnable is FALSE\n"); + returnCode = TPM_BAD_PARAMETER; + } + + } + /* 1. This operation MUST be implemented to process the values in the following order: */ + if (returnCode == TPM_SUCCESS) { + /* a. physicalPresenceHWEnable and physicalPresenceCMDEnable */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_HW_ENABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceHWEnable TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceHWEnable), + TRUE); /* value */ + } + if (physicalPresence & TPM_PHYSICAL_PRESENCE_CMD_ENABLE) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceCMDEnable TRUE\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceCMDEnable), + TRUE); /* value */ + } + /* b. physicalPresenceLifetimeLock */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_LIFETIME_LOCK) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceLifetimeLock\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.physicalPresenceLifetimeLock), + TRUE); /* value */ + } + /* c. PhysicalPresence */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_PRESENT) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresence TRUE\n"); + tpm_state->tpm_stclear_flags.physicalPresence = TRUE; + } + if (physicalPresence & TPM_PHYSICAL_PRESENCE_NOTPRESENT) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresence FALSE\n"); + tpm_state->tpm_stclear_flags.physicalPresence = FALSE; + } + /* d. PhysicalPresenceLock */ + if (physicalPresence & TPM_PHYSICAL_PRESENCE_LOCK) { + printf("TPM_Process_PhysicalPresence: Setting physicalPresenceLock TRUE\n"); + tpm_state->tpm_stclear_flags.physicalPresenceLock = TRUE; + } + } +#endif + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PhysicalPresence: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 6.4 TPM_DisableOwnerClear rev 87 + + The DisableOwnerClear 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. + + After the execution of TPM_ForceClear, ownerClear is re-enabled and must be explicitly disabled + again by the new TPM Owner. +*/ + +TPM_RESULT TPM_Process_DisableOwnerClear(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for owner authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization handle */ + TPM_AUTHDATA ownerAuth; /* The authorization digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey = NULL; + TPM_BOOL writeAllNV = FALSE; /* flag to write back NV */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DisableOwnerClear: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DisableOwnerClear: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. The TPM verifies that the authHandle properly authorizes the owner. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. The TPM sets the TPM_PERMANENT_FLAGS -> disableOwnerClear flag to TRUE. */ + /* 3. When this flag is TRUE the only mechanism that can clear the TPM is the TPM_ForceClear + command. The TPM_ForceClear command requires physical access to the TPM to execute. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DisableOwnerClear: Set disableOwnerClear\n"); + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.disableOwnerClear), /* flag */ + TRUE); /* value */ + } + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DisableOwnerClear: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + return rcf; +} + +/* 6.5 TPM_DisableForceClear rev 97 + + 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_Process_DisableForceClear(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_DisableForceClear: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DisableForceClear: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM sets the TPM_STCLEAR_FLAGS.disableForceClear flag in the TPM that disables the + execution of the TPM_ForceClear command. */ + if (returnCode == TPM_SUCCESS) { + tpm_state->tpm_stclear_flags.disableForceClear = TRUE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DisableForceClear: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 6.7 TSC_ResetEstablishmentBit rev 98 + + The PC TPM Interface Specification (TIS) specifies setting tpmEstablished to TRUE upon execution + of the HASH_START sequence. The setting implies the creation of a Trusted Operating System on the + platform. Platforms will use the value of tpmEstablished to determine if operations necessary to + maintain the security perimeter are necessary. + + The tpmEstablished bit provides a non-volatile, secure reporting that a HASH_START was previously + run on the platform. When a platform makes use of the tpmEstablished bit, the platform can reset + tpmEstablished as the operation is no longer necessary. + + For example, a platform could use tpmEstablished to ensure that, if HASH_START had ever been, + executed the platform could use the value to invoke special processing. Once the processing is + complete the platform will wish to reset tpmEstablished to avoid invoking the special process + again. + + The TPM_PERMANENT_FLAGS -> tpmEstablished bit described in the TPM specifications uses positive + logic. The TPM_ACCESS register uses negative logic, so that TRUE is reflected as a 0. +*/ + +TPM_RESULT TPM_Process_ResetEstablishmentBit(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL writeAllNV = FALSE; /* flag to write back flags */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_ResetEstablishmentBit: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ResetEstablishmentBit: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate the assertion of locality 3 or locality 4 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Locality_Check(TPM_LOC_THREE | TPM_LOC_FOUR, /* BYTE bitmap */ + tpm_state->tpm_stany_flags.localityModifier); + } + /* 2. Set TPM_PERMANENT_FLAGS -> tpmEstablished to FALSE */ + if (returnCode == TPM_SUCCESS) { + TPM_SetCapability_Flag(&writeAllNV, /* altered */ + &(tpm_state->tpm_permanent_flags.tpmEstablished), /* flag */ + FALSE); /* value */ + + } + /* Store the permanent flags back to NVRAM */ + returnCode = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + returnCode); + /* 3. Return TPM_SUCCESS */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ResetEstablishmentBit: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + diff --git a/src/tpm_owner.h b/src/tpm_owner.h new file mode 100644 index 00000000..b96464f4 --- /dev/null +++ b/src/tpm_owner.h @@ -0,0 +1,107 @@ +/********************************************************************************/ +/* */ +/* Ownership Processing */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_owner.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_OWNER_H +#define TPM_OWNER_H + +#include "tpm_global.h" +#include "tpm_secret.h" +#include "tpm_store.h" +#include "tpm_types.h" + +TPM_RESULT TPM_OwnerClearCommon(tpm_state_t *tpm_state, + TPM_BOOL deleteAllNvram); + +TPM_RESULT TPM_Process_TakeOwnership(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_OwnerClear(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_PhysicalPresence(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_DisableOwnerClear(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_ForceClear(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_DisableForceClear(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + +TPM_RESULT TPM_Process_ResetEstablishmentBit(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +#endif diff --git a/src/tpm_pcr.c b/src/tpm_pcr.c new file mode 100644 index 00000000..629c1b10 --- /dev/null +++ b/src/tpm_pcr.c @@ -0,0 +1,3791 @@ +/********************************************************************************/ +/* */ +/* PCR Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_pcr.c 4620 2011-09-07 21:43:19Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_constants.h" +#include "tpm_cryptoh.h" +#include "tpm_digest.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_global.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_process.h" +#include "tpm_sizedbuffer.h" +#include "tpm_types.h" +#include "tpm_ver.h" + +#include "tpm_pcr.h" + + +/* + Locality Utilities +*/ + +/* TPM_Locality_Set() sets a bit in the TPM_LOCALITY_SELECTION (BYTE) bitmap based on the + TPM_STANY_FLAGS -> TPM_MODIFIER_INDICATOR (uint32_t) -> localityModifier +*/ + +TPM_RESULT TPM_Locality_Set(TPM_LOCALITY_SELECTION *tpm_locality_selection, /* BYTE bitmap */ + TPM_MODIFIER_INDICATOR tpm_modifier_indicator) /* uint32_t from + TPM_STANY_FLAGS + */ +{ + TPM_RESULT rc = 0; + printf(" TPM_Locality_Set:\n"); + switch (tpm_modifier_indicator) { + case 0: + *tpm_locality_selection = TPM_LOC_ZERO; + break; + case 1: + *tpm_locality_selection = TPM_LOC_ONE; + break; + case 2: + *tpm_locality_selection = TPM_LOC_TWO; + break; + case 3: + *tpm_locality_selection = TPM_LOC_THREE; + break; + case 4: + *tpm_locality_selection = TPM_LOC_FOUR; + break; + default: + /* This should never occur. The code that sets TPM_STANY_FLAGS should screen out bad values + */ + printf("TPM_Locality_Set: Error (fatal), tpm_modifier_indicator %u out of range\n", + tpm_modifier_indicator); + rc = TPM_FAIL; + } + return rc; +} + +/* TPM_Locality_Check() checks that a bit in the TPM_LOCALITY_SELECTION (BYTE) bitmap is set for bit + TPM_STANY_FLAGS -> TPM_MODIFIER_INDICATOR (uint32_t) -> localityModifier + + 'tpm_locality_selection' is typically localityAtRelease, pcrResetLocal, pcrExtendLocal + 'localityModifier' is TPM_STANY_FLAGS.localityModifier +*/ + +TPM_RESULT TPM_Locality_Check(TPM_LOCALITY_SELECTION tpm_locality_selection, /* BYTE bitmap */ + TPM_MODIFIER_INDICATOR localityModifier) /* uint32_t from + TPM_STANY_FLAGS */ +{ + + TPM_RESULT rc = 0; + printf(" TPM_Locality_Check:\n"); + switch (localityModifier) { + case 0: + if ((tpm_locality_selection & TPM_LOC_ZERO) == 0) { + rc = TPM_BAD_LOCALITY; + } + break; + case 1: + if ((tpm_locality_selection & TPM_LOC_ONE) == 0) { + rc = TPM_BAD_LOCALITY; + } + break; + case 2: + if ((tpm_locality_selection & TPM_LOC_TWO) == 0) { + rc = TPM_BAD_LOCALITY; + } + break; + case 3: + if ((tpm_locality_selection & TPM_LOC_THREE) == 0) { + rc = TPM_BAD_LOCALITY; + } + break; + case 4: + if ((tpm_locality_selection & TPM_LOC_FOUR) == 0) { + rc = TPM_BAD_LOCALITY; + } + break; + default: + /* This should never occur. The code that sets TPM_STANY_FLAGS should screen out bad values + */ + printf("TPM_Locality_Check: Error (fatal), localityModifier %u out of range\n", + localityModifier); + rc = TPM_FAIL; + } + if (rc != 0) { + printf("TPM_Locality_Check: Error, " + "localityModifier %u tpm_locality_selection %02x\n", + localityModifier, tpm_locality_selection); + } + return rc; +} + +TPM_RESULT TPM_LocalitySelection_CheckLegal(TPM_LOCALITY_SELECTION tpm_locality_selection) /* BYTE + bitmap */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_LocalitySelection_CheckLegal: TPM_LOCALITY_SELECTION %02x\n", + tpm_locality_selection); + /* if any extra bits are set, illegal value */ + if ((tpm_locality_selection & ~TPM_LOC_ALL) || + /* This value MUST not be zero (0). (can never be satisfied) */ + (tpm_locality_selection == 0)) { + printf("TPM_LocalitySelection_CheckLegal: Error, bad locality selection %02x\n", + tpm_locality_selection); + rc = TPM_INVALID_STRUCTURE; + } + return rc; +} + +TPM_RESULT TPM_LocalityModifier_CheckLegal(TPM_MODIFIER_INDICATOR localityModifier) +{ + TPM_RESULT rc = 0; + + printf(" TPM_LocalityModifier_CheckLegal: TPM_MODIFIER_INDICATOR %08x\n", localityModifier); + /* if past the maximum, illegal value */ + if (localityModifier > TPM_LOC_MAX) { + printf("TPM_LocalityModifier_CheckLegal: Error, bad locality modifier %u\n", + localityModifier); + rc = TPM_BAD_LOCALITY; + } + return rc; +} + +void TPM_PCRLocality_Compare(TPM_BOOL *match, + TPM_LOCALITY_SELECTION tpm_locality_selection1, + TPM_LOCALITY_SELECTION tpm_locality_selection2) +{ + if (tpm_locality_selection1 == tpm_locality_selection2) { + *match = TRUE; + } + else { + *match = FALSE; + } + return; +} + +/* + state PCR's +*/ + +TPM_RESULT TPM_PCR_CheckRange(TPM_PCRINDEX index) +{ + TPM_RESULT rc = 0; + + if (index >= TPM_NUM_PCR) { + printf("TPM_PCR_CheckRange: Error, PCR index was %u should be <= %u\n", + index, TPM_NUM_PCR); + rc = TPM_BADINDEX; + } + return rc; +} + +/* TPM_PCR_Init() initializes the PCR based on the platform specification. This should be called by + TPM_Init. + + The caller must check that the PCR index is in range! +*/ + +void TPM_PCR_Init(TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes, + size_t pcrIndex) +{ + printf(" TPM_PCR_Init: pcrIndex %lu\n", (unsigned long)pcrIndex); + +#if defined TPM_PCCLIENT /* These values are from the PC Client specification */ + tpm_pcr_attributes = tpm_pcr_attributes; + if ((pcrIndex >= 17) && (pcrIndex <= 22)) { + TPM_Digest_Set(tpm_pcrs[pcrIndex]); /* 17-22 init to ff */ + } + else { + TPM_Digest_Init(tpm_pcrs[pcrIndex]); /* 0-16,23 init to 0 */ + } + /* #elif Add other platform specific values here */ +#else /* This is the default case for the main specification */ + if (!(tpm_pcr_attributes[pcrIndex].pcrReset)) { + /* FALSE- Default value of the PCR MUST be 0x00..00 */ + TPM_Digest_Init(tpm_pcrs[pcrIndex]); + } + else { + /* TRUE - Default value of the PCR MUST be 0xFF..FF. */ + TPM_Digest_Set(tpm_pcrs[pcrIndex]); + } +#endif + return; +} + +/* TPM_PCR_Reset() resets the PCR based on the platform specification. This should be called by the + TPM_PCR_Reset ordinal. + + The caller must check that the PCR index is in range and that pcrReset is TRUE! +*/ + +void TPM_PCR_Reset(TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + TPM_BOOL TOSPresent, + TPM_PCRINDEX pcrIndex) +{ + TPM_PCRVALUE zeroPCR; + TPM_PCRVALUE onesPCR; + + TPM_Digest_Init(zeroPCR); + TPM_Digest_Set(onesPCR); +#if defined TPM_PCCLIENT /* These values are from the PC Client specification */ + if (TOSPresent || /* TOSPresent -> 00 */ + (pcrIndex == 16) || /* PCR 16 -> 00 */ + (pcrIndex == 23)) { /* PCR 23 -> 00 */ + TPM_PCR_Store(tpm_pcrs, pcrIndex, zeroPCR); + } + else { + TPM_PCR_Store(tpm_pcrs, pcrIndex, onesPCR); /* PCR 17-22 -> ff */ + } + /* #elif Add other platform specific values here */ +#else /* This is the default case for the main specification */ + if (TOSPresent) { + TPM_PCR_Store(tpm_pcrs, pcrIndex, zeroPCR); + } + else { + TPM_PCR_Store(tpm_pcrs, pcrIndex, onesPCR); + } +#endif + return; +} + +/* TPM_PCR_Load() copies the PCR at 'index' to 'dest_pcr' + +*/ + +TPM_RESULT TPM_PCR_Load(TPM_PCRVALUE dest_pcr, + TPM_PCRVALUE *tpm_pcrs, + TPM_PCRINDEX index) +{ + TPM_RESULT rc = 0; + + /* range check pcrNum */ + if (rc == 0) { + rc = TPM_PCR_CheckRange(index); + } + if (rc == 0) { + TPM_Digest_Copy(dest_pcr, tpm_pcrs[index]); + } + return rc; +} + +/* TPM_PCR_Store() copies 'src_pcr' to the PCR at 'index' + +*/ + +TPM_RESULT TPM_PCR_Store(TPM_PCRVALUE *tpm_pcrs, + TPM_PCRINDEX index, + TPM_PCRVALUE src_pcr) +{ + TPM_RESULT rc = 0; + + /* range check pcrNum */ + if (rc == 0) { + rc = TPM_PCR_CheckRange(index); + } + if (rc == 0) { + TPM_Digest_Copy(tpm_pcrs[index], src_pcr); + } + return rc; +} + +/* + TPM_SELECT_SIZE +*/ + +/* TPM_SelectSize_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SelectSize_Init(TPM_SELECT_SIZE *tpm_select_size) +{ + printf(" TPM_SelectSize_Init:\n"); + tpm_select_size->major = TPM_MAJOR; + tpm_select_size->minor = TPM_MINOR; + tpm_select_size->reqSize = TPM_NUM_PCR/CHAR_BIT; + return; +} + +/* TPM_SelectSize_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_SelectSize_Init() +*/ + +TPM_RESULT TPM_SelectSize_Load(TPM_SELECT_SIZE *tpm_select_size, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + printf(" TPM_SelectSize_Load:\n"); + /* load major */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_select_size->major), stream, stream_size); + } + /* This SHALL indicate the major version of the TPM. This MUST be 0x01 */ + if (rc == 0) { + if (tpm_select_size->major != 0x01) { + printf("TPM_SelectSize_Load: Error, major %02x should be 01\n", tpm_select_size->major); + rc = TPM_BAD_PARAMETER; + } + } + /* load minor */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_select_size->minor), stream, stream_size); + } + /* This SHALL indicate the minor version of the TPM. This MAY be 0x01 or 0x02 */ + if (rc == 0) { + if ((tpm_select_size->minor != 0x01) && + (tpm_select_size->minor != 0x02)) { + printf("TPM_SelectSize_Load: Error, minor %02x should be 01\n", tpm_select_size->minor); + rc = TPM_BAD_PARAMETER; + } + } + /* load reqSize */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_select_size->reqSize), stream, stream_size); + } + return rc; +} + +/* + TPM_PCR_ATTRIBUTES +*/ + +/* 8.9 Debug PCR register + + There is a need to define a PCR that allows for debugging. The attributes of the debug register + are such that it is easy to reset but the register provides no measurement value that can not be + spoofed. Production applications should not use the debug PCR for any SEAL or other + operations. The anticipation is that the debug PCR is set and used by application developers + during the application development cycle. Developers are responsible for ensuring that a conflict + between two programs does not invalidate the settings they are interested in. + + The specific register that is the debug PCR MUST be set by the platform specific specification. + + The attributes for the debug PCR SHALL be the following: + pcrReset = TRUE; + pcrResetLocal = 0x1f; + pcrExtendLocal = 0x1f; + pcrUseLocal = 0x1f + + These settings are to create a PCR register that developers can use to reset at any time during + their development cycle. + + The debug PCR does NOT need to be saved during TPM_SaveState. + + 8.7 PCR Attributes + + 1. The PCR attributes MUST be set during manufacturing. + + 2. For a specific PCR register, the PCR attributes MUST match the requirements of the TCG + platform specific specification that describes the platform. +*/ + +void TPM_PCRAttributes_Init(TPM_PCR_ATTRIBUTES *tpm_pcr_attributes) +{ + size_t i; + + printf(" TPM_PCRAttributes_Init:\n"); + for (i = 0 ; i < TPM_NUM_PCR ; i++) { +#if defined TPM_PCCLIENT /* These values are from the PC Client specification */ +#if TPM_NUM_PCR != 24 +#error "Number of PCRs must be 24 for PC Client" +#endif + if (i <=15) { + tpm_pcr_attributes[i].pcrReset = FALSE; /* 0-15 are not resettable */ + tpm_pcr_attributes[i].pcrResetLocal = 0; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_ALL; + } + else { + tpm_pcr_attributes[i].pcrReset = TRUE; + switch (i) { + case 16: + case 23: + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_ALL; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_ALL; + break; + case 17: + case 18: + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_FOUR; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_FOUR | TPM_LOC_THREE | TPM_LOC_TWO; + break; + case 19: + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_FOUR; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_THREE | TPM_LOC_TWO; + break; + case 20: + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_FOUR | TPM_LOC_TWO; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_THREE | TPM_LOC_TWO | TPM_LOC_ONE; + break; + case 21: + case 22: + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_TWO; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_TWO; + break; + } + } + /* #elif Add other platform specific values here */ +#else /* This is the default case for the main specification */ + if (i != TPM_DEBUG_PCR) { + tpm_pcr_attributes[i].pcrReset = FALSE; + tpm_pcr_attributes[i].pcrResetLocal = 0; /* not relevant when pcrReset is FALSE */ + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_ALL; + } + else { /* debug PCR */ + tpm_pcr_attributes[i].pcrReset = TRUE; + tpm_pcr_attributes[i].pcrResetLocal = TPM_LOC_ALL; + tpm_pcr_attributes[i].pcrExtendLocal = TPM_LOC_ALL; + } +#endif + } + return; +} + +/* TPM_PCRInfo_Trace() traces some PCR Info components */ + +void TPM_PCRInfo_Trace(const char *message, + TPM_PCR_SELECTION pcrSelection, + TPM_COMPOSITE_HASH digestAtRelease) +{ + printf("%s\n", message); + printf("\tsizeOfSelect %hu\n", pcrSelection.sizeOfSelect); + printf("\tpcrSelect %02x %02x %02x\n", + pcrSelection.pcrSelect[0], + pcrSelection.pcrSelect[1], + pcrSelection.pcrSelect[2]); + TPM_PrintFour("\tdigestAtRelease", + digestAtRelease); + return; +} + +/* + PCRs - Functions that act on the entire set of PCRs +*/ + +/* TPM_PCRs_Init() initializes the entire PCR array. + + Typically called from TPM_Init. +*/ + +void TPM_PCRs_Init(TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes) +{ + size_t i; + + printf(" TPM_PCRs_Init:\n"); + for (i = 0 ; i < TPM_NUM_PCR ; i++) { + TPM_PCR_Init(tpm_pcrs, tpm_pcr_attributes, i); /* initialize a single PCR */ + } + return; +} + +TPM_RESULT TPM_PCRs_Load(TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PCRs_Load:\n"); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_PCR) ; i++) { + /* FALSE: Saved by TPM_SaveState + TRUE: MUST not be part of any state stored by TPM_SaveState */ + if (!(tpm_pcr_attributes[i].pcrReset)) { + rc = TPM_Digest_Load(tpm_pcrs[i], stream, stream_size); + } + } + return rc; +} + +TPM_RESULT TPM_PCRs_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PCRs_Store:\n"); + for (i = 0 ; (rc == 0) && (i < TPM_NUM_PCR) ; i++) { + /* FALSE: Saved by TPM_SaveState + TRUE: MUST not be part of any state stored by TPM_SaveState */ + if (!(tpm_pcr_attributes[i].pcrReset)) { + TPM_Digest_Store(sbuffer, tpm_pcrs[i]); + } + } + return rc; +} + +/* + TPM_PCR_COMPOSITE +*/ + +/* TPM_PCRComposite_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_PCRComposite_Init(TPM_PCR_COMPOSITE *tpm_pcr_composite) +{ + TPM_PCRSelection_Init(&(tpm_pcr_composite->select)); + TPM_SizedBuffer_Init(&(tpm_pcr_composite->pcrValue)); + return; +} + +/* TPM_PCRComposite_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + After use, call TPM_PCRComposite_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRComposite_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_COMPOSITE *tpm_pcr_composite) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRComposite_Store:\n"); + + /* store TPM_PCR_SELECTION select */ + if (rc == 0) { + rc = TPM_PCRSelection_Store(sbuffer, &(tpm_pcr_composite->select)); + } + /* store pcrValue */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_pcr_composite->pcrValue)); + } + return rc; +} + +/* TPM_PCRComposite_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_PCRComposite_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_PCRComposite_Delete(TPM_PCR_COMPOSITE *tpm_pcr_composite) +{ + printf(" TPM_PCRComposite_Delete:\n"); + if (tpm_pcr_composite != NULL) { + TPM_PCRSelection_Delete(&(tpm_pcr_composite->select)); + TPM_SizedBuffer_Delete(&(tpm_pcr_composite->pcrValue)); + TPM_PCRComposite_Init(tpm_pcr_composite); + } + return; +} + +/* TPM_PCRComposite_Set() + + sets members to input parameter values + allocates memory as required to fill in pointers + returns 0 or error codes + + After use, call TPM_PCRComposite_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRComposite_Set(TPM_PCR_COMPOSITE *tpm_pcr_composite, + TPM_PCR_SELECTION *tpm_pcr_selection, /* input selection map */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR array */ +{ + TPM_RESULT rc = 0; + size_t i; /* byte in map */ + size_t j; /* bit map in byte */ + size_t pcrs = 0; /* number of selected PCR's */ + TPM_PCRINDEX pcr_num; /* selected PCR being copied */ + size_t comp_num; /* index into composite */ + + printf(" TPM_PCRComposite_Set:\n"); + /* test sizeOfSelect value */ + if (rc == 0) { + rc = TPM_PCRSelection_CheckRange(tpm_pcr_selection); + } + /* construct the TPM_PCR_COMPOSITE structure */ + if (rc == 0) { + /* copy the TPM_PCR_SELECTION member */ + rc = TPM_PCRSelection_Copy(&(tpm_pcr_composite->select), tpm_pcr_selection); + } + /* iterate through all bytes in tpm_pcr_selection to count the number of selected PCR's */ + if (rc == 0) { + for (i = 0, pcrs = 0 ; i < tpm_pcr_selection->sizeOfSelect ; i++) { + /* iterate through all bits in each byte */ + for (j = 0x0001 ; j != (0x0001 << CHAR_BIT) ; j <<= 1) { + if (tpm_pcr_selection->pcrSelect[i] & j) { /* if the bit is set in the map */ + pcrs++; + } + } + } + } + /* allocate memory for the pcrValue member (a TPM_PCRVALUE for each selected PCR) */ + if ((rc == 0) && (pcrs > 0)) { + printf(" TPM_PCRComposite_Set: Digesting %lu pcrs\n", (unsigned long)pcrs); + rc = TPM_SizedBuffer_Allocate(&(tpm_pcr_composite->pcrValue), pcrs * sizeof(TPM_PCRVALUE)); + } + /* Next iterate through all bytes in tpm_pcr_selection and copy to TPM_PCR_COMPOSITE */ + if ((rc == 0) && (pcrs > 0)) { + for (i = 0, pcr_num = 0, comp_num = 0 ; i < tpm_pcr_selection->sizeOfSelect ; i++) { + /* iterate through all bits in each byte */ + for (j = 0x0001 ; j != (0x0001 << CHAR_BIT) ; j <<= 1, pcr_num++) { + if (tpm_pcr_selection->pcrSelect[i] & j) { /* if the bit is set in the map */ + /* append the the PCR value to TPM_PCR_COMPOSITE.pcrValue */ + /* NOTE: Ignore return code since range checked by + TPM_PCRSelection_CheckRange() */ + TPM_PCR_Load(&(tpm_pcr_composite->pcrValue.buffer[comp_num]), + tpm_pcrs, pcr_num); + comp_num += sizeof(TPM_PCRVALUE); + } + } + } + } + return rc; +} + +/* + TPM_PCR_INFO_SHORT +*/ + +void TPM_PCRInfoShort_Init(TPM_PCR_INFO_SHORT *tpm_pcr_info_short) +{ + TPM_PCRSelection_Init(&(tpm_pcr_info_short->pcrSelection)); + tpm_pcr_info_short->localityAtRelease = TPM_LOC_ALL; + TPM_Digest_Init(tpm_pcr_info_short->digestAtRelease); + return; +} + +/* TPM_PCRInfoShort_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + optimize invokes a special version used to an load TPM_NV_DATA_PUBLIC that may not include + digestAtRelease + + After use, call TPM_PCRInfoShort_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRInfoShort_Load(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL optimize) +{ + TPM_RESULT rc = 0; + TPM_BOOL pcrUsage = TRUE; + + printf(" TPM_PCRInfoShort_Load:\n"); + /* load pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Load(&(tpm_pcr_info_short->pcrSelection), stream, stream_size); + } + /* load the localityAtRelease */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_pcr_info_short->localityAtRelease), stream, stream_size); + } + /* check locality value */ + if (rc == 0) { + rc = TPM_LocalitySelection_CheckLegal(tpm_pcr_info_short->localityAtRelease); + } + /* if the store was optimized, check whether the pcrSelection specifies PCRs */ + if ((rc == 0) && optimize) { + rc = TPM_PCRSelection_GetPCRUsage(&pcrUsage, + &(tpm_pcr_info_short->pcrSelection), + 0); /* start_index */ + } + /* load the digestAtRelease */ + if (rc == 0) { + if (pcrUsage) { + rc = TPM_Digest_Load(tpm_pcr_info_short->digestAtRelease, stream, stream_size); + } + /* A pcrSelect of 0 indicates that the digestAsRelease is not checked. In this case, the TPM is + not required to consume NVRAM space to store the digest, although it may do so. When + TPM_GetCapability (TPM_CAP_NV_INDEX) returns the structure, a TPM that does not store the + digest can return zero. A TPM that does store the digest may return either the digest or + zero. Software should not be written to depend on either implementation. + */ + else { + TPM_Digest_Init(tpm_pcr_info_short->digestAtRelease); + } + } + return rc; +} + +/* TPM_PCRInfoShort_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + optimize invokes a special version used to an store TPM_NV_DATA_PUBLIC that may not include + digestAtRelease + + After use, call TPM_Sbuffer_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRInfoShort_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + TPM_BOOL optimize) +{ + TPM_RESULT rc = 0; + TPM_BOOL pcrUsage = TRUE; + + printf(" TPM_PCRInfoShort_Store:\n"); + /* store pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Store(sbuffer, &(tpm_pcr_info_short->pcrSelection)); + } + /* store the localityAtRelease */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_pcr_info_short->localityAtRelease), + sizeof(TPM_LOCALITY_SELECTION)); + } + /* check whether the pcrSelection specifies PCRs */ + if ((rc == 0) && optimize) { + rc = TPM_PCRSelection_GetPCRUsage(&pcrUsage, + &(tpm_pcr_info_short->pcrSelection), + 0); /* start_index */ + } + /* store the digestAtRelease */ + /* A pcrSelect of 0 indicates that the digestAsRelease is not checked. In this case, the TPM is + not required to consume NVRAM space to store the digest, although it may do so. When + TPM_GetCapability (TPM_CAP_NV_INDEX) returns the structure, a TPM that does not store the + digest can return zero. A TPM that does store the digest may return either the digest or + zero. Software should not be written to depend on either implementation. + */ if ((rc == 0) && pcrUsage) { + rc = TPM_Digest_Store(sbuffer, tpm_pcr_info_short->digestAtRelease); + } + return rc; +} + +/* TPM_PCRInfoShort_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the PCRInfoShort + sets pointers to NULL + calls TPM_PCRInfoShort_Init to set members back to default values + The PCRInfoShort itself is not freed + returns 0 or error codes +*/ + +void TPM_PCRInfoShort_Delete(TPM_PCR_INFO_SHORT *tpm_pcr_info_short) +{ + printf(" TPM_PCRInfoShort_Delete:\n"); + if (tpm_pcr_info_short != NULL) { + TPM_PCRSelection_Delete(&(tpm_pcr_info_short->pcrSelection)); + TPM_PCRInfoShort_Init(tpm_pcr_info_short); + } + return; +} + +/* TPM_PCRInfoShort_Create() allocates memory for a TPM_PCR_INFO_SHORT + +*/ + +TPM_RESULT TPM_PCRInfoShort_Create(TPM_PCR_INFO_SHORT **tpm_pcr_info_short) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoShort_Create:\n"); + /* This function should never be called when the TPM_PCR_INFO_SHORT structure has already been + loaded. This indicates an internal error. */ + if (rc == 0) { + if (*tpm_pcr_info_short != NULL) { + printf("TPM_PCRInfoShort_Create: Error (fatal), TPM_PCR_INFO_SHORT already loaded\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)tpm_pcr_info_short, sizeof(TPM_PCR_INFO_SHORT)); + } + return rc; +} + +/* TPM_PCRInfoShort_SetFromBuffer() sets a TPM_PCR_INFO_SHORT from a stream specified by a + TPM_SIZED_BUFFER. The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfoShort_LoadFromBuffer(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_PCRInfoShort_LoadFromBuffer:\n"); + if (rc == 0) { + TPM_PCRInfoShort_Init(tpm_pcr_info_short); + stream = tpm_sized_buffer->buffer; + stream_size = tpm_sized_buffer->size; + /* deserialize the TPM_SIZED_BUFFER into a TPM_PCR_INFO_SHORT structure */ + rc = TPM_PCRInfoShort_Load(tpm_pcr_info_short, &stream, &stream_size, FALSE); + } + return rc; +} + +/* TPM_PCRInfoShort_CreateFromBuffer() allocates the TPM_PCR_INFO_SHORT structure, typically a cache + within another structure. It then deserializes the TPM_SIZED_BUFFER into the structure. + + The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfoShort_CreateFromBuffer(TPM_PCR_INFO_SHORT **tpm_pcr_info_short, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoShort_CreateFromBuffer:\n"); + /* if there is no TPM_PCR_INFO_SHORT - done */ + if (rc == 0) { + if (tpm_sized_buffer->size == 0) { + done = TRUE; + } + } + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_Create(tpm_pcr_info_short); + } + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_LoadFromBuffer(*tpm_pcr_info_short, tpm_sized_buffer); + } + return rc; +} + +/* TPM_PCRInfoShort_Copy() copies the source pcrSelection, digestAtRelease, and digestAtCreation. + +*/ + +TPM_RESULT TPM_PCRInfoShort_Copy(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO_SHORT *src_tpm_pcr_info_short) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoShort_Copy:\n"); + /* copy TPM_PCR_SELECTION pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info_short->pcrSelection), + &(src_tpm_pcr_info_short->pcrSelection)); + } + if (rc == 0) { + /* copy TPM_LOCALITY_SELECTION localityAtRelease */ + dest_tpm_pcr_info_short->localityAtRelease = src_tpm_pcr_info_short->localityAtRelease; + /* copy TPM_COMPOSITE_HASH digestAtRelease */ + TPM_Digest_Copy(dest_tpm_pcr_info_short->digestAtRelease, + src_tpm_pcr_info_short->digestAtRelease); + } + return rc; +} + +/* TPM_PCRInfoShort_CopyInfo() copies the source TPM_PCR_INFO to the destination TPM_PCR_INFO_SHORT. + + It copies pcrSelection and digestAtRelease. + + It handles localityAtRelease as per the specification. +*/ + +TPM_RESULT TPM_PCRInfoShort_CopyInfo(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO *src_tpm_pcr_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoShort_CopyInfo:\n"); + /* 4. To set IS from IN */ + /* a. Set IS -> pcrSelection to IN -> pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info_short->pcrSelection), + &(src_tpm_pcr_info->pcrSelection)); + } + /* b. Set IS -> digestAtRelease to IN -> digestAtRelease */ + if (rc == 0) { + TPM_Digest_Copy(dest_tpm_pcr_info_short->digestAtRelease, + src_tpm_pcr_info->digestAtRelease); + /* c. Set IS -> localityAtRelease to 0x1F to indicate all localities are valid */ + dest_tpm_pcr_info_short->localityAtRelease = TPM_LOC_ALL; + /* d. Ignore IN -> digestAtCreation */ + } + return rc; +} + +/* TPM_PCRInfoShort_CopyInfoLong() copies the source TPM_PCR_INFO_LONG to the destination + TPM_PCR_INFO_SHORT. + + It copies creationPCRSelection, localityAtRelease, digestAtRelease. +*/ + +TPM_RESULT TPM_PCRInfoShort_CopyInfoLong(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoShort_CopyInfoLong:\n"); + /* 5. To set IS from IL */ + /* a. Set IS -> pcrSelection to IL -> releasePCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info_short->pcrSelection), + &(src_tpm_pcr_info_long->releasePCRSelection)); + } + /* b. Set IS -> localityAtRelease to IL -> localityAtRelease */ + if (rc == 0) { + dest_tpm_pcr_info_short->localityAtRelease = src_tpm_pcr_info_long->localityAtRelease; + /* c. Set IS -> digestAtRelease to IL -> digestAtRelease */ + TPM_Digest_Copy(dest_tpm_pcr_info_short->digestAtRelease, + src_tpm_pcr_info_long->digestAtRelease); + /* d. Ignore all other IL values */ + } + return rc; +} + +/* TPM_PCRInfoShort_CreateFromInfo() allocates memory for the TPM_PCR_INFO_SHORT structure. It + copies the source to the destination. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfoShort_CreateFromInfo(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_PCR_INFO *src_tpm_pcr_info) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoShort_CreateFromInfo:\n"); + if (rc == 0) { + /* if there is no source, leave the destination NULL */ + if (src_tpm_pcr_info == NULL) { + done = TRUE; + } + } + /* create the structure */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_Create(dest_tpm_pcr_info_short); + } + /* copy source to destination */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_CopyInfo(*dest_tpm_pcr_info_short, src_tpm_pcr_info); + } + return rc; +} + +/* TPM_PCRInfo_CreateFromInfoLong() allocates memory for the TPM_PCR_INFO structure. It copies the + source to the destination. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfoShort_CreateFromInfoLong(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoShort_CreateFromInfoLong:\n"); + /* if there is no source, leave the destination NULL */ + if (rc == 0) { + if (src_tpm_pcr_info_long == NULL) { + done = TRUE; + } + } + /* create the structure */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_Create(dest_tpm_pcr_info_short); + } + /* copy source to destination */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoShort_CopyInfoLong(*dest_tpm_pcr_info_short, src_tpm_pcr_info_long); + } + return rc; +} + +/* TPM_PCRInfoShort_CreateFromKey() allocates memory for the TPM_PCR_INFO_SHORT structure. + + If the input is a TPM_KEY, it copies the TPM_PCR_INFO cache. + + If the input is a TPM_KEY12, it copies the TPM_PCR_INFO_LONG cache. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfoShort_CreateFromKey(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoShort_CreateFromKey:\n"); + if (rc == 0) { + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_PCRInfoShort_CreateFromInfo(dest_tpm_pcr_info_short, + tpm_key->tpm_pcr_info); + } + else { /* TPM_KEY12 */ + rc = TPM_PCRInfoShort_CreateFromInfoLong(dest_tpm_pcr_info_short, + tpm_key->tpm_pcr_info_long); + } + } + return rc; +} + +/* TPM_PCRInfoShort_GenerateDigest() generates a Part 2 5.3.1 PCR composite hash + +*/ + +TPM_RESULT TPM_PCRInfoShort_GenerateDigest(TPM_DIGEST tpm_digest, /* output digest */ + TPM_PCR_INFO_SHORT *tpm_pcr_info_short, /* input */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR array */ +{ + TPM_RESULT rc = 0; + TPM_PCR_SELECTION *tpm_pcr_selection; + + printf(" TPM_PCRInfoShort_GenerateDigest:\n"); + if (rc == 0) { + if (tpm_pcr_info_short == NULL) { + printf("TPM_PCRInfoShort_GenerateDigest: Error (fatal), TPM_PCR_INFO_SHORT is NULL\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + tpm_pcr_selection = &(tpm_pcr_info_short->pcrSelection); /* get the TPM_PCR_SELECTION */ + rc = TPM_PCRSelection_GenerateDigest(tpm_digest, /* output digest */ + tpm_pcr_selection, /* input selection map */ + tpm_pcrs); /* points to the TPM PCR array */ + } + return rc; +} + +/* TPM_PCRInfoShort_CheckDigest() calculates a digestAtRelease based on the TPM_PCR_SELECTION and + compares it to digestAtRelease in the structure. +*/ + +TPM_RESULT TPM_PCRInfoShort_CheckDigest(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + TPM_MODIFIER_INDICATOR localityModifier) +{ + TPM_RESULT rc = 0; + TPM_COMPOSITE_HASH tpm_composite_hash; + TPM_BOOL pcrUsage; /* TRUE if PCR's are specified */ + + printf(" TPM_PCRInfoShort_CheckDigest:\n"); + /* returns FALSE if tpm_pcr_info_short is NULL or selection bitmap is zero */ + if (rc == 0) { + rc = TPM_PCRInfoShort_GetPCRUsage(&pcrUsage, tpm_pcr_info_short); + } + /* Calculate a TPM_COMPOSITE_HASH of the PCR selected by tpm_pcr_info_short -> + pcrSelection */ + if ((rc == 0) && pcrUsage) { + rc = TPM_PCRSelection_GenerateDigest(tpm_composite_hash, + &(tpm_pcr_info_short->pcrSelection), + tpm_pcrs); /* array of PCR's */ + } + /* Compare to tpm_pcr_info_short -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if ((rc == 0) && pcrUsage) { + rc = TPM_Digest_Compare(tpm_composite_hash, + tpm_pcr_info_short->digestAtRelease); + if (rc != 0) { + printf("TPM_PCRInfoShort_CheckDigest: Error, wrong digestAtRelease value\n"); + rc = TPM_WRONGPCRVAL; + } + } + /* If localityAtRelease is NOT 0x1f */ + if ((rc == 0) && (tpm_pcr_info_short != NULL)) { + if (tpm_pcr_info_short->localityAtRelease != TPM_LOC_ALL) { + /* Validate that TPM_STANY_FLAGS -> localityModifier is matched by tpm_pcr_info_short -> + localityAtRelease on mismatch return TPM_BAD_LOCALITY */ + rc = TPM_Locality_Check(tpm_pcr_info_short->localityAtRelease, + localityModifier); + } + } + return rc; +} + +/* TPM_PCRInfoShort_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit + mask. Returns FALSE if the TPM_PCR_INFO_SHORT is NULL. +*/ + +TPM_RESULT TPM_PCRInfoShort_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO_SHORT *tpm_pcr_info_short) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoShort_GetPCRUsage\n"); + if (rc == 0) { + /* if a loaded key had no pcrInfoShort, the structure remains NULL */ + if (tpm_pcr_info_short == NULL) { + *pcrUsage = FALSE; + done = TRUE; + } + } + if ((rc == 0) && !done) { + rc = TPM_PCRSelection_GetPCRUsage(pcrUsage, &(tpm_pcr_info_short->pcrSelection), 0); + } + if (rc == 0) { + printf(" TPM_PCRInfoShort_GetPCRUsage: Result %d\n", *pcrUsage); + } + return rc; +} + +/* + TPM_PCR_INFO +*/ + +void TPM_PCRInfo_Init(TPM_PCR_INFO *tpm_pcr_info) +{ + TPM_PCRSelection_Init(&(tpm_pcr_info->pcrSelection)); + TPM_Digest_Init(tpm_pcr_info->digestAtRelease); + TPM_Digest_Init(tpm_pcr_info->digestAtCreation); + return; +} + +/* TPM_PCRInfo_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_PCRInfo_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRInfo_Load(TPM_PCR_INFO *tpm_pcr_info, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_Load:\n"); + /* load pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Load(&(tpm_pcr_info->pcrSelection), stream, stream_size); + } + /* load the digestAtRelease */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_pcr_info->digestAtRelease, stream, stream_size); + } + /* load the digestAtCreation */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_pcr_info->digestAtCreation, stream, stream_size); + } + return rc; +} + +/* TPM_PCRInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + After use, call TPM_Sbuffer_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO *tpm_pcr_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_Store:\n"); + /* store pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Store(sbuffer, &(tpm_pcr_info->pcrSelection)); + } + /* store digestAtRelease */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_pcr_info->digestAtRelease); + } + /* store digestAtCreation */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_pcr_info->digestAtCreation); + } + return rc; +} + +/* TPM_PCRInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the PCRInfo + sets pointers to NULL2 + calls TPM_PCRInfo_Init to set members back to default values + The PCRInfo itself is not freed + returns 0 or error codes +*/ + +void TPM_PCRInfo_Delete(TPM_PCR_INFO *tpm_pcr_info) +{ + printf(" TPM_PCRInfo_Delete:\n"); + if (tpm_pcr_info != NULL) { + TPM_PCRSelection_Delete(&(tpm_pcr_info->pcrSelection)); + TPM_PCRInfo_Init(tpm_pcr_info); + } + return; +} + +/* TPM_PCRInfo_Create() allocates memory for a TPM_PCR_INFO + +*/ + +TPM_RESULT TPM_PCRInfo_Create(TPM_PCR_INFO **tpm_pcr_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_Create:\n"); + /* This function should never be called when the TPM_PCR_INFO structure has already been loaded. + This indicates an internal error. */ + if (rc == 0) { + if (*tpm_pcr_info != NULL) { + printf("TPM_PCRInfo_Create: Error (fatal), TPM_PCR_INFO already loaded\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)tpm_pcr_info, sizeof(TPM_PCR_INFO)); + } + return rc; +} + +/* TPM_PCRInfo_LoadFromBuffer() sets a TPM_PCR_INFO from a stream specified by a TPM_SIZED_BUFFER. + The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfo_LoadFromBuffer(TPM_PCR_INFO *tpm_pcr_info, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_PCRInfo_LoadFromBuffer:\n"); + if (rc == 0) { + TPM_PCRInfo_Init(tpm_pcr_info); + stream = tpm_sized_buffer->buffer; + stream_size = tpm_sized_buffer->size; + /* deserialize the TPM_SIZED_BUFFER into a TPM_PCR_INFO structure */ + rc = TPM_PCRInfo_Load(tpm_pcr_info, &stream, &stream_size); + } + return rc; +} + +/* TPM_PCRInfo_CreateFromBuffer() allocates the TPM_PCR_INFO structure, typically a cache within + another structure. It then deserializes the TPM_SIZED_BUFFER into the structure. + + If the stream is empty, a NULL is returned. + + The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfo_CreateFromBuffer(TPM_PCR_INFO **tpm_pcr_info, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfo_CreateFromBuffer:\n"); + /* if there is no TPM_PCR_INFO - done */ + if (rc == 0) { + if (tpm_sized_buffer->size == 0) { + done = TRUE; + } + } + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_Create(tpm_pcr_info); + } + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_LoadFromBuffer(*tpm_pcr_info, tpm_sized_buffer); + } + return rc; +} + +/* TPM_PCRInfo_Copy() copies the source to the destination. + + It copies pcrSelection, digestAtRelease, and digestAtCreation. +*/ + +TPM_RESULT TPM_PCRInfo_Copy(TPM_PCR_INFO *dest_tpm_pcr_info, + TPM_PCR_INFO *src_tpm_pcr_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_Copy:\n"); + /* copy TPM_PCR_SELECTION pcrSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info->pcrSelection), + &(src_tpm_pcr_info->pcrSelection)); + } + /* copy TPM_COMPOSITE_HASH's */ + if (rc == 0) { + TPM_Digest_Copy(dest_tpm_pcr_info->digestAtRelease, + src_tpm_pcr_info->digestAtRelease); + TPM_Digest_Copy(dest_tpm_pcr_info->digestAtCreation, + src_tpm_pcr_info->digestAtCreation); + } + return rc; +} + +/* TPM_PCRInfo_CopyInfoLong() copies the source TPM_PCR_INFO_LONG to the destination TPM_PCR_INFO. + + It copies pcrSelection and digestAtRelease. + + It handles digestAtCreation as per the specification. +*/ + +TPM_RESULT TPM_PCRInfo_CopyInfoLong(TPM_PCR_INFO *dest_tpm_pcr_info, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + TPM_BOOL selectMatch; + TPM_BOOL localityMatch; + + printf(" TPM_PCRInfo_Copy:\n"); + /* 9. To set IN from IL */ + /* a. Set IN -> pcrSelection to IL -> releasePCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info->pcrSelection), + &(src_tpm_pcr_info_long->releasePCRSelection)); + } + /* copy TPM_COMPOSITE_HASH's */ + if (rc == 0) { + /* b. Set IN -> digestAtRelease to IL -> digestAtRelease */ + TPM_Digest_Copy(dest_tpm_pcr_info->digestAtRelease, + src_tpm_pcr_info_long->digestAtRelease); + TPM_PCRSelection_Compare(&selectMatch, + &(src_tpm_pcr_info_long->creationPCRSelection), + &(src_tpm_pcr_info_long->releasePCRSelection)); + TPM_PCRLocality_Compare(&localityMatch, + src_tpm_pcr_info_long->localityAtCreation, + src_tpm_pcr_info_long->localityAtRelease); + /* c. If IL -> creationPCRSelection and IL -> localityAtCreation both match IL -> + releasePCRSelection and IL -> localityAtRelease */ + if (selectMatch && localityMatch) { + /* i. Set IN -> digestAtCreation to IL -> digestAtCreation */ + TPM_Digest_Copy(dest_tpm_pcr_info->digestAtCreation, + src_tpm_pcr_info_long->digestAtCreation); + } + /* d. Else */ + else { + /* i. Set IN -> digestAtCreation to NULL */ + TPM_Digest_Init(dest_tpm_pcr_info->digestAtCreation); + } + } + return rc; +} + +/* TPM_PCRInfo_CreateFromInfo() allocates memory for the TPM_PCR_INFO structure. It copies the + source to the destination. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfo_CreateFromInfo(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_PCR_INFO *src_tpm_pcr_info) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfo_CreateFromInfo:\n"); + /* if there is no source, leave the destination NULL */ + if (rc == 0) { + if (src_tpm_pcr_info == NULL) { + done = TRUE; + } + } + /* create the structure */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_Create(dest_tpm_pcr_info); + } + /* copy source to destination */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_Copy(*dest_tpm_pcr_info, src_tpm_pcr_info); + } + return rc; +} + +/* TPM_PCRInfo_CreateFromInfoLong() allocates memory for the TPM_PCR_INFO structure. It copies the + source to the destination. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfo_CreateFromInfoLong(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfo_CreateFromInfoLong:\n"); + /* if there is no source, leave the destination NULL */ + if (rc == 0) { + if (src_tpm_pcr_info_long == NULL) { + done = TRUE; + } + } + /* create the structure */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_Create(dest_tpm_pcr_info); + } + /* copy source to destination */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfo_CopyInfoLong(*dest_tpm_pcr_info, src_tpm_pcr_info_long); + } + return rc; +} + +/* TPM_PCRInfo_CreateFromKey() allocates memory for the TPM_PCR_INFO structure. + + If the input is a TPM_KEY, it copies the TPM_PCR_INFO cache. + + If the input is a TPM_KEY12, it copies the TPM_PCR_INFO_LONG cache. + + If the source is NULL, the destination is NULL. +*/ + + +TPM_RESULT TPM_PCRInfo_CreateFromKey(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_CreateFromKey:\n"); + if (rc == 0) { + if (((TPM_KEY12 *)tpm_key)->tag != TPM_TAG_KEY12) { /* TPM_KEY */ + rc = TPM_PCRInfo_CreateFromInfo(dest_tpm_pcr_info, tpm_key->tpm_pcr_info); + } + else { /* TPM_KEY12 */ + rc = TPM_PCRInfo_CreateFromInfoLong(dest_tpm_pcr_info, tpm_key->tpm_pcr_info_long); + } + } + return rc; +} + +/* TPM_PCRInfo_GenerateDigest() generates a Part 2 5.3.1 PCR composite hash + +*/ + +TPM_RESULT TPM_PCRInfo_GenerateDigest(TPM_DIGEST tpm_digest, /* output digest */ + TPM_PCR_INFO *tpm_pcr_info, /* input */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR array */ +{ + TPM_RESULT rc = 0; + TPM_PCR_SELECTION *tpm_pcr_selection; + + printf(" TPM_PCRInfo_GenerateDigest:\n"); + if (rc == 0) { + if (tpm_pcr_info == NULL) { + printf("TPM_PCRInfo_GenerateDigest: Error (fatal), TPM_PCR_INFO is NULL\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + tpm_pcr_selection = &(tpm_pcr_info->pcrSelection); /* get the TPM_PCR_SELECTION */ + rc = TPM_PCRSelection_GenerateDigest(tpm_digest, /* output digest */ + tpm_pcr_selection, /* input selection map */ + tpm_pcrs); /* points to the TPM PCR array */ + } + return rc; +} + +/* TPM_PCRInfo_CheckDigest() calculates a digestAtRelease based on the TPM_PCR_SELECTION + and compares it to digestAtRelease in the structure. +*/ + +TPM_RESULT TPM_PCRInfo_CheckDigest(TPM_PCR_INFO *tpm_pcr_info, + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR + array */ +{ + TPM_RESULT rc = 0; + TPM_COMPOSITE_HASH tpm_composite_hash; + TPM_BOOL pcrUsage; /* TRUE if PCR's are specified */ + + printf(" TPM_PCRInfo_CheckDigest:\n"); + /* Calculate a TPM_COMPOSITE_HASH of the PCR selected by tpm_pcr_info -> pcrSelection */ + if (rc == 0) { + rc = TPM_PCRInfo_GetPCRUsage(&pcrUsage, tpm_pcr_info, 0); + } + if ((rc == 0) && pcrUsage) { + rc = TPM_PCRSelection_GenerateDigest(tpm_composite_hash, + &(tpm_pcr_info->pcrSelection), + tpm_pcrs); /* array of PCR's */ + } + /* Compare to pcrInfo -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if ((rc == 0) && pcrUsage) { + rc = TPM_Digest_Compare(tpm_composite_hash, + tpm_pcr_info->digestAtRelease); + if (rc != 0) { + printf("TPM_PCRInfo_CheckDigest: Error, wrong digestAtRelease value\n"); + rc = TPM_WRONGPCRVAL; + } + } + return rc; +} + +/* TPM_PCRInfo_SetDigestAtCreation() calculates a digestAtCreation based on the TPM_PCR_SELECTION + already set in the TPM_PCR_INFO structure. +*/ + +TPM_RESULT TPM_PCRInfo_SetDigestAtCreation(TPM_PCR_INFO *tpm_pcr_info, + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR + array */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfo_SetDigestAtCreation:\n"); + if (rc == 0) { + rc = TPM_PCRInfo_GenerateDigest(tpm_pcr_info->digestAtCreation, tpm_pcr_info, tpm_pcrs); + } + return rc; +} + +/* TPM_PCRInfo_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit mask. + + 'start_pcr' indicates the starting byte index into pcrSelect[] +*/ + +TPM_RESULT TPM_PCRInfo_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO *tpm_pcr_info, + size_t start_index) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfo_GetPCRUsage: Start %lu\n", (unsigned long)start_index); + if (rc == 0) { + /* if a loaded key had no pcrInfo, the structure remains NULL */ + if (tpm_pcr_info == NULL) { + *pcrUsage = FALSE; + done = TRUE; + } + } + if ((rc == 0) && !done) { + rc = TPM_PCRSelection_GetPCRUsage(pcrUsage, &(tpm_pcr_info->pcrSelection), start_index); + } + if (rc == 0) { + printf(" TPM_PCRInfo_GetPCRUsage: Result %d\n", *pcrUsage); + } + return rc; +} + +/* + TPM_PCR_INFO_LONG +*/ + +/* TPM_PCRInfoLong_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_PCRInfoLong_Init(TPM_PCR_INFO_LONG *tpm_pcr_info_long) +{ + printf(" TPM_PCRInfoLong_Init:\n"); +/* tpm_pcr_info_long->tag = TPM_TAG_PCR_INFO_LONG; */ + tpm_pcr_info_long->localityAtCreation = TPM_LOC_ZERO; + tpm_pcr_info_long->localityAtRelease = TPM_LOC_ALL; + TPM_PCRSelection_Init(&(tpm_pcr_info_long->creationPCRSelection)); + TPM_PCRSelection_Init(&(tpm_pcr_info_long->releasePCRSelection)); + TPM_Digest_Init(tpm_pcr_info_long->digestAtCreation); + TPM_Digest_Init(tpm_pcr_info_long->digestAtRelease); + return; +} + +/* TPM_PCRInfoLong_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_PCRInfoLong_Init() + After use, call TPM_PCRInfoLong_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRInfoLong_Load(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoLong_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_PCR_INFO_LONG, stream, stream_size); + } + /* load localityAtCreation */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_pcr_info_long->localityAtCreation), stream, stream_size); + } + /* check locality value. The TPM MAY treat a localityAtCreation value of 0 as an error. */ + if (rc == 0) { + rc = TPM_LocalitySelection_CheckLegal(tpm_pcr_info_long->localityAtCreation); + } + /* load localityAtRelease */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_pcr_info_long->localityAtRelease), stream, stream_size); + } + /* check locality value */ + if (rc == 0) { + rc = TPM_LocalitySelection_CheckLegal(tpm_pcr_info_long->localityAtRelease); + } + /* load creationPCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Load(&(tpm_pcr_info_long->creationPCRSelection), stream, stream_size); + } + /* load releasePCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Load(&(tpm_pcr_info_long->releasePCRSelection), stream, stream_size); + } + /* load digestAtCreation */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_pcr_info_long->digestAtCreation, stream, stream_size); + } + /* load digestAtRelease */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_pcr_info_long->digestAtRelease, stream, stream_size); + } + return rc; +} + +/* TPM_PCRInfoLong_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_PCRInfoLong_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO_LONG *tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoLong_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_PCR_INFO_LONG); + } + /* store localityAtCreation */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_pcr_info_long->localityAtCreation), + sizeof(TPM_LOCALITY_SELECTION)); + } + /* store localityAtRelease */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_pcr_info_long->localityAtRelease), + sizeof(TPM_LOCALITY_SELECTION)); + } + /* store creationPCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Store(sbuffer, &(tpm_pcr_info_long->creationPCRSelection)); + } + /* store releasePCRSelection */ + if (rc == 0) { + rc = TPM_PCRSelection_Store(sbuffer, &(tpm_pcr_info_long->releasePCRSelection)); + } + /* store digestAtCreation */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_pcr_info_long->digestAtCreation); + } + /* store digestAtRelease */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_pcr_info_long->digestAtRelease); + } + return rc; +} + +/* TPM_PCRInfoLong_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_PCRInfoLong_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_PCRInfoLong_Delete(TPM_PCR_INFO_LONG *tpm_pcr_info_long) +{ + printf(" TPM_PCRInfoLong_Delete:\n"); + if (tpm_pcr_info_long != NULL) { + TPM_PCRSelection_Delete(&(tpm_pcr_info_long->creationPCRSelection)); + TPM_PCRSelection_Delete(&(tpm_pcr_info_long->releasePCRSelection)); + TPM_PCRInfoLong_Init(tpm_pcr_info_long); + } + return; +} + +/* TPM_PCRInfoLong_Create() allocates memory for a TPM_PCR_INFO_LONG + +*/ + +TPM_RESULT TPM_PCRInfoLong_Create(TPM_PCR_INFO_LONG **tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoLong_Create:\n"); + /* This function should never be called when the TPM_PCR_INFO_LONG structure has already been + loaded. This indicates an internal error. */ + if (rc == 0) { + if (*tpm_pcr_info_long != NULL) { + printf("TPM_PCRInfoLong_Create: Error (fatal), TPM_PCR_INFO_LONG already loaded\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + rc = TPM_Malloc((unsigned char **)tpm_pcr_info_long, sizeof(TPM_PCR_INFO_LONG)); + } + return rc; +} + +/* TPM_PCRInfoLong_LoadFromBuffer() sets a TPM_PCR_INFO_LONG from a stream specified by a + TPM_SIZED_BUFFER. The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfoLong_LoadFromBuffer(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_PCRInfoLong_LoadFromBuffer:\n"); + if (rc == 0) { + TPM_PCRInfoLong_Init(tpm_pcr_info_long); + stream = tpm_sized_buffer->buffer; + stream_size = tpm_sized_buffer->size; + /* deserialize the TPM_SIZED_BUFFER into a TPM_PCR_INFO_LONG structure */ + rc = TPM_PCRInfoLong_Load(tpm_pcr_info_long, &stream, &stream_size); + } + return rc; +} + +/* TPM_PCRInfoLong_CreateFromBuffer() allocates the TPM_PCR_INFO_LONG structure, typically a cache + within another structure. It then deserializes the TPM_SIZED_BUFFER into the structure. + + If the stream is empty, a NULL is returned. + + The TPM_SIZED_BUFFER is not modified. +*/ + +TPM_RESULT TPM_PCRInfoLong_CreateFromBuffer(TPM_PCR_INFO_LONG **tpm_pcr_info_long, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoLong_CreateFromBuffer:\n"); + /* if there is no TPM_PCR_INFO_LONG - done */ + if (rc == 0) { + if (tpm_sized_buffer->size == 0) { + done = TRUE; + } + } + /* allocate memory for the buffer */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoLong_Create(tpm_pcr_info_long); + } + /* deserialize the input stream */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoLong_LoadFromBuffer(*tpm_pcr_info_long, tpm_sized_buffer); + } + return rc; +} + +/* TPM_PCRInfoLong_Copy() copies the source to the destination */ + +TPM_RESULT TPM_PCRInfoLong_Copy(TPM_PCR_INFO_LONG *dest_tpm_pcr_info_long, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoLong_Copy:\n"); + if (rc == 0) { + /* copy the localityAtCreation, localityAtRelease */ + dest_tpm_pcr_info_long->localityAtCreation = src_tpm_pcr_info_long->localityAtCreation; + dest_tpm_pcr_info_long->localityAtRelease = src_tpm_pcr_info_long->localityAtRelease; + /* copy TPM_PCR_SELECTION creationPCRSelection */ + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info_long->creationPCRSelection), + &(src_tpm_pcr_info_long->creationPCRSelection)); + } + if (rc == 0) { + /* copy TPM_PCR_SELECTION releasePCRSelection*/ + rc = TPM_PCRSelection_Copy(&(dest_tpm_pcr_info_long->releasePCRSelection), + &(src_tpm_pcr_info_long->releasePCRSelection)); + } + /* copy TPM_COMPOSITE_HASH's */ + if (rc == 0) { + TPM_Digest_Copy(dest_tpm_pcr_info_long->digestAtRelease, + src_tpm_pcr_info_long->digestAtRelease); + TPM_Digest_Copy(dest_tpm_pcr_info_long->digestAtCreation, + src_tpm_pcr_info_long->digestAtCreation); + } + return rc; +} + +/* TPM_PCRInfoLong_CreateFromInfoLong() allocates memory for the TPM_PCR_INFO_LONG structure. It + copies the source tag, localityAtCreation, localityAtRelease, creationPCRSelection, + releasePCRSelection digestAtCreation, and digestAtRelease. + + If the source is NULL, the destination is NULL. +*/ + +TPM_RESULT TPM_PCRInfoLong_CreateFromInfoLong(TPM_PCR_INFO_LONG **dest_tpm_pcr_info_long, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoLong_CreateFromInfoLong:\n"); + if (rc == 0) { + /* if there is no source, leave the destination NULL */ + if (src_tpm_pcr_info_long == NULL) { + done = TRUE; + } + } + /* create the structure */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoLong_Create(dest_tpm_pcr_info_long); + } + /* copy source to destination */ + if ((rc == 0) && !done) { + rc = TPM_PCRInfoLong_Copy(*dest_tpm_pcr_info_long, src_tpm_pcr_info_long); + } + return rc; +} + +/* TPM_PCRInfoLong_GenerateDigest() generates a Part 2 5.3.1 PCR composite hash + +*/ + +TPM_RESULT TPM_PCRInfoLong_GenerateDigest(TPM_DIGEST tpm_digest, /* output digest */ + TPM_PCR_INFO_LONG *tpm_pcr_info_long, /* input */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR array */ +{ + TPM_RESULT rc = 0; + TPM_PCR_SELECTION *tpm_pcr_selection; + + printf(" TPM_PCRInfoLong_GenerateDigest:\n"); + if (rc == 0) { + if (tpm_pcr_info_long == NULL) { + printf("TPM_PCRInfoLong_GenerateDigest: Error (fatal), TPM_PCR_INFO_LONG is NULL\n"); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + tpm_pcr_selection = &(tpm_pcr_info_long->creationPCRSelection); /* get TPM_PCR_SELECTION */ + rc = TPM_PCRSelection_GenerateDigest(tpm_digest, /* output digest */ + tpm_pcr_selection, /* input selection map */ + tpm_pcrs); /* points to the TPM PCR array */ + } + return rc; +} + +/* TPM_PCRInfoLong_CheckDigest() calculates a digestAtRelease based on the TPM_PCR_SELECTION + and compares it to digestAtRelease in the structure. +*/ + +TPM_RESULT TPM_PCRInfoLong_CheckDigest(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + TPM_PCRVALUE *tpm_pcrs, /* points to the TPM PCR array */ + TPM_MODIFIER_INDICATOR localityModifier) +{ + TPM_RESULT rc = 0; + TPM_COMPOSITE_HASH tpm_composite_hash; + TPM_BOOL pcrUsage; /* TRUE if PCR's are specified */ + + printf(" TPM_PCRInfoLong_CheckDigest:\n"); + /* returns FALSE if tpm_pcr_info_long is NULL or selection bitmap is zero */ + if (rc == 0) { + rc = TPM_PCRInfoLong_GetPCRUsage(&pcrUsage, tpm_pcr_info_long, 0); + } + /* Calculate a TPM_COMPOSITE_HASH of the PCR selected by tpm_pcr_info_long -> + releasePCRSelection */ + if ((rc == 0) && pcrUsage) { + rc = TPM_PCRSelection_GenerateDigest(tpm_composite_hash, + &(tpm_pcr_info_long->releasePCRSelection), + tpm_pcrs); /* array of PCR's */ + } + /* Compare to tpm_pcr_info_long -> digestAtRelease on mismatch return TPM_WRONGPCRVAL */ + if ((rc == 0) && pcrUsage) { + rc = TPM_Digest_Compare(tpm_composite_hash, + tpm_pcr_info_long->digestAtRelease); + if (rc != 0) { + printf("TPM_PCRInfoLong_CheckDigest: Error, wrong digestAtRelease value\n"); + rc = TPM_WRONGPCRVAL; + } + } + /* If localityAtRelease is NOT 0x1f */ + if ((rc == 0) && (tpm_pcr_info_long != NULL)) { + if (tpm_pcr_info_long->localityAtRelease != TPM_LOC_ALL) { + /* Validate that TPM_STANY_FLAGS -> localityModifier is matched by tpm_pcr_info_short -> + localityAtRelease on mismatch return TPM_BAD_LOCALITY */ + rc = TPM_Locality_Check(tpm_pcr_info_long->localityAtRelease, localityModifier); + } + } + return rc; +} + +/* TPM_PCRInfoLong_SetDigestAtCreation() calculates a digestAtCreation based on the + TPM_PCR_SELECTION creationPCRSelection already set in the TPM_PCR_INFO_LONG structure. +*/ + +TPM_RESULT TPM_PCRInfoLong_SetDigestAtCreation(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR + array */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRInfoLong_SetDigestAtCreation:\n"); + if (rc == 0) { + rc = TPM_PCRInfoLong_GenerateDigest(tpm_pcr_info_long->digestAtCreation, + tpm_pcr_info_long, + tpm_pcrs); + } + return rc; +} + +/* TPM_PCRInfoLong_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit + mask. Returns FALSE if the TPM_PCR_INFO_LONG is NULL. + + 'start_pcr' indicates the starting byte index into pcrSelect[] +*/ + +TPM_RESULT TPM_PCRInfoLong_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO_LONG *tpm_pcr_info_long, + size_t start_index) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + + printf(" TPM_PCRInfoLong_GetPCRUsage: Start %lu\n", (unsigned long)start_index);; + if (rc == 0) { + /* if a loaded key had no pcrInfo, the structure remains NULL */ + if (tpm_pcr_info_long == NULL) { + *pcrUsage = FALSE; + done = TRUE; + } + } + if ((rc == 0) && !done) { + rc = TPM_PCRSelection_GetPCRUsage(pcrUsage, + &(tpm_pcr_info_long->releasePCRSelection), start_index); + } + if (rc == 0) { + printf(" TPM_PCRInfoLong_GetPCRUsage: Result %d\n", *pcrUsage); + } + return rc; +} + + +/* + TPM_PCR_SELECTION +*/ + +void TPM_PCRSelection_Init(TPM_PCR_SELECTION *tpm_pcr_selection) +{ + size_t i; + + printf(" TPM_PCRSelection_Init:\n"); + tpm_pcr_selection->sizeOfSelect = TPM_NUM_PCR/CHAR_BIT; + for (i = 0 ; i < (TPM_NUM_PCR/CHAR_BIT) ; i++) { + tpm_pcr_selection->pcrSelect[i] = 0; + } + return; +} + +/* TPM_PCRSelection_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_PCRSelection_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRSelection_Load(TPM_PCR_SELECTION *tpm_pcr_selection, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PCRSelection_Load:\n"); + /* load sizeOfSelect */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_pcr_selection->sizeOfSelect), stream, stream_size); + } + /* test sizeOfSelect value */ + if (rc == 0) { + rc = TPM_PCRSelection_CheckRange(tpm_pcr_selection); + } + /* load pcrSelect map */ + for (i = 0 ; (rc == 0) && (i < tpm_pcr_selection->sizeOfSelect) ; i++) { + rc = TPM_Load8(&(tpm_pcr_selection->pcrSelect[i]), stream, stream_size); + } + /* if there was insufficient input, zero the rest of the map */ + for ( ; (rc == 0) && (i < (TPM_NUM_PCR/CHAR_BIT)) ; i++) { + rc = tpm_pcr_selection->pcrSelect[i] = 0; + } + return rc; +} + +/* TPM_PCRSelection_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + After use, call TPM_Sbuffer_Delete() to free memory +*/ + +TPM_RESULT TPM_PCRSelection_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_SELECTION *tpm_pcr_selection) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PCRSelection_Store:\n"); + /* NOTE: Cannot use TPM_SizedBuffer_Store since the first parameter is a uint16_t */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_pcr_selection->sizeOfSelect); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + tpm_pcr_selection->pcrSelect, tpm_pcr_selection->sizeOfSelect); + } + return rc; +} + + +/* TPM_PCRSelection_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the PCRSelection + sets pointers to NULL + calls TPM_PCRSelection_Init to set members back to default values + The PCRSelection itself is not freed + returns 0 or error codes +*/ + +void TPM_PCRSelection_Delete(TPM_PCR_SELECTION *tpm_pcr_selection) +{ + printf(" TPM_PCRSelection_Delete:\n"); + if (tpm_pcr_selection != NULL) { + TPM_PCRSelection_Init(tpm_pcr_selection); + } + return; +} + +/* TPM_PCRSelection_Copy() copies the source to the destination + + It returns an error if the source -> sizeOfSelect is too large. If the source is smaller than + the internally defined, fixed size of the destination, the remainder of the destination is filled + with 0's. +*/ + +TPM_RESULT TPM_PCRSelection_Copy(TPM_PCR_SELECTION *destination, TPM_PCR_SELECTION *source) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PCRSelection_Copy:\n"); + if (rc == 0) { + rc = TPM_PCRSelection_CheckRange(source); + } + if (rc == 0) { + /* copy sizeOfSelect member */ + destination->sizeOfSelect = source->sizeOfSelect; + /* copy pcrSelect map up to the size of the source */ + for (i = 0 ; i < source->sizeOfSelect ; i++) { + destination->pcrSelect[i] = source->pcrSelect[i]; + } + /* if the input wasn't sufficient, zero the rest of the map */ + for ( ; i < (TPM_NUM_PCR/CHAR_BIT) ; i++) { + destination->pcrSelect[i] = 0; + } + } + return rc; +} + +/* TPM_PCRSelection_GenerateDigest() generates a digest based on the TPM_PCR_SELECTION and the + current TPM PCR values. + + It internally generates a TPM_PCR_COMPOSITE according to Part 2 5.4.1. To return this structure + as well, use TPM_PCRSelection_GenerateDigest2(). +*/ + +TPM_RESULT TPM_PCRSelection_GenerateDigest(TPM_DIGEST tpm_digest, /* output digest */ + TPM_PCR_SELECTION *tpm_pcr_selection, /* input selection + map */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR array */ +{ + TPM_RESULT rc = 0; + TPM_PCR_COMPOSITE tpm_pcr_composite; /* structure to be hashed */ + + printf(" TPM_PCRSelection_GenerateDigest:\n"); + TPM_PCRComposite_Init(&tpm_pcr_composite); /* freed @1 */ + rc = TPM_PCRSelection_GenerateDigest2(tpm_digest, + &tpm_pcr_composite, + tpm_pcr_selection, + tpm_pcrs); + TPM_PCRComposite_Delete(&tpm_pcr_composite); /* @1 */ + return rc; +} + +/* TPM_PCRSelection_GenerateDigest2() generates a digest based on the TPM_PCR_SELECTION and the + current TPM PCR values. + + It first generates a TPM_PCR_COMPOSITE according to Part 2 5.4.1. That structure is also + returned. + + TPM_PCR_COMPOSITE should be initialized and deleted by the caller. To generate and delete the + structure internally, use TPM_PCRSelection_GenerateDigest(). +*/ + +TPM_RESULT TPM_PCRSelection_GenerateDigest2(TPM_DIGEST tpm_digest, /* output digest */ + TPM_PCR_COMPOSITE *tpm_pcr_composite, /* output + structure + */ + TPM_PCR_SELECTION *tpm_pcr_selection, /* input selection + map */ + TPM_PCRVALUE *tpm_pcrs) /* points to the TPM PCR + array */ +{ + TPM_RESULT rc = 0; + TPM_BOOL pcrUsage; + + printf(" TPM_PCRSelection_GenerateDigest2:\n"); + /* assemble the TPM_PCR_COMPOSITE structure */ + if (rc == 0) { + rc = TPM_PCRComposite_Set(tpm_pcr_composite, tpm_pcr_selection, tpm_pcrs); + } + if (rc == 0) { + rc = TPM_PCRSelection_GetPCRUsage(&pcrUsage, tpm_pcr_selection, 0); + } + if (rc == 0) { + printf(" TPM_PCRSelection_GenerateDigest2: pcrUsage %02x\n", pcrUsage); + if (pcrUsage) { + /* serialize and hash TPM_PCR_COMPOSITE */ + if (rc == 0) { + rc = TPM_SHA1_GenerateStructure(tpm_digest, tpm_pcr_composite, + (TPM_STORE_FUNCTION_T)TPM_PCRComposite_Store); + } + } + /* 4. If TPM_PCR_SELECTION.pcrSelect is all 0's */ + /* a. a.For digestAtCreation, the TPM MUST set TPM_COMPOSITE_HASH to be all 0's. */ + else { + TPM_Digest_Init(tpm_digest); + } + } + return rc; +} + +/* TPM_PCRSelection_GetPCRUsage() returns 'pcrUsage' TRUE if any bit is set in the pcrSelect bit + mask. + + 'start_pcr' indicates the starting byte index into pcrSelect[]. +*/ + +TPM_RESULT TPM_PCRSelection_GetPCRUsage(TPM_BOOL *pcrUsage, + const TPM_PCR_SELECTION *tpm_pcr_selection, + size_t start_index) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PCRSelection_GetPCRUsage: Start %lu\n", (unsigned long)start_index); + if (rc == 0) { + rc = TPM_PCRSelection_CheckRange(tpm_pcr_selection); + } + if (rc == 0) { + *pcrUsage = FALSE; + /* If sizeOfSelect is 0 or start_index is past the end, this loop won't be entered and FALSE + will be returned */ + for (i = start_index ; i < tpm_pcr_selection->sizeOfSelect ; i++) { + if (tpm_pcr_selection->pcrSelect[i] != 0) { /* is any bit set in the mask */ + *pcrUsage = TRUE; + break; + } + } + } + return rc; +} + +/* TPM_PCRSelection_CheckRange() checks the sizeOfSelect index + +*/ + +TPM_RESULT TPM_PCRSelection_CheckRange(const TPM_PCR_SELECTION *tpm_pcr_selection) +{ + TPM_RESULT rc = 0; + + if (tpm_pcr_selection->sizeOfSelect > (TPM_NUM_PCR/CHAR_BIT)) { + printf("TPM_PCRSelection_CheckRange: Error, sizeOfSelect %u must be 0 - %u\n", + tpm_pcr_selection->sizeOfSelect, TPM_NUM_PCR/CHAR_BIT); + rc = TPM_INVALID_PCR_INFO; + } + return rc; +} + +/* TPM_PCRSelection_Compare() compares the TPM_PCR_SELECTION's for equality + +*/ + +void TPM_PCRSelection_Compare(TPM_BOOL *match, + TPM_PCR_SELECTION *tpm_pcr_selection1, + TPM_PCR_SELECTION *tpm_pcr_selection2) +{ + size_t i; + *match = TRUE; + + if (tpm_pcr_selection1->sizeOfSelect != tpm_pcr_selection2->sizeOfSelect) { + *match = FALSE; + } + for (i = 0 ; *match && (i < tpm_pcr_selection1->sizeOfSelect) ; i++) { + if (tpm_pcr_selection1->pcrSelect[i] != tpm_pcr_selection2->pcrSelect[i]) { + *match = FALSE; + } + } + return; +} + +/* TPM_PCRSelection_LessThan() compares the new selection to the old selection. It returns lessThan + TRUE is the new selection does not select a PCR that was selected by the old selection. +*/ + +void TPM_PCRSelection_LessThan(TPM_BOOL *lessThan, + TPM_PCR_SELECTION *tpm_pcr_selection_new, + TPM_PCR_SELECTION *tpm_pcr_selection_old) +{ + size_t i; + *lessThan = TRUE; + + if (tpm_pcr_selection_new->sizeOfSelect != tpm_pcr_selection_old->sizeOfSelect) { + *lessThan = FALSE; + } + for (i = 0 ; *lessThan && (i < tpm_pcr_selection_new->sizeOfSelect) ; i++) { + /* if there's a 0 in the new selection and a 1 on the old selection */ + if (~(tpm_pcr_selection_new->pcrSelect[i]) & tpm_pcr_selection_old->pcrSelect[i]) { + *lessThan = FALSE; + } + } + return; +} + + +/* + TPM_QUOTE_INFO +*/ + +/* TPM_QuoteInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_QuoteInfo_Init(TPM_QUOTE_INFO *tpm_quote_info) +{ + printf(" TPM_QuoteInfo_Init:\n"); + TPM_StructVer_Init(&(tpm_quote_info->version)); + memcpy(&(tpm_quote_info->fixed), "QUOT", 4); + TPM_Digest_Init(tpm_quote_info->digestValue); + TPM_Nonce_Init(tpm_quote_info->externalData); + return; +} + +/* TPM_QuoteInfo_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_QuoteInfo_Init() + After use, call TPM_QuoteInfo_Delete() to free memory + + NOTE: Never called. +*/ + +TPM_RESULT TPM_QuoteInfo_Load(TPM_QUOTE_INFO *tpm_quote_info, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_QuoteInfo_Load:\n"); + /* load version */ + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_quote_info->version), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_quote_info->version)); + } + /* load fixed */ + if (rc == 0) { + rc = TPM_Loadn(tpm_quote_info->fixed, 4, stream, stream_size); + } + /* load digestValue */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_quote_info->digestValue, stream, stream_size); + } + /* load externalData */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_quote_info->externalData, stream, stream_size); + } + return rc; +} + +/* TPM_QuoteInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_QuoteInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_QUOTE_INFO *tpm_quote_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_QuoteInfo_Store:\n"); + /* store version */ + if (rc == 0) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_quote_info->version)); + } + /* store fixed */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_quote_info->fixed, 4); + } + /* store digestValue */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_quote_info->digestValue); + } + /* store externalData */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_quote_info->externalData); + } + return rc; +} + +/* TPM_QuoteInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_QuoteInfo_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_QuoteInfo_Delete(TPM_QUOTE_INFO *tpm_quote_info) +{ + printf(" TPM_QuoteInfo_Delete:\n"); + if (tpm_quote_info != NULL) { + TPM_QuoteInfo_Init(tpm_quote_info); + } + return; +} + +/* + TPM_QUOTE_INFO2 +*/ + +/* TPM_QuoteInfo2_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_QuoteInfo2_Init(TPM_QUOTE_INFO2 *tpm_quote_info2) +{ + printf(" TPM_QuoteInfo2_Init:\n"); + memcpy(tpm_quote_info2->fixed, "QUT2", 4); + TPM_Nonce_Init(tpm_quote_info2->externalData); + TPM_PCRInfoShort_Init(&(tpm_quote_info2->infoShort)); + return; +} + +/* TPM_QuoteInfo2_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_QuoteInfo2_Init() + After use, call TPM_QuoteInfo2_Delete() to free memory +*/ + +TPM_RESULT TPM_QuoteInfo2_Load(TPM_QUOTE_INFO2 *tpm_quote_info2, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_QuoteInfo2_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_QUOTE_INFO2, stream, stream_size); + } + /* load fixed */ + if (rc == 0) { + rc = TPM_Loadn(tpm_quote_info2->fixed, 4, stream, stream_size); + } + /* load externalData */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_quote_info2->externalData, stream, stream_size); + } + /* load infoShort */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Load(&(tpm_quote_info2->infoShort), stream, stream_size, FALSE); + } + return rc; +} + +/* TPM_QuoteInfo2_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_QuoteInfo2_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_QUOTE_INFO2 *tpm_quote_info2) +{ + TPM_RESULT rc = 0; + + printf(" TPM_QuoteInfo2_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_QUOTE_INFO2); + } + /* store fixed */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_quote_info2->fixed, 4); + } + /* store externalData */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_quote_info2->externalData); + } + /* store infoShort */ + if (rc == 0) { + rc = TPM_PCRInfoShort_Store(sbuffer, &(tpm_quote_info2->infoShort), FALSE); + } + return rc; +} + +/* TPM_QuoteInfo2_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_QuoteInfo2_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_QuoteInfo2_Delete(TPM_QUOTE_INFO2 *tpm_quote_info2) +{ + printf(" TPM_QuoteInfo2_Delete:\n"); + if (tpm_quote_info2 != NULL) { + TPM_PCRInfoShort_Delete(&(tpm_quote_info2->infoShort)); + TPM_QuoteInfo2_Init(tpm_quote_info2); + } + return; +} + +/* + Command Processing Functions +*/ + + +/* 16.2 TPM_PCRRead rev 109 + + The TPM_PCRRead operation provides non-cryptographic reporting of the contents of a named PCR. +*/ + +TPM_RESULT TPM_Process_PcrRead(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_PCRINDEX pcrIndex; /* Index of the PCR to be read */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PCRVALUE outDigest; + + printf("TPM_Process_PcrRead: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pcrIndex parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&pcrIndex, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PcrRead: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1.Validate that pcrIndex represents a legal PCR number. On error, return TPM_BADINDEX. */ + /* 2. Set outDigest to TPM_STCLEAR_DATA -> PCR[pcrIndex] */ + /* NOTE Done by TPM_PCR_Load() */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PcrRead: pcrIndex %u\n", pcrIndex); + returnCode = TPM_PCR_Load(outDigest, + tpm_state->tpm_stclear_data.PCRS, + pcrIndex); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_PcrRead: PCR value", outDigest); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PcrRead: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append outDigest */ + returnCode = TPM_Digest_Store(response, outDigest); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 16.3 TPM_Quote rev 101 + + 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). + + The term "ExternalData" is used because an important use of TPM_Quote is to provide a digital + signature on arbitrary data, where the signature includes the PCR values of the platform at time + of signing. Hence the "ExternalData" is not just for anti-replay purposes, although it is (of + course) used for that purpose in an integrity challenge. +*/ + +TPM_RESULT TPM_Process_Quote(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can sign + the PCR values. */ + TPM_NONCE externalData; /* 160 bits of externally supplied data (typically a nonce + provided by a server to prevent replay-attacks) */ + TPM_PCR_SELECTION targetPCR; /* The indices of the PCRs that are to be reported. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA privAuth; /* The authorization digest for inputs and keyHandle. HMAC + key: key -> usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_QUOTE_INFO q1QuoteInfo; + TPM_DIGEST q1_digest; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PCR_COMPOSITE pcrData; /* A structure containing the same indices as + targetPCR, plus the corresponding current PCR + values. */ + TPM_SIZED_BUFFER sig; /* The signed data blob. */ + + printf("TPM_Process_Quote: Ordinal Entry\n"); + TPM_PCRSelection_Init(&targetPCR); /* freed @1 */ + TPM_PCRComposite_Init(&pcrData); /* freed @2 */ + TPM_QuoteInfo_Init(&q1QuoteInfo); /* freed @3 */ + TPM_SizedBuffer_Init(&sig); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get externalData parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Quote: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(externalData, &command, ¶mSize); + } + /* get targetPCR parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_Load(&targetPCR, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_Process_Quote: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Quote: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_Quote: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM MUST validate the authorization to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or + TPM_SS_RSASSAPKCS1v15_INFO,, if not return TPM_INAPPROPRIATE_SIG. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_Quote: Error, invalid sigKey sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = 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 (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + ((sigKey->keyUsage) != TPM_KEY_IDENTITY) && + ((sigKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_Quote: Error, keyUsage %04hx is invalid\n", sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Validate targetPCR */ + /* a. targetPCR is a valid TPM_PCR_SELECTION structure */ + /* b. On errors return TPM_INVALID_PCR_INFO */ + /* NOTE: done during TPM_PCRSelection_Load() */ + /* 5. Create H1 a SHA-1 hash of a TPM_PCR_COMPOSITE using the PCRs indicated by targetPCR -> + pcrSelect */ + /* NOTE TPM_PCRSelection_GenerateDigest2() generates the TPM_PCR_COMPOSITE as well. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_GenerateDigest2(q1QuoteInfo.digestValue, + &pcrData, /* TPM_PCR_COMPOSITE */ + &targetPCR, + tpm_state->tpm_stclear_data.PCRS); + } + /* 6. Create Q1 a TPM_QUOTE_INFO structure */ + /* a. Set Q1 -> version to 1.1.0.0 */ + /* b. Set Q1 -> fixed to "QUOT" */ + /* NOTE: done at TPM_QuoteInfo_Init() */ + /* c. Set Q1 -> digestValue to H1 */ + /* NOTE: Generated directly in Q1 */ + /* d. Set Q1 -> externalData to externalData */ + if (returnCode == TPM_SUCCESS) { + TPM_Nonce_Copy(q1QuoteInfo.externalData, externalData); + } + /* 7. Sign SHA-1 hash of Q1 using keyHandle as the signature key */ + /* digest Q1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(q1_digest, &q1QuoteInfo, + (TPM_STORE_FUNCTION_T)TPM_QuoteInfo_Store); + } + /* sign the Q1 digest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + q1_digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* signing key and parameters */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Quote: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the pcrData */ + returnCode = TPM_PCRComposite_Store(response, &pcrData); + } + /* 8. Return the signature in sig */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_PCRSelection_Delete(&targetPCR); /* @1 */ + TPM_PCRComposite_Delete(&pcrData); /* @2 */ + TPM_QuoteInfo_Delete(&q1QuoteInfo); /* @3 */ + TPM_SizedBuffer_Delete(&sig); /* @4 */ + return rcf; +} + + +/* 16.5 TPM_Quote2 rev 96 + + 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). + + The term "ExternalData" is used because an important use of TPM_Quote is to provide a digital + signature on arbitrary data, where the signature includes the PCR values of the platform at time + of signing. Hence the "ExternalData" is not just for anti-replay purposes, although it is (of + course) used for that purpose in an integrity challenge. + + Quote2 differs from quote in that Quote2 uses TPM_PCR_INFO_SHORT to hold information relative to + the PCR registers. INFO_SHORT includes locality information to provide the requester a more + complete view of the current platform configuration. +*/ + +TPM_RESULT TPM_Process_Quote2(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can sign + the PCR values. */ + TPM_NONCE externalData; /* 160 bits of externally supplied data (typically a nonce + provided by a server to prevent replay-attacks) */ + TPM_PCR_SELECTION targetPCR; /* The indices of the PCRs that are to be reported. */ + TPM_BOOL addVersion; /* When TRUE add TPM_CAP_VERSION_INFO to the output */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA privAuth; /* The authorization session digest for inputs and + keyHandle. HMAC key: key -> usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_COMPOSITE_HASH h1CompositeHash; + TPM_QUOTE_INFO2 q1; + TPM_PCR_INFO_SHORT *s1 = NULL; + TPM_STORE_BUFFER q1_sbuffer; + TPM_STORE_BUFFER versionInfo_sbuffer; + const unsigned char *versionInfo_buffer; + TPM_DIGEST q1_digest; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + uint32_t versionInfoSize; /* Size of the version info */ + TPM_CAP_VERSION_INFO versionInfo; /* The version info */ + TPM_SIZED_BUFFER sig; /* The signed data blob. */ + + printf("TPM_Process_Quote2: Ordinal Entry\n"); + TPM_PCRSelection_Init(&targetPCR); /* freed @1 */ + TPM_CapVersionInfo_Set(&versionInfo, &(tpm_state->tpm_permanent_data)); /* freed @2 */ + TPM_SizedBuffer_Init(&sig); /* freed @3 */ + TPM_QuoteInfo2_Init(&q1); /* freed @4 */ + TPM_Sbuffer_Init(&q1_sbuffer); /* freed @5 */ + TPM_Sbuffer_Init(&versionInfo_sbuffer); /* freed @6 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get externalData */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Quote2: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(externalData, &command, ¶mSize); + } + /* get targetPCR parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_Load(&targetPCR, &command, ¶mSize); + } + /* get addVersion parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadBool(&addVersion, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Quote2: addVersion %02x\n", addVersion); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_Process_Quote2: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Quote2: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_Quote2: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM MUST validate the AuthData to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1, if not return + TPM_INAPPROPRIATE_SIG. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_Quote2: Error, inappropriate signature scheme %04x\n", + sigKey->algorithmParms.sigScheme); + returnCode = 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 (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + ((sigKey->keyUsage) != TPM_KEY_IDENTITY) && + ((sigKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_Quote2: Error, keyUsage %04hx is invalid\n", sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Validate targetPCR is a valid TPM_PCR_SELECTION structure, on errors return + TPM_INVALID_PCR_INFO */ + /* NOTE: done during TPM_PCRSelection_Load() */ + /* 5. Create H1 a SHA-1 hash of a TPM_PCR_COMPOSITE using the PCRs indicated by targetPCR -> + pcrSelect */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_GenerateDigest(h1CompositeHash, + &targetPCR, + tpm_state->tpm_stclear_data.PCRS); + } + if (returnCode == TPM_SUCCESS) { + /* 6. Create S1 a TPM_PCR_INFO_SHORT */ + s1 = &(q1.infoShort); + /* a. Set S1->pcrSelection to pcrSelect */ + returnCode = TPM_PCRSelection_Copy(&(s1->pcrSelection), &targetPCR); + } + /* b. Set S1->localityAtRelease to TPM_STANY_DATA -> localityModifier */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Locality_Set(&(s1->localityAtRelease), + tpm_state->tpm_stany_flags.localityModifier); + } + /* c. Set S1->digestAtRelease to H1 */ + if (returnCode == TPM_SUCCESS) { + TPM_Digest_Copy(s1->digestAtRelease, h1CompositeHash); + /* 7. Create Q1 a TPM_QUOTE_INFO2 structure */ + /* a. Set Q1 -> fixed to "QUT2" */ + /* NOTE: done at TPM_QuoteInfo2_Init() */ + /* b. Set Q1 -> infoShort to S1 */ + /* NOTE: created S1 in place */ + /* c. Set Q1 -> externalData to externalData */ + TPM_Nonce_Copy(q1.externalData, externalData); + /* serialize q1 */ + returnCode = TPM_QuoteInfo2_Store(&q1_sbuffer, &q1); + } + if (returnCode == TPM_SUCCESS) { + /* 8. If addVersion is TRUE */ + if (addVersion) { + if (returnCode == TPM_SUCCESS) { + /* a. Concatenate to Q1 a TPM_CAP_VERSION_INFO structure */ + /* b. Set the output parameters for versionInfo */ + /* serialize versionInfo. The result cannot be added directly to q1_sbuffer because + it is needed as an outgoing parameter */ + /* NOTE: Created at TPM_CapVersionInfo_Set() */ + returnCode = TPM_CapVersionInfo_Store(&versionInfo_sbuffer, &versionInfo); + } + if (returnCode == TPM_SUCCESS) { + /* get the serialized results */ + TPM_Sbuffer_Get(&versionInfo_sbuffer, &versionInfo_buffer, &versionInfoSize); + /* concatenate TPM_CAP_VERSION_INFO versionInfo to TPM_QUOTE_INFO2 q1 buffer */ + returnCode = TPM_Sbuffer_Append(&q1_sbuffer, versionInfo_buffer, versionInfoSize); + } + } + /* 9. Else */ + else { + /* a. Set versionInfoSize to 0 */ + versionInfoSize = 0; + /* b. Return no bytes in versionInfo */ + /* NOTE Done at response, (&& addVersion) */ + } + } + /* 10. Sign a SHA-1 hash of Q1 using keyHandle as the signature key */ + /* hash q1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1Sbuffer(q1_digest, &q1_sbuffer); + } + /* sign the Q1 digest */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + q1_digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* signing key and parameters */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Quote2: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the TPM_PCR_INFO_SHORT pcrData */ + returnCode = TPM_PCRInfoShort_Store(response, s1, FALSE); + } + /* An email clarification said that, if addVersion is FALSE, a versionInfoSize is 0 is + returned. This indicates the missing versionInfo. */ + /* return the versionInfoSize */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, versionInfoSize); + } + /* return the versionInfo */ + if ((returnCode == TPM_SUCCESS) && addVersion) { + returnCode = TPM_Sbuffer_Append(response, versionInfo_buffer, versionInfoSize); + } + /* 11. Return the signature in sig */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_PCRSelection_Delete(&targetPCR); /* @1 */ + TPM_CapVersionInfo_Delete(&versionInfo); /* @2 */ + TPM_SizedBuffer_Delete(&sig); /* @3 */ + TPM_QuoteInfo2_Delete(&q1); /* @4 */ + TPM_Sbuffer_Delete(&q1_sbuffer); /* @5 */ + TPM_Sbuffer_Delete(&versionInfo_sbuffer); /* @6 */ + return rcf; +} + +/* TPM_ExtendCommon() rev 109 + + Contains code common to TPM_Process_Extend() and TPM_Process_SHA1CompleteExtend(). + + Add a measurement value to a PCR +*/ + +TPM_RESULT TPM_ExtendCommon(TPM_PCRVALUE outDigest, /* The PCR value after execution of + the command */ + tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, /* command ordinal */ + TPM_PCRINDEX pcrNum, /* Index of the PCR to be modified */ + TPM_DIGEST inDigest) /* the event to be recorded */ +{ + TPM_RESULT rc = 0; + TPM_PCRVALUE currentPcrValue; + TPM_DIGEST h1; + + printf("TPM_ExtendCommon: pcrNum %u\n", pcrNum); + /* 1. Validate that pcrNum represents a legal PCR number. On error, return TPM_BADINDEX. */ + if (rc == 0) { + rc = TPM_PCR_CheckRange(pcrNum); + } + if (rc == 0) { + /* 2. Map V1 to TPM_STANY_FLAGS */ + /* 3. Map L1 to V1 -> localityModifier */ + /* 4. If the current locality, held in L1, is not selected in TPM_PERMANENT_DATA -> + pcrAttrib[PCRIndex].pcrExtendLocal, return TPM_BAD_LOCALITY */ + rc = TPM_Locality_Check(tpm_state->tpm_permanent_data.pcrAttrib[pcrNum].pcrExtendLocal, + tpm_state->tpm_stany_flags.localityModifier); + } + /* get the current PCR digest value */ + if (rc == 0) { + rc = TPM_PCR_Load(currentPcrValue, + tpm_state->tpm_stclear_data.PCRS, + pcrNum); + } +#if defined TPM_PCCLIENT + /* From the PC Client TIS spec + + 1. When the locality 4 PCR is at its reset value of 0, the entry for the locality 4 PCR in + section 7.2 SHALL be interpreted as if the column labeled pcrExtendLocal for locality + 4,3,2,1,0 contains the bit field definitions: 1,0,0,0,0. + + 2. Once the locality 4 PCR is no longer at its reset value of 0, table 4 in section 7.2 + applies as written. + */ + if (rc == 0) { + TPM_BOOL isZero; + if ((pcrNum == 17) && /* PCR 17 is the Locality 4 PCR */ + (tpm_state->tpm_stany_flags.localityModifier != 4)) { + /* if not locality 4, must not be at the reset value */ + TPM_Digest_IsZero(&isZero, currentPcrValue); + if (isZero) { + printf("TPM_ExtendCommon: Error, " + "pcrNum %u and locality %u and PCR at reset value\n", + pcrNum, tpm_state->tpm_stany_flags.localityModifier); + rc = TPM_BAD_LOCALITY; + } + } + } +#endif + /* 5. Create c1 by concatenating (PCRindex TPM_PCRVALUE || inDigest). This takes the current PCR + value and concatenates the inDigest parameter. */ + /* NOTE: Not required, SHA1 uses varargs */ + /* 6. Create h1 by performing a SHA-1 digest of c1. */ + if (rc == 0) { + TPM_PrintFour("TPM_ExtendCommon: Current PCR ", currentPcrValue); + /* TPM_PrintFour("TPM_ExtendCommon: Current PCR ", + tpm_state->tpm_stclear_data.PCR[pcrNum]); */ + TPM_PrintFour("TPM_ExtendCommon: Input Digest", inDigest); + rc = TPM_SHA1(h1, + TPM_DIGEST_SIZE, currentPcrValue, + TPM_DIGEST_SIZE, inDigest, + 0, NULL); + } + if (rc == 0) { + TPM_PrintFour("TPM_ExtendCommon: New PCR", h1); + /* 7. Store h1 as the new TPM_PCRVALUE of PCRindex */ + rc = TPM_PCR_Store(tpm_state->tpm_stclear_data.PCRS, + pcrNum, + h1); + } + if (rc == 0) { + /* 8. If TPM_PERMANENT_FLAGS -> disable is TRUE or TPM_STCLEAR_FLAGS -> deactivated is + TRUE */ + if ((tpm_state->tpm_permanent_flags.disable) || + (tpm_state->tpm_stclear_flags.deactivated)) { + /* a. Set outDigest to 20 bytes of 0x00 */ + TPM_Digest_Init(outDigest); + } + /* 9. Else */ + else { + /* a. Set outDigest to h1 */ + TPM_Digest_Copy(outDigest, h1); + } + } + if (rc == 0) { + ordinal = ordinal; + } + return rc; +} + +/* 16.1 TPM_Extend rev 109 + + This adds a new measurement to a PCR. +*/ + +TPM_RESULT TPM_Process_Extend(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_PCRINDEX pcrNum; /* The PCR to be updated. */ + TPM_DIGEST inDigest; /* The 160 bit value representing the event to be + recorded. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_PCRVALUE outDigest; /* The PCR value after execution of the command. */ + + printf("TPM_Process_Extend: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pcrNum parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&pcrNum, &command, ¶mSize); + } + /* get inDigest parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Digest_Load(inDigest, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Extend: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* extend the resultant digest into a PCR */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ExtendCommon(outDigest, tpm_state, ordinal, pcrNum, inDigest); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Extend: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* append outDigest */ + returnCode = TPM_Digest_Store(response, outDigest); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 16.4 TPM_PCR_Reset rev 87 + + For PCR with the pcrReset attribute set to TRUE, this command resets the PCR back to the default + value, this mimics the actions of TPM_Init. The PCR may have restrictions as to which locality + can perform the reset operation. + + Sending a null pcrSelection results in an error is due to the requirement that the command + actually do something. If pcrSelection is null there are no PCR to reset and the command would + then do nothing. + + For PCR that are resettable, the presence of a Trusted Operating System (TOS) can change the + behavior of TPM_PCR_Reset. The following pseudo code shows how the behavior changes + + At TPM_Startup + If TPM_PCR_ATTRIBUTES->pcrReset is FALSE + Set PCR to 0x00...00 + Else + Set PCR to 0xFF...FF + + At TPM_PCR_Reset + If TPM_PCR_ATTRIBUTES->pcrReset is TRUE + If TOSPresent + Set PCR to 0x00...00 + Else + Set PCR to 0xFF...FF + Else + Return error + + The above pseudocode is for example only, for the details of a specific platform, the reader must + review the platform specific specification. The purpose of the above pseudocode is to show that + both pcrReset and the TOSPresent bit control the value in use to when the PCR resets. +*/ + +TPM_RESULT TPM_Process_PcrReset(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_PCR_SELECTION pcrSelection; /* The PCR's to reset*/ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL pcrUsage; /* TRUE if pcrSelection specifies one or more + PCR's */ + TPM_PERMANENT_DATA *tpm_permanent_data = NULL; + size_t i; /* PCR selection iterator */ + size_t j; /* PCR selection bit map in byte */ + TPM_PCRINDEX pcr_num; /* PCR iterator */ + TPM_MODIFIER_INDICATOR localityModifier = 0; + uint16_t sizeOfSelect = 0; /* from pcrSelection input parameter */ + + /* output parameters */ + uint16_t outParamStart; /* starting point of outParam's */ + uint16_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_PcrReset: Ordinal Entry\n"); + TPM_PCRSelection_Init(&pcrSelection); /* freed @1 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pcrSelection */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_Load(&pcrSelection, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_PcrReset: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Validate that pcrSelection is valid */ + /* a. is a valid TPM_PCR_SELECTION structure */ + /* NOTE: Done during TPM_PCRSelection_Load() */ + /* b. pcrSelection -> pcrSelect is non-zero */ + /* NOTE: TPM_PCRSelection_GetPCRUsage() range checks pcrSelection */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_PcrReset: Getting input PCR usage\n"); + returnCode = TPM_PCRSelection_GetPCRUsage(&pcrUsage, &pcrSelection, 0); + } + /* c. On errors return TPM_INVALID_PCR_INFO */ + if (returnCode == TPM_SUCCESS) { + if (!pcrUsage) { + printf("TPM_Process_PcrReset: Error, pcrSelect is zero\n"); + returnCode = TPM_INVALID_PCR_INFO; + } + } + /* 2. Map L1 to TPM_STANY_FLAGS -> localityModifier (NOTE and other optimizations of the inner + loop) */ + if (returnCode == TPM_SUCCESS) { + localityModifier = tpm_state->tpm_stany_flags.localityModifier; + tpm_permanent_data = &(tpm_state->tpm_permanent_data); + sizeOfSelect = pcrSelection.sizeOfSelect; /* bytes of input PCR selection */ + } + /* 3. For each PCR selected perform the following */ + for (i = 0, pcr_num = 0 ; (returnCode == TPM_SUCCESS) && (i < sizeOfSelect) ; i++) { + /* iterate through all bits in each selection byte */ + for (j = 0x0001 ; + (returnCode == TPM_SUCCESS) && (j != (0x0001 << CHAR_BIT)) ; + j <<= 1, pcr_num++) { + + if (pcrSelection.pcrSelect[i] & j) { /* if the bit is set in the selection map */ + /* a. If pcrAttrib[pcrIndex].pcrReset is FALSE */ + if (!(tpm_permanent_data->pcrAttrib[pcr_num].pcrReset)) { + printf("TPM_Process_PcrReset: Error, PCR %u not resettable\n", pcr_num); + /* a. Return TPM_NOTRESETABLE */ + returnCode = TPM_NOTRESETABLE; + } + /* b. If, for the value L1, the corresponding bit is clear in the bit map + TPM_PERMANENT_DATA -> pcrAttrib[pcrIndex].pcrResetLocal, return + TPM_NOTLOCAL */ + else { + returnCode = + TPM_Locality_Check(tpm_permanent_data->pcrAttrib[pcr_num].pcrResetLocal, + localityModifier); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_PcrReset: Error, PCR %u bad pcrResetLocal %02x\n", + pcr_num, tpm_permanent_data->pcrAttrib[pcr_num].pcrResetLocal); + returnCode = TPM_NOTLOCAL; + } + } + /* NOTE: No 'else reset' here. The command MUST validate that all PCR registers + that are selected are available to be reset before resetting any PCR. */ + } + } + } + /* 3. For each PCR selected perform the following */ + if (returnCode == TPM_SUCCESS) { + for (i = 0, pcr_num = 0 ; i < sizeOfSelect ; i++) { + /* iterate through all bits in each selection byte */ + for (j = 0x0001 ; j != (0x0001 << CHAR_BIT) ; j <<= 1, pcr_num++) { + if (pcrSelection.pcrSelect[i] & j) { /* if the bit is set in the selection map */ + printf("TPM_Process_PcrReset: Resetting PCR %u\n", pcr_num); + /* a. The PCR MAY only reset to 0x00...00 or 0xFF...FF */ + /* b. The logic to determine which value to use MUST be described by a platform + specific specification + */ + /* Ignore errors here since PCR selection has already been validated. pcr_num + is guaranteed to be in range from from 'for' iterator, and pcrReset is + guaranteed to be TRUE from the previous loop. */ + TPM_PCR_Reset(tpm_state->tpm_stclear_data.PCRS, + tpm_state->tpm_stany_flags.TOSPresent, + pcr_num); + } + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_PcrReset: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_PCRSelection_Delete(&pcrSelection); /* @1 */ + return rcf; +} + diff --git a/src/tpm_pcr.h b/src/tpm_pcr.h new file mode 100644 index 00000000..8306e661 --- /dev/null +++ b/src/tpm_pcr.h @@ -0,0 +1,361 @@ +/********************************************************************************/ +/* */ +/* PCR Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_pcr.h 4620 2011-09-07 21:43:19Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_PCR_H +#define TPM_PCR_H + +#include "tpm_global.h" +#include "tpm_sizedbuffer.h" +#include "tpm_store.h" + +/* + Locality Utilities +*/ + +TPM_RESULT TPM_Locality_Set(TPM_LOCALITY_SELECTION *tpm_locality_selection, + TPM_MODIFIER_INDICATOR tpm_modifier_indicator); +TPM_RESULT TPM_Locality_Check(TPM_LOCALITY_SELECTION tpm_locality_selection, + TPM_MODIFIER_INDICATOR localityModifier); + +TPM_RESULT TPM_LocalitySelection_CheckLegal(TPM_LOCALITY_SELECTION tpm_locality_selection); +TPM_RESULT TPM_LocalityModifier_CheckLegal(TPM_MODIFIER_INDICATOR localityModifier); + +void TPM_PCRLocality_Compare(TPM_BOOL *match, + TPM_LOCALITY_SELECTION tpm_locality_selection1, + TPM_LOCALITY_SELECTION tpm_locality_selection2); + +/* + state PCR's +*/ + +TPM_RESULT TPM_PCR_CheckRange(TPM_PCRINDEX index); +void TPM_PCR_Init(TPM_PCRVALUE *tpm_pcrs, + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes, + size_t pcrIndex); +void TPM_PCR_Reset(TPM_PCRVALUE *tpm_pcrs, + TPM_BOOL TOSPresent, + TPM_PCRINDEX pcrIndex); +TPM_RESULT TPM_PCR_Load(TPM_PCRVALUE dest_pcr, + TPM_PCRVALUE *tpm_pcrs, + TPM_PCRINDEX index); +TPM_RESULT TPM_PCR_Store(TPM_PCRVALUE *tpm_pcrs, + TPM_PCRINDEX index, + TPM_PCRVALUE src_pcr); + +/* + TPM_SELECT_SIZE +*/ + +void TPM_SelectSize_Init(TPM_SELECT_SIZE *tpm_select_size); +TPM_RESULT TPM_SelectSize_Load(TPM_SELECT_SIZE *tpm_select_size, + unsigned char **stream, + uint32_t *stream_size); + + +/* + TPM_PCR_SELECTION +*/ + +void TPM_PCRSelection_Init(TPM_PCR_SELECTION *tpm_pcr_selection); +TPM_RESULT TPM_PCRSelection_Load(TPM_PCR_SELECTION *tpm_pcr_selection, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PCRSelection_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_SELECTION *tpm_pcr_selection); +void TPM_PCRSelection_Delete(TPM_PCR_SELECTION *tpm_pcr_selection); +/* copy */ +TPM_RESULT TPM_PCRSelection_Copy(TPM_PCR_SELECTION *destination, + TPM_PCR_SELECTION *source); +/* setters */ +TPM_RESULT TPM_PCRSelection_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_PCR_SELECTION *tpm_pcr_selection, + TPM_PCRVALUE *tpm_pcrs); +TPM_RESULT TPM_PCRSelection_GenerateDigest2(TPM_DIGEST tpm_digest, + TPM_PCR_COMPOSITE *tpm_pcr_composite, + TPM_PCR_SELECTION *tpm_pcr_selection, + TPM_PCRVALUE *tpm_pcrs); +/* getters */ +TPM_RESULT TPM_PCRSelection_GetPCRUsage(TPM_BOOL *pcrUsage, + const TPM_PCR_SELECTION *tpm_pcr_selection, + size_t start_index); +/* checkers */ +TPM_RESULT TPM_PCRSelection_CheckRange(const TPM_PCR_SELECTION *tpm_pcr_selection); +void TPM_PCRSelection_Compare(TPM_BOOL *match, + TPM_PCR_SELECTION *tpm_pcr_selection1, + TPM_PCR_SELECTION *tpm_pcr_selection2); +void TPM_PCRSelection_LessThan(TPM_BOOL *lessThan, + TPM_PCR_SELECTION *tpm_pcr_selection_new, + TPM_PCR_SELECTION *tpm_pcr_selection_old); + +/* TPM_PCR_ATTRIBUTES */ + +void TPM_PCRAttributes_Init(TPM_PCR_ATTRIBUTES *tpm_pcr_attributes); + +void TPM_PCRInfo_Trace(const char *message, + TPM_PCR_SELECTION pcrSelection, + TPM_COMPOSITE_HASH digestAtRelease); +/* + PCRs - Functions that act on the entire set of PCRs +*/ + +void TPM_PCRs_Init(TPM_PCRVALUE *tpm_pcrs, + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes); +TPM_RESULT TPM_PCRs_Load(TPM_PCRVALUE *tpm_pcrs, + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PCRs_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PCRVALUE *tpm_pcrs, + const TPM_PCR_ATTRIBUTES *tpm_pcr_attributes); + +/* + TPM_PCR_INFO +*/ + +void TPM_PCRInfo_Init(TPM_PCR_INFO *tpm_pcr_info); +TPM_RESULT TPM_PCRInfo_Load(TPM_PCR_INFO *tpm_pcr_info, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PCRInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO *tpm_pcr_info); +void TPM_PCRInfo_Delete(TPM_PCR_INFO *tpm_pcr_info); +/* create */ +TPM_RESULT TPM_PCRInfo_Create(TPM_PCR_INFO **tpm_pcr_info); +/* load */ +TPM_RESULT TPM_PCRInfo_LoadFromBuffer(TPM_PCR_INFO *tpm_pcr_info, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_PCRInfo_CreateFromBuffer(TPM_PCR_INFO **tpm_pcr_info, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +/* copy */ +TPM_RESULT TPM_PCRInfo_Copy(TPM_PCR_INFO *dest_tpm_pcr_info, + TPM_PCR_INFO *src_tpm_pcr_info); +TPM_RESULT TPM_PCRInfo_CopyInfoLong(TPM_PCR_INFO *dest_tpm_pcr_info, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfo_CreateFromInfo(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_PCR_INFO *src_tpm_pcr_info); +TPM_RESULT TPM_PCRInfo_CreateFromInfoLong(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfo_CreateFromKey(TPM_PCR_INFO **dest_tpm_pcr_info, + TPM_KEY *tpm_key); + +/* setters */ +TPM_RESULT TPM_PCRInfo_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_PCR_INFO *tpm_pcr_info, + TPM_PCRVALUE *tpm_pcrs); +TPM_RESULT TPM_PCRInfo_CheckDigest(TPM_PCR_INFO *tpm_pcr_info, + TPM_PCRVALUE *tpm_pcrs); +TPM_RESULT TPM_PCRInfo_SetDigestAtCreation(TPM_PCR_INFO *tpm_pcr_info, + TPM_PCRVALUE *tpm_pcrs); +/* getters */ +TPM_RESULT TPM_PCRInfo_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO *tpm_pcr_info, + size_t start_index); + +/* + TPM_PCR_INFO_LONG +*/ + +void TPM_PCRInfoLong_Init(TPM_PCR_INFO_LONG *tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfoLong_Load(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PCRInfoLong_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO_LONG *tpm_pcr_info_long); +void TPM_PCRInfoLong_Delete(TPM_PCR_INFO_LONG *tpm_pcr_info_long); +/* create */ +TPM_RESULT TPM_PCRInfoLong_Create(TPM_PCR_INFO_LONG **tpm_pcr_info_long); +/* load */ +TPM_RESULT TPM_PCRInfoLong_LoadFromBuffer(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_PCRInfoLong_CreateFromBuffer(TPM_PCR_INFO_LONG **tpm_pcr_info_long, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +/* copy */ +TPM_RESULT TPM_PCRInfoLong_Copy(TPM_PCR_INFO_LONG *dest_tpm_pcr_info_long, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfoLong_CreateFromInfoLong(TPM_PCR_INFO_LONG **dest_tpm_pcr_info_long, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +/* setters */ +TPM_RESULT TPM_PCRInfoLong_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_PCR_INFO_LONG *tpm_pcr_info_long, + TPM_PCRVALUE *tpm_pcrs); +TPM_RESULT TPM_PCRInfoLong_CheckDigest(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + TPM_PCRVALUE *tpm_pcrs, + TPM_MODIFIER_INDICATOR localityModifier); +TPM_RESULT TPM_PCRInfoLong_SetDigestAtCreation(TPM_PCR_INFO_LONG *tpm_pcr_info_long, + TPM_PCRVALUE *tpm_pcrs); +/* getters */ +TPM_RESULT TPM_PCRInfoLong_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO_LONG *tpm_pcr_info_long, + size_t start_index); + +/* + TPM_PCR_INFO_SHORT +*/ + +void TPM_PCRInfoShort_Init(TPM_PCR_INFO_SHORT *tpm_pcr_info_short); +TPM_RESULT TPM_PCRInfoShort_Load(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL optimize); +TPM_RESULT TPM_PCRInfoShort_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + TPM_BOOL optimize); +void TPM_PCRInfoShort_Delete(TPM_PCR_INFO_SHORT *tpm_pcr_info_short); +/* create */ +TPM_RESULT TPM_PCRInfoShort_Create(TPM_PCR_INFO_SHORT **tpm_pcr_info_short); +/* load */ +TPM_RESULT TPM_PCRInfoShort_LoadFromBuffer(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_PCRInfoShort_CreateFromBuffer(TPM_PCR_INFO_SHORT **tpm_pcr_info_short, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +/* copy */ +TPM_RESULT TPM_PCRInfoShort_Copy(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO_SHORT *src_tpm_pcr_info_short); +TPM_RESULT TPM_PCRInfoShort_CopyInfo(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO *src_tpm_pcr_info); +TPM_RESULT TPM_PCRInfoShort_CopyInfoLong(TPM_PCR_INFO_SHORT *dest_tpm_pcr_info_short, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfoShort_CreateFromInfo(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_PCR_INFO *src_tpm_pcr_info); +TPM_RESULT TPM_PCRInfoShort_CreateFromInfoLong(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_PCR_INFO_LONG *src_tpm_pcr_info_long); +TPM_RESULT TPM_PCRInfoShort_CreateFromKey(TPM_PCR_INFO_SHORT **dest_tpm_pcr_info_short, + TPM_KEY *tpm_key); + +/* setters */ +TPM_RESULT TPM_PCRInfoShort_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + TPM_PCRVALUE *tpm_pcrs); +TPM_RESULT TPM_PCRInfoShort_CheckDigest(TPM_PCR_INFO_SHORT *tpm_pcr_info_short, + TPM_PCRVALUE *tpm_pcrs, + TPM_MODIFIER_INDICATOR localityModifier); + +/* getters */ +TPM_RESULT TPM_PCRInfoShort_GetPCRUsage(TPM_BOOL *pcrUsage, + TPM_PCR_INFO_SHORT *tpm_pcr_info_short); + +/* + TPM_PCR_COMPOSITE +*/ + +void TPM_PCRComposite_Init(TPM_PCR_COMPOSITE *tpm_pcr_composite); +TPM_RESULT TPM_PCRComposite_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PCR_COMPOSITE *tpm_pcr_composite); +void TPM_PCRComposite_Delete(TPM_PCR_COMPOSITE *tpm_pcr_composite); + +TPM_RESULT TPM_PCRComposite_Set(TPM_PCR_COMPOSITE *tpm_pcr_composite, + TPM_PCR_SELECTION *tpm_pcr_selection, + TPM_PCRVALUE *tpm_pcrs); + +/* + TPM_QUOTE_INFO +*/ + +void TPM_QuoteInfo_Init(TPM_QUOTE_INFO *tpm_quote_info); +TPM_RESULT TPM_QuoteInfo_Load(TPM_QUOTE_INFO *tpm_quote_info, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_QuoteInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_QUOTE_INFO *tpm_quote_info); +void TPM_QuoteInfo_Delete(TPM_QUOTE_INFO *tpm_quote_info); + +/* + TPM_QUOTE_INFO2 +*/ + +void TPM_QuoteInfo2_Init(TPM_QUOTE_INFO2 *tpm_quote_info2); +TPM_RESULT TPM_QuoteInfo2_Load(TPM_QUOTE_INFO2 *tpm_quote_info2, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_QuoteInfo2_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_QUOTE_INFO2 *tpm_quote_info2); +void TPM_QuoteInfo2_Delete(TPM_QUOTE_INFO2 *tpm_quote_info2); + + +/* + Common command processing +*/ + +TPM_RESULT TPM_ExtendCommon(TPM_PCRVALUE outDigest, + tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, + TPM_PCRINDEX pcrNum, + TPM_DIGEST inDigest); +/* + Command Processing +*/ + +TPM_RESULT TPM_Process_PcrRead(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_Quote(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_Quote2(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_Extend(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_PcrReset(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +#endif diff --git a/src/tpm_permanent.c b/src/tpm_permanent.c new file mode 100644 index 00000000..b9a62099 --- /dev/null +++ b/src/tpm_permanent.c @@ -0,0 +1,1333 @@ +/********************************************************************************/ +/* */ +/* Permanent Flag and Data Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_permanent.c 4623 2011-09-28 15:15:09Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_audit.h" +#include "tpm_counter.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_delegate.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_global.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_nvfile.h" +#include "tpm_nvfilename.h" +#include "tpm_nvram.h" +#include "tpm_pcr.h" +#include "tpm_secret.h" +#include "tpm_storage.h" +#include "tpm_structures.h" +#include "tpm_types.h" +#include "tpm_svnrevision.h" + + +#include "tpm_permanent.h" + +/* + TPM_PERMANENT_FLAGS +*/ + +void TPM_PermanentFlags_Init(TPM_PERMANENT_FLAGS *tpm_permanent_flags) +{ + printf(" TPM_PermanentFlags_Init:\n"); +#ifndef TPM_ENABLE_ACTIVATE + tpm_permanent_flags->disable = TRUE; +#else /* for servers, not TCG standard */ + tpm_permanent_flags->disable = FALSE; +#endif + tpm_permanent_flags->ownership = TRUE; +#ifndef TPM_ENABLE_ACTIVATE + tpm_permanent_flags->deactivated = TRUE; +#else /* for servers, not TCG standard */ + tpm_permanent_flags->deactivated = FALSE; +#endif + tpm_permanent_flags->readPubek = TRUE; + tpm_permanent_flags->disableOwnerClear = FALSE; + tpm_permanent_flags->allowMaintenance = TRUE; + tpm_permanent_flags->physicalPresenceLifetimeLock = FALSE; + tpm_permanent_flags->physicalPresenceHWEnable = FALSE; +#ifndef TPM_PP_CMD_ENABLE /* TCG standard */ + tpm_permanent_flags->physicalPresenceCMDEnable = FALSE; +#else /* 'ship' TRUE */ + tpm_permanent_flags->physicalPresenceCMDEnable = TRUE; +#endif + /* tpm_permanent_flags->CEKPUsed = ; This flag has no default value */ + tpm_permanent_flags->TPMpost = FALSE; + tpm_permanent_flags->TPMpostLock = FALSE; + tpm_permanent_flags->FIPS = FALSE; /* if TRUE, could not test no-auth commands */ + tpm_permanent_flags->tpmOperator = FALSE; + tpm_permanent_flags->enableRevokeEK = TRUE; + tpm_permanent_flags->nvLocked = FALSE; + tpm_permanent_flags->readSRKPub = FALSE; + tpm_permanent_flags->tpmEstablished = FALSE; + tpm_permanent_flags->maintenanceDone = FALSE; +#if (TPM_REVISION >= 103) /* added for rev 103 */ + tpm_permanent_flags->disableFullDALogicInfo = FALSE; +#endif +} + +/* TPM_PermanentFlags_Load() + + deserializes the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + It is used when deserializing the structure from storage in NVRAM. +*/ + +TPM_RESULT TPM_PermanentFlags_Load(TPM_PERMANENT_FLAGS *tpm_permanent_flags, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t tpm_bitmap; + TPM_TAG permanentFlagsVersion; + + printf(" TPM_PermanentFlags_Load:\n"); + /* load the TPM_PERMANENT_FLAGS version tag from the stream */ + if (rc == 0) { + rc = TPM_Load16(&permanentFlagsVersion, stream, stream_size); + } + /* load the TPM_PERMANENT_FLAGS from the stream */ + if (rc == 0) { + rc = TPM_Load32(&tpm_bitmap, stream, stream_size); + } + /* load the TPM_PERMANENT_FLAGS from the bitmap */ + if (rc == 0) { + rc = TPM_PermanentFlags_LoadBitmap(tpm_permanent_flags, permanentFlagsVersion, tpm_bitmap); + } + return rc; +} + +/* TPM_PermanentFlags_Store() serializes the TPM_PERMANENT_FLAGS structure as a bitmap. + + It is used when serializing the structure for storage in NVRAM. +*/ + +TPM_RESULT TPM_PermanentFlags_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags) + +{ + TPM_RESULT rc = 0; + uint32_t tpm_bitmap; + + printf(" TPM_PermanentFlags_Store:\n"); + /* store the TPM_PERMANENT_FLAGS structure in a bit map */ + if (rc == 0) { + rc = TPM_PermanentFlags_StoreBitmap(&tpm_bitmap, tpm_permanent_flags); + } + /* append a TPM_PERMANENT_FLAGS version tag */ +#if (TPM_REVISION >= 103) + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_PF103); + } +#else + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_PF94); + } +#endif + /* append the bitmap to the stream */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_bitmap); + } + return rc; +} + +/* TPM_PermanentFlags_StoreBytes() serializes the TPM_PERMANENT_FLAGS structure as bytes + + */ + +TPM_RESULT TPM_PermanentFlags_StoreBytes(TPM_STORE_BUFFER *sbuffer, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PermanentFlags_StoreBytes:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_PERMANENT_FLAGS); + } + /* store disable */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->disable), sizeof(BYTE)); + } + /* store ownership */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->ownership), sizeof(BYTE)); + } + /* store deactivated */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->deactivated), sizeof(BYTE)); + } + /* store readPubek */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->readPubek), sizeof(BYTE)); + } + /* store disableOwnerClear */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->disableOwnerClear), sizeof(BYTE)); + } + /* store allowMaintenance */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->allowMaintenance), sizeof(BYTE)); + } + /* store physicalPresenceLifetimeLock */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->physicalPresenceLifetimeLock), + sizeof(BYTE)); + } + /* store physicalPresenceHWEnable */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->physicalPresenceHWEnable), + sizeof(BYTE)); + } + /* store physicalPresenceCMDEnable */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->physicalPresenceCMDEnable), + sizeof(BYTE)); + } + /* store CEKPUsed */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->CEKPUsed), sizeof(BYTE)); + } + /* store TPMpost */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->TPMpost), sizeof(BYTE)); + } + /* store TPMpostLock */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->TPMpostLock), sizeof(BYTE)); + } + /* store FIPS */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->FIPS), sizeof(BYTE)); + } + /* store operator */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->tpmOperator), sizeof(BYTE)); + } + /* store enableRevokeEK */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->enableRevokeEK), sizeof(BYTE)); + } + /* store nvLocked */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->nvLocked), sizeof(BYTE)); + } + /* store readSRKPub */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->readSRKPub), sizeof(BYTE)); + } + /* store tpmEstablished */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->tpmEstablished), sizeof(BYTE)); + } + /* store maintenanceDone */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_flags->maintenanceDone), sizeof(BYTE)); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + /* store disableFullDALogicInfo */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_permanent_flags->disableFullDALogicInfo), sizeof(BYTE)); + } +#endif + return rc; +} + +/* TPM_PermanentFlags_LoadBitmap() loads the TPM_PERMANENT_FLAGS structure from the bit map + + permanentFlagsVersion indicates the version being loaded from NVRAM +*/ + +TPM_RESULT TPM_PermanentFlags_LoadBitmap(TPM_PERMANENT_FLAGS *tpm_permanent_flags, + TPM_TAG permanentFlagsVersion, + uint32_t tpm_bitmap) +{ + TPM_RESULT rc = 0; + uint32_t pos = 0; /* position in bitmap */ + + if (rc == 0) { + switch (permanentFlagsVersion) { + case TPM_TAG_NVSTATE_PF94: + break; + case TPM_TAG_NVSTATE_PF103: + /* if the TPM_REVISION supports the permanentFlagsVersion, break with no error. If it + doesn't, omit the break and fall through to the unsupported case. */ +#if (TPM_REVISION >= 103) + break; +#endif + default: + /* no forward compatibility */ + printf("TPM_PermanentFlags_LoadBitmap: Error (fatal) unsupported version tag %04x\n", + permanentFlagsVersion); + rc = TPM_FAIL; + break; + } + } + printf(" TPM_PermanentFlags_LoadBitmap:\n"); + /* load disable */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->disable), tpm_bitmap, &pos); + } + /* load ownership */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->ownership), tpm_bitmap, &pos); + } + /* load deactivated */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->deactivated), tpm_bitmap, &pos); + } + /* load readPubek */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->readPubek), tpm_bitmap, &pos); + } + /* load disableOwnerClear */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->disableOwnerClear), tpm_bitmap, &pos); + } + /* load allowMaintenance */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->allowMaintenance), tpm_bitmap, &pos); + } + /* load physicalPresenceLifetimeLock */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->physicalPresenceLifetimeLock), + tpm_bitmap, &pos); + } + /* load physicalPresenceHWEnable */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->physicalPresenceHWEnable), tpm_bitmap, &pos); + } + /* load physicalPresenceCMDEnable */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->physicalPresenceCMDEnable), tpm_bitmap, &pos); + } + /* load CEKPUsed */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->CEKPUsed), tpm_bitmap, &pos); + } + /* load TPMpost */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->TPMpost), tpm_bitmap, &pos); + } + /* load TPMpostLock */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->TPMpostLock), tpm_bitmap, &pos); + } + /* load FIPS */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->FIPS), tpm_bitmap, &pos); + } + /* load operator */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->tpmOperator), tpm_bitmap, &pos); + } + /* load enableRevokeEK */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->enableRevokeEK), tpm_bitmap, &pos); + } + /* load nvLocked */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->nvLocked), tpm_bitmap, &pos); + } + /* load readSRKPub */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->readSRKPub), tpm_bitmap, &pos); + } + /* load tpmEstablished */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->tpmEstablished), tpm_bitmap, &pos); + } + /* load maintenanceDone */ + if (rc == 0) { + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->maintenanceDone), tpm_bitmap, &pos); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + if (rc == 0) { + switch (permanentFlagsVersion) { + case TPM_TAG_NVSTATE_PF94: + /* 94 to 103, set extra flags to default value */ + tpm_permanent_flags->disableFullDALogicInfo = FALSE; + break; + case TPM_TAG_NVSTATE_PF103: + /* 103 to 103, process normally */ + /* load disableFullDALogicInfo */ + rc = TPM_Bitmap_Load(&(tpm_permanent_flags->disableFullDALogicInfo), tpm_bitmap, &pos); + break; + } + } +#endif + return rc; +} + +/* TPM_PermanentFlags_StoreBitmap() stores the TPM_PERMANENT_FLAGS structure in a bit map + + It is used when serializing the structure for storage in NVRAM and as the return to + TPM_GetCapability. +*/ + +TPM_RESULT TPM_PermanentFlags_StoreBitmap(uint32_t *tpm_bitmap, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags) +{ + TPM_RESULT rc = 0; + uint32_t pos = 0; /* position in bitmap */ + + printf(" TPM_PermanentFlags_StoreBitmap:\n"); + *tpm_bitmap = 0; /* set unused bits to 0 */ + /* store disable */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->disable, &pos); + } + /* store ownership */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->ownership, &pos); + } + /* store deactivated */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->deactivated, &pos); + } + /* store readPubek */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->readPubek, &pos); + } + /* store disableOwnerClear */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->disableOwnerClear, &pos); + } + /* store allowMaintenance */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->allowMaintenance, &pos); + } + /* store physicalPresenceLifetimeLock */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->physicalPresenceLifetimeLock, &pos); + } + /* store physicalPresenceHWEnable */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->physicalPresenceHWEnable, &pos); + } + /* store physicalPresenceCMDEnable */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->physicalPresenceCMDEnable, &pos); + } + /* store CEKPUsed */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->CEKPUsed, &pos); + } + /* store TPMpost */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->TPMpost, &pos); + } + /* store TPMpostLock */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->TPMpostLock, &pos); + } + /* store FIPS */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->FIPS, &pos); + } + /* store operator */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->tpmOperator, &pos); + } + /* store enableRevokeEK */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->enableRevokeEK, &pos); + } + /* store nvLocked */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->nvLocked, &pos); + } + /* store readSRKPub */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->readSRKPub, &pos); + } + /* store tpmEstablished */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->tpmEstablished, &pos); + } + /* store maintenanceDone */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->maintenanceDone, &pos); + } +#if (TPM_REVISION >= 103) /* added for rev 103 */ + /* store disableFullDALogicInfo */ + if (rc == 0) { + rc = TPM_Bitmap_Store(tpm_bitmap, tpm_permanent_flags->disableFullDALogicInfo, &pos); + } +#endif + return rc; +} + +/* + TPM_PERMANENT_DATA +*/ + +/* TPM_PermanentData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + + This function generates a new contextKey, delegateKey, daaBlobKey. +*/ + + +TPM_RESULT TPM_PermanentData_Init(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PermanentData_Init:\n"); + if (rc == 0) { + tpm_permanent_data->revMajor = ((tpm_svn_revision >> 8) & 0xff); + tpm_permanent_data->revMinor = ((tpm_svn_revision ) & 0xff); + printf(" TPM_PermanentData_Init: revMajor %02x revMinor %02x\n", + tpm_permanent_data->revMajor, tpm_permanent_data->revMinor); + /* zero all secrets */ + TPM_PermanentData_Zero(tpm_permanent_data, instanceData); + +#ifndef TPM_NOMAINTENANCE + TPM_Pubkey_Init(&(tpm_permanent_data->manuMaintPub)); +#endif + TPM_Key_Init(&(tpm_permanent_data->endorsementKey)); + TPM_Key_Init(&(tpm_permanent_data->srk)); + tpm_permanent_data->contextKey = NULL; + rc = TPM_SymmetricKeyData_New(&(tpm_permanent_data->contextKey)); + } + if (rc == 0) { + tpm_permanent_data->delegateKey = NULL; + rc = TPM_SymmetricKeyData_New(&(tpm_permanent_data->delegateKey)); + } + if (rc == 0) { + TPM_CounterValue_Init(&(tpm_permanent_data->auditMonotonicCounter)); + TPM_Counters_Init(tpm_permanent_data->monotonicCounter); + TPM_PCRAttributes_Init(tpm_permanent_data->pcrAttrib); + rc = TPM_OrdinalAuditStatus_Init(tpm_permanent_data); + } + if (rc == 0) { + TPM_FamilyTable_Init(&(tpm_permanent_data->familyTable)); + TPM_DelegateTable_Init(&(tpm_permanent_data->delegateTable)); + tpm_permanent_data->lastFamilyID = 0; + tpm_permanent_data->noOwnerNVWrite = 0; + tpm_permanent_data->restrictDelegate = 0; + /* tpmDAASeed done by TPM_PermanentData_Zero() */ + /* daaProof done by TPM_PermanentData_Zero() */ + rc = TPM_SymmetricKeyData_New(&(tpm_permanent_data->daaBlobKey)); + } + if (rc == 0) { + tpm_permanent_data->ownerInstalled = FALSE; + /* tscOrdinalAuditStatus initialized by TPM_OrdinalAuditStatus_Init() */ + /* instanceOrdinalAuditStatus initialized by TPM_OrdinalAuditStatus_Init() */ + tpm_permanent_data->allowLoadMaintPub = TRUE; + if (instanceData) { + } + } + return rc; +} + +/* TPM_PermanentData_Load() + + deserializes the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_PermanentData_Load(TPM_PERMANENT_DATA *tpm_permanent_data, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL instanceData) +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL tpm_bool; + + + printf(" TPM_PermanentData_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_PERMANENT_DATA, stream, stream_size); + } + /* load revMajor */ + /* load revMinor */ + /* not stored, loaded from hard coded value */ + if (rc == 0) { + tpm_permanent_data->revMajor = (tpm_svn_revision >> 8) & 0xff; + tpm_permanent_data->revMinor = tpm_svn_revision & 0xff; + } + /* load tpmProof */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Loading tpmProof\n"); + rc = TPM_Secret_Load(tpm_permanent_data->tpmProof, stream, stream_size); + } + /* load EKReset */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_permanent_data->EKReset, stream, stream_size); + } + /* load ownerAuth */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Loading ownerAuth \n"); + rc = TPM_Secret_Load(tpm_permanent_data->ownerAuth, stream, stream_size); + } + /* load operatorAuth */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_permanent_data->operatorAuth, stream, stream_size); + } + /* load authDIR */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_permanent_data->authDIR, stream, stream_size); + } + /* load manuMaintPub present marker */ + if (rc == 0) { + rc = TPM_Load8(&tpm_bool, stream, stream_size); + } +#ifndef TPM_NOMAINTENANCE + /* check that manuMaintPub is present */ + if (rc == 0) { + if (!tpm_bool) { + printf(" TPM_PermanentData_Load: Error (fatal) missing manuMaintPub\n"); + rc = TPM_FAIL; + } + } + /* load manuMaintPub */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load manuMaintPub\n"); + rc = TPM_Pubkey_Load(&(tpm_permanent_data->manuMaintPub), stream, stream_size); + } +#else + /* check that manuMaintPub is absent */ + if (tpm_bool) { + printf(" TPM_PermanentData_Load: Error (fatal) contains manuMaintPub\n"); + rc = TPM_FAIL; + } +#endif + /* load endorsementKey */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load endorsement key\n"); + rc = TPM_Key_LoadClear(&(tpm_permanent_data->endorsementKey), TRUE, stream, stream_size); + } + /* load srk */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load SRK\n"); + rc = TPM_Key_LoadClear(&(tpm_permanent_data->srk), FALSE, stream, stream_size); + } + /* load contextKey */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load contextKey\n"); + rc = TPM_SymmetricKeyData_Load(tpm_permanent_data->contextKey, stream, stream_size); + } + /* load delegateKey */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load delegateKey\n"); + rc = TPM_SymmetricKeyData_Load(tpm_permanent_data->delegateKey, stream, stream_size); + } + /* load auditMonotonicCounter */ + if (rc == 0) { + rc = TPM_CounterValue_Load(&(tpm_permanent_data->auditMonotonicCounter), + stream, stream_size); + } + /* load monotonicCounter's */ + if (rc == 0) { + rc = TPM_Counters_Load(tpm_permanent_data->monotonicCounter, stream, stream_size); + } + /* load pcrAttrib's, since they are constants, no need to load from NV space */ + if (rc == 0) { + TPM_PCRAttributes_Init(tpm_permanent_data->pcrAttrib); + } + if (rc == 0) { + printf(" TPM_PermanentData_Load: Load ordinalAuditStatus\n"); + } + /* load ordinalAuditStatus's */ + for (i = 0 ; (rc == 0) && (i < (TPM_ORDINALS_MAX/CHAR_BIT)) ; i++) { + rc = TPM_Load8(&(tpm_permanent_data->ordinalAuditStatus[i]), stream, stream_size); + } + /* load familyTable */ + if (rc == 0) { + rc = TPM_FamilyTable_Load(&(tpm_permanent_data->familyTable), stream, stream_size); + } + /* load delegateTable */ + if (rc == 0) { + rc = TPM_DelegateTable_Load(&(tpm_permanent_data->delegateTable), stream, stream_size); + } + /* load lastFamilyID */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_permanent_data->lastFamilyID), stream, stream_size); + } + /* load noOwnerNVWrite */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_permanent_data->noOwnerNVWrite), stream, stream_size); + } + /* load restrictDelegate */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_permanent_data->restrictDelegate), stream, stream_size); + } + /* load tpmDAASeed */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_permanent_data->tpmDAASeed, stream, stream_size); + } + /* load ownerInstalled */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_permanent_data->ownerInstalled), stream, stream_size); + } + /* load tscOrdinalAuditStatus */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_permanent_data->tscOrdinalAuditStatus), stream, stream_size); + } + /* load allowLoadMaintPub */ + if (rc == 0) { + rc = TPM_LoadBool(&(tpm_permanent_data->allowLoadMaintPub), stream, stream_size); + } + /* load daaProof */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_permanent_data->daaProof, stream, stream_size); + } + /* load daaBlobKey */ + if (rc == 0) { + printf(" TPM_PermanentData_Load: Loading DAA Blob key\n"); + rc = TPM_SymmetricKeyData_Load(tpm_permanent_data->daaBlobKey, stream, stream_size); + } + instanceData = instanceData; /* to quiet the compiler */ + return rc; +} + +/* TPM_PermanentData_Store() serializes the TPM_PERMANENT_DATA structure + + */ + +TPM_RESULT TPM_PermanentData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_PermanentData_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_PERMANENT_DATA); + } + /* store revMajor */ + /* store revMinor */ + /* not stored, loaded from hard coded value */ + /* store tpmProof */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_permanent_data->tpmProof); + } + /* store EKReset */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_permanent_data->EKReset); + } + /* store ownerAuth */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_permanent_data->ownerAuth); + } + /* store operatorAuth */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_permanent_data->operatorAuth); + } + /* store authDIR */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_permanent_data->authDIR); + } +#ifndef TPM_NOMAINTENANCE + /* mark that manuMaintPub is present */ + if (rc == 0) { + rc = TPM_Sbuffer_Append8(sbuffer, TRUE); + } + /* store manuMaintPub */ + if (rc == 0) { + rc = TPM_Pubkey_Store(sbuffer, &(tpm_permanent_data->manuMaintPub)); + } +#else + /* mark that manuMaintPub is absent */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, FALSE); + } +#endif + /* store endorsementKey */ + if (rc == 0) { + rc = TPM_Key_StoreClear(sbuffer, TRUE, &(tpm_permanent_data->endorsementKey)); + } + /* store srk */ + if (rc == 0) { + rc = TPM_Key_StoreClear(sbuffer, FALSE, &(tpm_permanent_data->srk)); + } + /* store contextKey */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Store(sbuffer, tpm_permanent_data->contextKey); + } + /* store delegateKey */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Store(sbuffer, tpm_permanent_data->delegateKey); + } + /* store auditMonotonicCounter */ + if (rc == 0) { + rc = TPM_CounterValue_Store(sbuffer, &(tpm_permanent_data->auditMonotonicCounter)); + } + /* store monotonicCounter */ + if (rc == 0) { + rc = TPM_Counters_Store(sbuffer, tpm_permanent_data->monotonicCounter); + } + /* store pcrAttrib, since they are constants, no need to store to NV space */ + /* store ordinalAuditStatus */ + for (i = 0 ; (rc == 0) && (i < (TPM_ORDINALS_MAX/CHAR_BIT)) ; i++) { + rc = TPM_Sbuffer_Append(sbuffer, + &(tpm_permanent_data->ordinalAuditStatus[i]), sizeof(BYTE)); + } + /* store familyTable */ + if (rc == 0) { + rc = TPM_FamilyTable_Store(sbuffer, + &(tpm_permanent_data->familyTable), + FALSE); /* don't store the tag, to save NV space */ + } + /* store delegateTable */ + if (rc == 0) { + rc = TPM_DelegateTable_Store(sbuffer, &(tpm_permanent_data->delegateTable)); + } + /* store lastFamilyID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_permanent_data->lastFamilyID); + } + /* store noOwnerNVWrite */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_permanent_data->noOwnerNVWrite); + } + /* store restrictDelegate */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_permanent_data->restrictDelegate); + } + /* store tpmDAASeed */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_permanent_data->tpmDAASeed); + } + /* store ownerInstalled */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_data->ownerInstalled), sizeof(BYTE)); + } + /* store tscOrdinalAuditStatus */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_data->tscOrdinalAuditStatus), + sizeof(BYTE)); + } + /* store allowLoadMaintPub */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_permanent_data->allowLoadMaintPub), sizeof(BYTE)); + } + /* store daaProof */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_permanent_data->daaProof); + } + /* store daaBlobKey */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_Store(sbuffer, tpm_permanent_data->daaBlobKey); + } + instanceData = instanceData; /* to quiet the compiler */ + return rc; +} + +/* TPM_PermanentData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_PermanentData_Zero to zero secrets that are not Delete'd + The object itself is not freed +*/ + +void TPM_PermanentData_Delete(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData) +{ + printf(" TPM_PermanentData_Delete:\n"); + if (tpm_permanent_data != NULL) { +#ifndef TPM_NOMAINTENANCE + TPM_Pubkey_Delete(&(tpm_permanent_data->manuMaintPub)); +#endif + TPM_Key_Delete(&(tpm_permanent_data->endorsementKey)); + TPM_Key_Delete(&(tpm_permanent_data->srk)); + TPM_SymmetricKeyData_Free(&(tpm_permanent_data->contextKey)); + TPM_SymmetricKeyData_Free(&(tpm_permanent_data->delegateKey)); + TPM_FamilyTable_Delete(&(tpm_permanent_data->familyTable)); + TPM_DelegateTable_Delete(&(tpm_permanent_data->delegateTable)); + TPM_SymmetricKeyData_Free(&(tpm_permanent_data->daaBlobKey)); + /* zero all secrets */ + TPM_PermanentData_Zero(tpm_permanent_data, instanceData); + } + return; +} + +/* TPM_PermanentData_Zero() zeros all secrets not already zeroed and freed by + TPM_PermanentData_Delete() + + It is called by TPM_PermanentData_Delete() and TPM_PermanentData_Init(). It does a subset of + TPM_PermanentData_Init() that will never fail. +*/ + +void TPM_PermanentData_Zero(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData) +{ + printf(" TPM_PermanentData_Zero:\n"); + instanceData = instanceData; + if (tpm_permanent_data != NULL) { + TPM_Secret_Init(tpm_permanent_data->tpmProof); + TPM_Nonce_Init(tpm_permanent_data->EKReset); + TPM_Secret_Init(tpm_permanent_data->ownerAuth); + TPM_Secret_Init(tpm_permanent_data->operatorAuth); + TPM_Digest_Init(tpm_permanent_data->authDIR); + /* endorsementKey handled by TPM_Key_Delete() */ + /* srk handled by TPM_Key_Delete() */ + /* contextKey handled by TPM_SymmetricKeyData_Free() */ + /* delegateKey handled by TPM_SymmetricKeyData_Free() */ + TPM_Nonce_Init(tpm_permanent_data->tpmDAASeed); + TPM_Nonce_Init(tpm_permanent_data->daaProof); + /* daaBlobKey handled by TPM_SymmetricKeyData_Free() */ + } + return; +} + +/* TPM_PermanentData_InitDaa() generates new values for the 3 DAA elements: tpmDAASeed, daaProof, + and daaBlobKey. + + This is common code, use when creating the EK, revoke trust, and the set capability + used by the owner to invalidate DAA blobs. +*/ + +TPM_RESULT TPM_PermanentData_InitDaa(TPM_PERMANENT_DATA *tpm_permanent_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PermanentData_InitDaa:\n"); + /* generate tpmDAASeed */ + if (rc == 0) { + rc = TPM_Nonce_Generate(tpm_permanent_data->tpmDAASeed); + } + /* generate daaProof*/ + if (rc == 0) { + rc = TPM_Nonce_Generate(tpm_permanent_data->daaProof); + } + /* generate daaBlobKey */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_GenerateKey(tpm_permanent_data->daaBlobKey); + } + return rc; +} + +/* + PermanentAll is TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, owner evict keys, and NV defined space. +*/ + +/* TPM_PermanentAll_Load() deserializes all TPM NV data from a stream created by + TPM_PermanentAll_Store(). + + The two functions must be kept in sync. + + Data includes TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, Owner Evict keys, and NV defined space. +*/ + +TPM_RESULT TPM_PermanentAll_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + unsigned char *stream_start = *stream; /* copy for integrity check */ + uint32_t stream_size_start = *stream_size; + + printf(" TPM_PermanentAll_Load:\n"); + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_NVSTATE_V1, stream, stream_size); + } + /* TPM_PERMANENT_DATA deserialize from stream */ + if (rc == 0) { + rc = TPM_PermanentData_Load(&(tpm_state->tpm_permanent_data), + stream, stream_size, TRUE); + } + /* TPM_PERMANENT_FLAGS deserialize from stream */ + if (rc == 0) { + rc = TPM_PermanentFlags_Load(&(tpm_state->tpm_permanent_flags), + stream, stream_size); + } + /* owner evict keys deserialize from stream */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_OwnerEvictLoad(tpm_state->tpm_key_handle_entries, + stream, stream_size); + } + /* NV defined space deserialize from stream */ + if (rc == 0) { + rc = TPM_NVIndexEntries_Load(&(tpm_state->tpm_nv_index_entries), + stream, stream_size); + } + /* sanity check the stream size */ + if (rc == 0) { + if (*stream_size != TPM_DIGEST_SIZE) { + printf("TPM_PermanentAll_Load: Error (fatal) stream size %u not %u\n", + *stream_size, TPM_DIGEST_SIZE); + rc = TPM_FAIL; + } + } + /* check the integrity digest */ + if (rc == 0) { + printf(" TPM_PermanentAll_Load: Checking integrity digest\n"); + rc = TPM_SHA1_Check(*stream, /* currently points to integrity digest */ + stream_size_start - TPM_DIGEST_SIZE, stream_start, + 0, NULL); + } + /* remove the integrity digest from the stream */ + if (rc == 0) { + *stream_size -= TPM_DIGEST_SIZE; + } + return rc; +} + +/* TPM_PermanentAll_Store() serializes all TPM NV data into a stream that can be restored through + TPM_PermanentAll_Load(). + + The two functions must be kept in sync. + + Data includes TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, Owner Evict keys, and NV defined space. + + The TPM_STORE_BUFFER, buffer and length are returned for convenience. + + This has two uses: + + - It is called before the actual NV store to serialize the data + - It is called by TPM_NV_DefineSpace to determine if there is enough NV space for the new index +*/ + +TPM_RESULT TPM_PermanentAll_Store(TPM_STORE_BUFFER *sbuffer, /* freed by caller */ + const unsigned char **buffer, + uint32_t *length, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_DIGEST tpm_digest; + + printf(" TPM_PermanentAll_Store:\n"); + /* overall format tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_NVSTATE_V1); + } + /* serialize TPM_PERMANENT_DATA */ + if (rc == 0) { + rc = TPM_PermanentData_Store(sbuffer, + &(tpm_state->tpm_permanent_data), TRUE); + } + /* serialize TPM_PERMANENT_FLAGS */ + if (rc == 0) { + rc = TPM_PermanentFlags_Store(sbuffer, + &(tpm_state->tpm_permanent_flags)); + } + /* serialize owner evict keys */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_OwnerEvictStore(sbuffer, + tpm_state->tpm_key_handle_entries); + } + /* serialize NV defined space */ + if (rc == 0) { + rc = TPM_NVIndexEntries_Store(sbuffer, + &(tpm_state->tpm_nv_index_entries)); + } + if (rc == 0) { + /* get the current serialized buffer and its length */ + TPM_Sbuffer_Get(sbuffer, buffer, length); + /* generate the integrity digest */ + rc = TPM_SHA1(tpm_digest, + *length, *buffer, + 0, NULL); + } + /* append the integrity digest to the stream */ + if (rc == 0) { + printf(" TPM_PermanentAll_Store: Appending integrity digest\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_digest, TPM_DIGEST_SIZE); + } + /* get the final serialized buffer and its length */ + if (rc == 0) { + TPM_Sbuffer_Get(sbuffer, buffer, length); + } + return rc; +} + +/* TPM_PermanentAll_NVLoad() + + Deserialize the TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, owner evict keys, and NV defined + space from a stream read from the NV file TPM_PERMANENT_ALL_NAME. + + Returns: + + 0 success + TPM_RETRY if file does not exist (first time) + TPM_FAIL on failure to load (fatal), since they should never occur +*/ + +TPM_RESULT TPM_PermanentAll_NVLoad(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + unsigned char *stream = NULL; + unsigned char *stream_start = NULL; + uint32_t stream_size; + + printf(" TPM_PermanentAll_NVLoad:\n"); + if (rc == 0) { + /* try loading from NVRAM */ + /* Returns TPM_RETRY on non-existent file */ + rc = TPM_NVRAM_LoadData(&stream, /* freed @1 */ + &stream_size, + tpm_state->tpm_number, + TPM_PERMANENT_ALL_NAME); + } + /* deserialize from stream */ + if (rc == 0) { + stream_start = stream; /* save starting point for free() */ + rc = TPM_PermanentAll_Load(tpm_state, &stream, &stream_size); + if (rc != 0) { + printf("TPM_PermanentAll_NVLoad: Error (fatal) loading deserializing NV state\n"); + rc = TPM_FAIL; + } + } + free(stream_start); /* @1 */ + return rc; +} + +/* TPM_PermanentAll_NVStore() serializes all NV data and stores it in the NV file + TPM_PERMANENT_ALL_NAME + + If the writeAllNV flag is FALSE, the function is a no-op, and returns the input 'rcIn'. + + If writeAllNV is TRUE and rcIn is not TPM_SUCCESS, this indicates that the ordinal + modified the in-memory TPM_PERMANENT_DATA and/or TPM_PERMANENT_FLAGS structures (perhaps only + partially) and then detected an error. Since the command is failing, roll back the structure by + reading the NV file. If the read then fails, this is a fatal error. + + Similarly, if writeAllNV is TRUE and the actual NV write fails, this is a fatal error. +*/ + +TPM_RESULT TPM_PermanentAll_NVStore(tpm_state_t *tpm_state, + TPM_BOOL writeAllNV, + TPM_RESULT rcIn) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + TPM_NV_DATA_ST *tpm_nv_data_st = NULL; /* array of saved NV index volatile flags */ + + printf(" TPM_PermanentAll_NVStore: write flag %u\n", writeAllNV); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + if (writeAllNV) { + if (rcIn == TPM_SUCCESS) { + /* serialize state to be written to NV */ + if (rc == 0) { + rc = TPM_PermanentAll_Store(&sbuffer, + &buffer, &length, + tpm_state); + } + /* validate the length of the stream against the maximum provided NV space */ + if (rc == 0) { + printf(" TPM_PermanentAll_NVStore: Require %u bytes\n", length); + if (length > TPM_MAX_NV_SPACE) { + printf("TPM_PermanentAll_NVStore: Error, No space, need %u max %u\n", + length, TPM_MAX_NV_SPACE); + rc = TPM_NOSPACE; + } + } + /* store the buffer in NVRAM */ + if (rc == 0) { + rc = TPM_NVRAM_StoreData(buffer, + length, + tpm_state->tpm_number, + TPM_PERMANENT_ALL_NAME); + } + if (rc != 0) { + printf("TPM_PermanentAll_NVStore: Error (fatal), " + "NV structure in-memory caches are in invalid state\n"); + rc = TPM_FAIL; + } + } + else { + /* An in-memory structure was altered, but the ordinal had a subsequent error. Since + the structure is in an invalid state, roll back to the previous value by reading the + NV file. */ + printf(" TPM_PermanentAll_NVStore: Ordinal error, " + "rolling back NV structure cache\n"); + /* Save a copy of the NV defined space volatile state. It is not stored in NV, so it + will be destroyed during the rollback. */ + /* get a copy of the NV volatile flags, to be used during a rollback */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetVolatile(&tpm_nv_data_st, /* freed @2 */ + &(tpm_state->tpm_nv_index_entries)); + } + /* Returns TPM_RETRY on non-existent file */ + if (rc == 0) { + printf(" TPM_PermanentAllNVStore: Deleting TPM_PERMANENT_DATA structure\n"); + TPM_PermanentData_Delete(&(tpm_state->tpm_permanent_data), TRUE); + printf(" TPM_PermanentAllNVStore: Deleting owner evict keys\n"); + TPM_KeyHandleEntries_OwnerEvictDelete(tpm_state->tpm_key_handle_entries); + printf(" TPM_PermanentAllNVStore: Deleting NV defined space \n"); + TPM_NVIndexEntries_Delete(&(tpm_state->tpm_nv_index_entries)); + printf(" TPM_PermanentAllNVStore: " + "Rereading TPM_PERMANENT_DATA, TPM_PERMANENT_FLAGS, owner evict keys\n"); + /* re-allocate TPM_PERMANENT_DATA data structures */ + rc = TPM_PermanentData_Init(&(tpm_state->tpm_permanent_data), TRUE); + } + if (rc == 0) { + rc = TPM_PermanentAll_NVLoad(tpm_state); + } + if (rc == 0) { + rc = TPM_NVIndexEntries_SetVolatile(tpm_nv_data_st, + &(tpm_state->tpm_nv_index_entries)); + } + /* after a successful rollback, return the ordinal's original error code */ + if (rc == 0) { + rc = rcIn; + } + /* a failure during rollback is fatal */ + else { + printf("TPM_PermanentAll_NVStore: Error (fatal), " + "Permanent Data, Flags, or owner evict keys structure is invalid\n"); + rc = TPM_FAIL; + } + + } + } + /* no write required, no-op */ + else { + rc = rcIn; + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + free(tpm_nv_data_st); /* @2 */ + return rc; +} + +/* TPM_PermanentAll_NVDelete() deletes ann NV data in the NV file TPM_PERMANENT_ALL_NAME. + + If mustExist is TRUE, returns an error if the file does not exist. + + It does not delete the in-memory copy. +*/ + +TPM_RESULT TPM_PermanentAll_NVDelete(uint32_t tpm_number, + TPM_BOOL mustExist) +{ + TPM_RESULT rc = 0; + + printf(" TPM_PermanentAll_NVDelete:\n"); + /* remove the NVRAM file */ + if (rc == 0) { + rc = TPM_NVRAM_DeleteName(tpm_number, + TPM_PERMANENT_ALL_NAME, + mustExist); + } + return rc; +} + +/* TPM_PermanentAll_IsSpace() determines if there is enough NV space for the serialized NV state. + + It does this by serializing the entire state and comparing the length to the configured maximum. +*/ + +TPM_RESULT TPM_PermanentAll_IsSpace(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + + printf("TPM_PermanentAll_IsSpace :\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + if (rc == 0) { + rc = TPM_PermanentAll_Store(&sbuffer, + &buffer, &length, + tpm_state); + } + if (rc == 0) { + printf(" TPM_PermanentAll_IsSpace: Require %u bytes\n", length); + if (length > TPM_MAX_NV_SPACE) { + printf("TPM_PermanentAll_IsSpace: No space, need %u max %u\n", + length, TPM_MAX_NV_SPACE); + rc = TPM_NOSPACE; + } + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_PermanentAll_GetSpace() returns the NV free space. + + It does this by serializing the entire state and comparing the length to the configured maximum. +*/ + +TPM_RESULT TPM_PermanentAll_GetSpace(uint32_t *bytes_free, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_NVRAM_IsSpace:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + if (rc == 0) { + rc = TPM_PermanentAll_Store(&sbuffer, + &buffer, &length, + tpm_state); + } + if (rc == 0) { + printf(" TPM_PermanentAll_GetSpace: Used %u max %u bytes\n", length, TPM_MAX_NV_SPACE); + if (length > TPM_MAX_NV_SPACE) { + /* This should never occur */ + printf("TPM_PermanentAll_GetSpace: Error (fatal) Used more than maximum\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + *bytes_free = TPM_MAX_NV_SPACE - length; + printf(" TPM_PermanentAll_GetSpace: Free space %u\n", *bytes_free); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + diff --git a/src/tpm_permanent.h b/src/tpm_permanent.h new file mode 100644 index 00000000..2d95acb8 --- /dev/null +++ b/src/tpm_permanent.h @@ -0,0 +1,108 @@ +/********************************************************************************/ +/* */ +/* Permanent Flag and Data Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_permanent.h 4623 2011-09-28 15:15:09Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_PERMANENT_H +#define TPM_PERMANENT_H + +#include "tpm_global.h" +#include "tpm_structures.h" + + +/* + TPM_PERMANENT_FLAGS +*/ + +void TPM_PermanentFlags_Init(TPM_PERMANENT_FLAGS *tpm_permanent_flags); +TPM_RESULT TPM_PermanentFlags_Load(TPM_PERMANENT_FLAGS *tpm_permanent_flags, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PermanentFlags_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags); +TPM_RESULT TPM_PermanentFlags_LoadBitmap(TPM_PERMANENT_FLAGS *tpm_permanent_flags, + TPM_TAG permanentFlagsVersion, + uint32_t tpm_bitmap); +TPM_RESULT TPM_PermanentFlags_StoreBitmap(uint32_t *tpm_bitmap, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags); +TPM_RESULT TPM_PermanentFlags_StoreBytes(TPM_STORE_BUFFER *sbuffer, + const TPM_PERMANENT_FLAGS *tpm_permanent_flags); + +/* + TPM_PERMANENT_DATA +*/ + +TPM_RESULT TPM_PermanentData_Init(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData); +TPM_RESULT TPM_PermanentData_Load(TPM_PERMANENT_DATA *tpm_permanent_data, + unsigned char **stream, + uint32_t *stream_size, + TPM_BOOL instanceData); +TPM_RESULT TPM_PermanentData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData); +void TPM_PermanentData_Delete(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData); +void TPM_PermanentData_Zero(TPM_PERMANENT_DATA *tpm_permanent_data, + TPM_BOOL instanceData); + +TPM_RESULT TPM_PermanentData_InitDaa(TPM_PERMANENT_DATA *tpm_permanent_data); + +/* + PermanentAll is TPM_PERMANENT_DATA plus TPM_PERMANENT_FLAGS +*/ + +TPM_RESULT TPM_PermanentAll_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_PermanentAll_Store(TPM_STORE_BUFFER *sbuffer, + const unsigned char **buffer, + uint32_t *length, + tpm_state_t *tpm_state); + +TPM_RESULT TPM_PermanentAll_NVLoad(tpm_state_t *tpm_state); +TPM_RESULT TPM_PermanentAll_NVStore(tpm_state_t *tpm_state, + TPM_BOOL writeAllNV, + TPM_RESULT rcIn); +TPM_RESULT TPM_PermanentAll_NVDelete(uint32_t tpm_number, + TPM_BOOL mustExist); + +TPM_RESULT TPM_PermanentAll_IsSpace(tpm_state_t *tpm_state); +TPM_RESULT TPM_PermanentAll_GetSpace(uint32_t *bytes_free, + tpm_state_t *tpm_state); + +#endif diff --git a/src/tpm_platform.c b/src/tpm_platform.c new file mode 100644 index 00000000..16da5dba --- /dev/null +++ b/src/tpm_platform.c @@ -0,0 +1,175 @@ +/********************************************************************************/ +/* */ +/* TPM Platform I/O */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_platform.c 4621 2011-09-09 20:19:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_debug.h" +#include "tpm_pcr.h" +#include "tpm_platform.h" + +#ifdef TPM_LIBTPMS_CALLBACKS +#include "tpm_library_intern.h" +#endif + +#ifndef TPM_IO_LOCALITY + +/* TPM_IO_GetLocality() is platform specific code to set the localityModifier before an ordinal is + processed. + + Place holder, to be modified for the platform. +*/ + +TPM_RESULT TPM_IO_GetLocality(TPM_MODIFIER_INDICATOR *localityModifier, + uint32_t tpm_number) +{ + TPM_RESULT rc = 0; + +#ifdef TPM_LIBTPMS_CALLBACKS + struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); + + /* call user-provided function if available, otherwise execute + default behavior */ + if (cbs->tpm_io_getlocality) { + rc = cbs->tpm_io_getlocality(localityModifier, tpm_number); + return rc; + } +#else + tpm_number = tpm_number; /* to silence the compiler */ +#endif + + if (rc == 0) { + *localityModifier = 0; + printf(" TPM_IO_GetLocality: localityModifier %u\n", *localityModifier); + rc = TPM_LocalityModifier_CheckLegal(*localityModifier); + } + return rc; +} + +#endif /* TPM_IO_LOCALITY */ + +#ifndef TPM_IO_PHYSICAL_PRESENCE + +/* TPM_IO_GetPhysicalPresence() is platform specific code to get the hardware physicalPresence + state. + + Place holder, to be modified for the platform. +*/ + +TPM_RESULT TPM_IO_GetPhysicalPresence(TPM_BOOL *physicalPresence, + uint32_t tpm_number) +{ + TPM_RESULT rc = 0; + +#ifdef TPM_LIBTPMS_CALLBACKS + struct libtpms_callbacks *cbs = TPMLIB_GetCallbacks(); + + /* call user-provided function if available, otherwise execute + default behavior */ + if (cbs->tpm_io_getphysicalpresence) { + rc = cbs->tpm_io_getphysicalpresence(physicalPresence, tpm_number); + return rc; + } +#else + tpm_number = tpm_number; /* to silence the compiler */ +#endif + *physicalPresence = FALSE; + return rc; +} + +#endif /* TPM_IO_PHYSICAL_PRESENCE */ + +#ifndef TPM_IO_GPIO + +/* TPM_IO_GPIO_Write() should write 'dataSize' bytes of 'data' to 'nvIndex' at the GPIO port. + + Place holder, to be modified for the platform. +*/ + +TPM_RESULT TPM_IO_GPIO_Write(TPM_NV_INDEX nvIndex, + uint32_t dataSize, + BYTE *data, + uint32_t tpm_number) +{ + TPM_RESULT rc = 0; + tpm_number = tpm_number; /* to silence the compiler */ + +#if defined TPM_PCCLIENT /* These values are from the PC Client specification */ + printf(" TPM_IO_GPIO_Write: nvIndex %08x\n", nvIndex); + TPM_PrintAll(" TPM_IO_GPIO_Write: Stub", data, dataSize); + /* #elif Add other platform specific values here */ +#else /* This is the default case for the main specification */ + nvIndex = nvIndex; /* unused parameter, to quiet the compiler */ + dataSize = dataSize; + data = data; + printf("TPM_IO_GPIO_Write: Error (fatal), platform does not support GPIO\n"); + rc = TPM_FAIL; /* Should never get here. The invalid address be detected earlier */ +#endif + return rc; +} + +/* TPM_IO_GPIO_Read() + + Place holder, to be modified for the platform. +*/ + +TPM_RESULT TPM_IO_GPIO_Read(TPM_NV_INDEX nvIndex, + uint32_t dataSize, + BYTE *data, + uint32_t tpm_number) +{ + TPM_RESULT rc = 0; + tpm_number = tpm_number; /* to silence the compiler */ + +#if defined TPM_PCCLIENT /* These values are from the PC Client specification */ + printf(" TPM_IO_GPIO_Read: nvIndex %08x\n", nvIndex); + memset(data, 0, dataSize); + /* #elif Add other platform specific values here */ +#else /* This is the default case for the main specification */ + nvIndex = nvIndex;; /* unused parameter, to quiet the compiler */ + dataSize = dataSize;; + data = data; + printf("TPM_IO_GPIO_Read: Error (fatal), platform does not support GPIO\n"); + rc = TPM_FAIL; /* Should never get here. The invalid address be detected earlier */ +#endif + return rc; +} + +#endif /* TPM_IO_GPIO */ + diff --git a/src/tpm_platform.h b/src/tpm_platform.h new file mode 100644 index 00000000..94036e01 --- /dev/null +++ b/src/tpm_platform.h @@ -0,0 +1,64 @@ +/********************************************************************************/ +/* */ +/* TPM Platform I/O */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_platform.h 4621 2011-09-09 20:19:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +/* Interface independent platform I/O Functions */ + +#ifndef TPM_PLATFORM_H +#define TPM_PLATFORM_H + +#include "tpm_types.h" + +/* Every platform will need this function, as TPM_MainInit() calls it. */ + +TPM_RESULT TPM_IO_Init(void); + +TPM_RESULT TPM_IO_GetLocality(TPM_MODIFIER_INDICATOR *localityModifier, + uint32_t tpm_number); +TPM_RESULT TPM_IO_GetPhysicalPresence(TPM_BOOL *physicalPresence, + uint32_t tpm_number); +TPM_RESULT TPM_IO_GPIO_Write(TPM_NV_INDEX nvIndex, + uint32_t dataSize, + BYTE *data, + uint32_t tpm_number); +TPM_RESULT TPM_IO_GPIO_Read(TPM_NV_INDEX nvIndex, + uint32_t dataSize, + BYTE *data, + uint32_t tpm_number); + +#endif diff --git a/src/tpm_process.c b/src/tpm_process.c new file mode 100644 index 00000000..87ad9f8a --- /dev/null +++ b/src/tpm_process.c @@ -0,0 +1,6051 @@ +/********************************************************************************/ +/* */ +/* TPM Command Processor */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_process.c 4621 2011-09-09 20:19:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 + +#ifdef TPM_POSIX +#include +#include +#endif + +#include "tpm_admin.h" +#include "tpm_audit.h" +#include "tpm_auth.h" +#include "tpm_constants.h" +#include "tpm_commands.h" +#include "tpm_counter.h" +#include "tpm_cryptoh.h" +#include "tpm_crypto.h" +#include "tpm_daa.h" +#include "tpm_debug.h" +#include "tpm_delegate.h" +#include "tpm_error.h" +#include "tpm_identity.h" +#include "tpm_init.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_maint.h" +#include "tpm_memory.h" +#include "tpm_migration.h" +#include "tpm_nonce.h" +#include "tpm_nvram.h" +#include "tpm_owner.h" +#include "tpm_pcr.h" +#include "tpm_permanent.h" +#include "tpm_platform.h" +#include "tpm_session.h" +#include "tpm_sizedbuffer.h" +#include "tpm_startup.h" +#include "tpm_storage.h" +#include "tpm_ticks.h" +#include "tpm_transport.h" +#include "tpm_ver.h" + +#include "tpm_process.h" + +/* local prototypes */ + +/* get capabilities */ + +static TPM_RESULT TPM_GetCapability_CapOrd(TPM_STORE_BUFFER *capabilityResponse, + uint32_t ordinal); +static TPM_RESULT TPM_GetCapability_CapAlg(TPM_STORE_BUFFER *capabilityResponse, + uint32_t algorithmID); +static TPM_RESULT TPM_GetCapability_CapPid(TPM_STORE_BUFFER *capabilityResponse, + uint16_t protocolID); +static TPM_RESULT TPM_GetCapability_CapFlag(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t capFlag); +static TPM_RESULT TPM_GetCapability_CapProperty(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t capProperty); +static TPM_RESULT TPM_GetCapability_CapVersion(TPM_STORE_BUFFER *capabilityResponse); +static TPM_RESULT TPM_GetCapability_CapCheckLoaded(TPM_STORE_BUFFER *capabilityResponse, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry, + TPM_SIZED_BUFFER *subCap); +static TPM_RESULT TPM_GetCapability_CapSymMode(TPM_STORE_BUFFER *capabilityResponse, + TPM_SYM_MODE symMode); +static TPM_RESULT TPM_GetCapability_CapKeyStatus(TPM_STORE_BUFFER *capabilityResponse, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + uint32_t tpm_key_handle); +static TPM_RESULT TPM_GetCapability_CapMfr(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_SIZED_BUFFER *subCap); +static TPM_RESULT TPM_GetCapability_CapNVIndex(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t nvIndex); +static TPM_RESULT TPM_GetCapability_CapTransAlg(TPM_STORE_BUFFER *capabilityResponse, + TPM_ALGORITHM_ID algorithmID); +static TPM_RESULT TPM_GetCapability_CapHandle(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_RESOURCE_TYPE resourceType); +static TPM_RESULT TPM_GetCapability_CapTransEs(TPM_STORE_BUFFER *capabilityResponse, + TPM_ENC_SCHEME encScheme); +static TPM_RESULT TPM_GetCapability_CapAuthEncrypt(TPM_STORE_BUFFER *capabilityResponse, + uint32_t algorithmID); +static TPM_RESULT TPM_GetCapability_CapSelectSize(TPM_STORE_BUFFER *capabilityResponse, + TPM_SIZED_BUFFER *subCap); +#if (TPM_REVISION >= 103) /* added for rev 103 */ +static TPM_RESULT TPM_GetCapability_CapDaLogic(TPM_STORE_BUFFER *capabilityResponse, + TPM_SIZED_BUFFER *subCap, + tpm_state_t *tpm_state); +#endif +static TPM_RESULT TPM_GetCapability_CapVersionVal(TPM_STORE_BUFFER *capabilityResponse, + TPM_PERMANENT_DATA *tpm_permanent_data); + +static TPM_RESULT TPM_GetCapability_CapPropTisTimeout(TPM_STORE_BUFFER *capabilityResponse); +static TPM_RESULT TPM_GetCapability_CapPropDuration(TPM_STORE_BUFFER *capabilityResponse); + +/* set capabilities */ + +static TPM_RESULT TPM_SetCapability_CapPermFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool); +static TPM_RESULT TPM_SetCapability_CapPermData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + uint32_t valueUint32); +static TPM_RESULT TPM_SetCapability_CapStclearFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool); +static TPM_RESULT TPM_SetCapability_CapStclearData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + uint32_t valueUint32); +static TPM_RESULT TPM_SetCapability_CapStanyFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool); +static TPM_RESULT TPM_SetCapability_CapStanyData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_SIZED_BUFFER *setValue); +static TPM_RESULT TPM_SetCapability_CapVendor(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_SIZED_BUFFER *setValue); + +/* + TPM_CAP_VERSION_INFO +*/ + +/* TPM_CapVersionInfo_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_CapVersionInfo_Init(TPM_CAP_VERSION_INFO *tpm_cap_version_info) +{ + printf(" TPM_CapVersionInfo_Init:\n"); + TPM_Version_Init(&(tpm_cap_version_info->version)); + tpm_cap_version_info->specLevel = TPM_SPEC_LEVEL; + tpm_cap_version_info->errataRev = TPM_ERRATA_REV; + memcpy(&(tpm_cap_version_info->tpmVendorID), TPM_VENDOR_ID, + sizeof(tpm_cap_version_info->tpmVendorID)); + tpm_cap_version_info->vendorSpecificSize = 0; + tpm_cap_version_info->vendorSpecific = NULL; + return; +} + +/* TPM_CapVersionInfo_Set() sets members to software specific data */ + +void TPM_CapVersionInfo_Set(TPM_CAP_VERSION_INFO *tpm_cap_version_info, + TPM_PERMANENT_DATA *tpm_permanent_data) +{ + printf(" TPM_CapVersionInfo_Set:\n"); + TPM_Version_Set(&(tpm_cap_version_info->version), tpm_permanent_data); + tpm_cap_version_info->specLevel = TPM_SPEC_LEVEL; + tpm_cap_version_info->errataRev = TPM_ERRATA_REV; + memcpy(&(tpm_cap_version_info->tpmVendorID), TPM_VENDOR_ID, + sizeof(tpm_cap_version_info->tpmVendorID)); + tpm_cap_version_info->vendorSpecificSize = 0; + tpm_cap_version_info->vendorSpecific = NULL; + return; +} + +#if 0 /* not required */ +/* TPM_CapVersionInfo_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CapVersionInfo_Init() or TPM_CapVersionInfo_Set() + After use, call TPM_CapVersionInfo_Delete() to free memory +*/ + +TPM_RESULT TPM_CapVersionInfo_Load(TPM_CAP_VERSION_INFO *tpm_cap_version_info, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CapVersionInfo_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CAP_VERSION_INFO, stream, stream_size); + } + /* load version */ + if (rc == 0) { + rc = TPM_Version_Load(&(tpm_cap_version_info->version), stream, stream_size); + } + /* load specLevel */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_cap_version_info->specLevel), stream, stream_size); + } + /* load errataRev */ + if (rc == 0) { + rc = TPM_Loadn(&(tpm_cap_version_info->errataRev), sizeof(tpm_cap_version_info->errataRev), + stream, stream_size); + } + /* load tpmVendorID */ + if (rc == 0) { + rc = TPM_Loadn(tpm_cap_version_info->tpmVendorID, sizeof(tpm_cap_version_info->tpmVendorID), + stream, stream_size); + } + /* load vendorSpecificSize */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_cap_version_info->vendorSpecificSize), stream, stream_size); + } + /* allocate memory for vendorSpecific */ + if ((rc == 0) && (tpm_cap_version_info->vendorSpecificSize > 0)) { + rc = TPM_Malloc(&(tpm_cap_version_info->vendorSpecific), + tpm_cap_version_info->vendorSpecificSize); + } + /* load vendorSpecific */ + if ((rc == 0) && (tpm_cap_version_info->vendorSpecificSize > 0)) { + rc = TPM_Loadn(tpm_cap_version_info->vendorSpecific, + tpm_cap_version_info->vendorSpecificSize, + stream, stream_size); + } + return rc; +} +#endif + +/* TPM_CapVersionInfo_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CapVersionInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CAP_VERSION_INFO *tpm_cap_version_info) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CapVersionInfo_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CAP_VERSION_INFO); + } + /* store version */ + if (rc == 0) { + rc = TPM_Version_Store(sbuffer, &(tpm_cap_version_info->version)); + } + /* store specLevel */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_cap_version_info->specLevel); + } + /* store errataRev */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_cap_version_info->errataRev), + sizeof(tpm_cap_version_info->errataRev)); + } + /* store tpmVendorID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_cap_version_info->tpmVendorID, + sizeof(tpm_cap_version_info->tpmVendorID)); + } + /* store vendorSpecificSize */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_cap_version_info->vendorSpecificSize); + } + /* store vendorSpecific */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, + tpm_cap_version_info->vendorSpecific, + tpm_cap_version_info->vendorSpecificSize); + } + return rc; +} + +/* TPM_CapVersionInfo_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_CapVersionInfo_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_CapVersionInfo_Delete(TPM_CAP_VERSION_INFO *tpm_cap_version_info) +{ + printf(" TPM_CapVersionInfo_Delete:\n"); + if (tpm_cap_version_info != NULL) { + free(tpm_cap_version_info->vendorSpecific); + TPM_CapVersionInfo_Init(tpm_cap_version_info); + } + return; +} + +/* + Processing Commands +*/ + + +/* 17. Ordinals rev 107 + + This structure maps the specification Ordinals table to software functions and parameters. + + It provides direct mapping that easier to understand and maintain than scattering and hard coding + these values. + + The functions currently supported are: + + - processing jump table for 1.1 and 1.2 (implied get capability - ordinals supported) + - allow audit + - audit default value + - owner delegation permissions + - key delegation permissions + - wrappable + + Future possibilities include: + + - no owner, disabled, deactivated + - 0,1,2 auth + + typedef struct tdTPM_ORDINAL_TABLE { + + TPM_COMMAND_CODE ordinal; + tpm_process_function_t process_function_v11; + tpm_process_function_t process_function_v12; + TPM_BOOL auditable; + TPM_BOOL auditDefault; + uint16_t ownerPermissionBlock; + uint32_t ownerPermissionPosition; + uint16_t keyPermissionBlock; + uint32_t keyPermissionPosition; + uint32_t inputHandleSize; + uint32_t keyHandles; + uint32_t outputHandleSize; + TPM_BOOL transportWrappable; + TPM_BOOL instanceWrappable; + TPM_BOOL hardwareWrappable; + } TPM_ORDINAL_TABLE; +*/ + +static TPM_ORDINAL_TABLE tpm_ordinal_table[] = +{ + {TPM_ORD_ActivateIdentity, + TPM_Process_ActivateIdentity, TPM_Process_ActivateIdentity, + TRUE, + TRUE, + 1, TPM_DELEGATE_ActivateIdentity, + 1, TPM_KEY_DELEGATE_ActivateIdentity, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_AuthorizeMigrationKey, + TPM_Process_AuthorizeMigrationKey, TPM_Process_AuthorizeMigrationKey, + TRUE, + TRUE, + 1, TPM_DELEGATE_AuthorizeMigrationKey, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CertifyKey, + TPM_Process_CertifyKey, TPM_Process_CertifyKey, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_CertifyKey, + sizeof(TPM_KEY_HANDLE) + sizeof(TPM_KEY_HANDLE), + 2, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CertifyKey2, + TPM_Process_Unused, TPM_Process_CertifyKey2, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_CertifyKey2, + sizeof(TPM_KEY_HANDLE) + sizeof(TPM_KEY_HANDLE), + 2, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CertifySelfTest, + TPM_Process_CertifySelfTest, TPM_Process_Unused, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ChangeAuth, + TPM_Process_ChangeAuth, TPM_Process_ChangeAuth, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_ChangeAuth, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ChangeAuthAsymFinish, + TPM_Process_ChangeAuthAsymFinish, TPM_Process_ChangeAuthAsymFinish, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_ChangeAuthAsymFinish, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ChangeAuthAsymStart, + TPM_Process_ChangeAuthAsymStart, TPM_Process_ChangeAuthAsymStart, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_ChangeAuthAsymStart, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ChangeAuthOwner, + TPM_Process_ChangeAuthOwner, TPM_Process_ChangeAuthOwner, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_ApproveMA, + TPM_Process_Unused, TPM_Process_CMK_ApproveMA, + TRUE, + FALSE, + 1, TPM_DELEGATE_CMK_ApproveMA, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_ConvertMigration, + TPM_Process_Unused, TPM_Process_CMK_ConvertMigration, + TRUE, + FALSE, + 1, TPM_KEY_DELEGATE_CMK_ConvertMigration, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_CreateBlob, + TPM_Process_Unused, TPM_Process_CMK_CreateBlob, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_CMK_CreateBlob, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_CreateKey, + TPM_Process_Unused, TPM_Process_CMK_CreateKey, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_CMK_CreateKey, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_CreateTicket, + TPM_Process_Unused, TPM_Process_CMK_CreateTicket, + TRUE, + FALSE, + 1, TPM_DELEGATE_CMK_CreateTicket, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CMK_SetRestrictions, + TPM_Process_Unused, TPM_Process_CMK_SetRestrictions, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ContinueSelfTest, + TPM_Process_ContinueSelfTest, TPM_Process_ContinueSelfTest, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ConvertMigrationBlob, + TPM_Process_ConvertMigrationBlob, TPM_Process_ConvertMigrationBlob, + TRUE, + TRUE, + 0, 0, + 1, TPM_KEY_DELEGATE_ConvertMigrationBlob, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CreateCounter, + TPM_Process_Unused, TPM_Process_CreateCounter, + TRUE, + FALSE, + 1, TPM_DELEGATE_CreateCounter, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CreateEndorsementKeyPair, + TPM_Process_CreateEndorsementKeyPair, TPM_Process_CreateEndorsementKeyPair, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_CreateMaintenanceArchive, +#ifdef TPM_NOMAINTENANCE + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, +#else + TPM_Process_CreateMaintenanceArchive, TPM_Process_CreateMaintenanceArchive, + TRUE, + TRUE, +#endif + 1, TPM_DELEGATE_CreateMaintenanceArchive, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CreateMigrationBlob, + TPM_Process_CreateMigrationBlob, TPM_Process_CreateMigrationBlob, + TRUE, + TRUE, + 0, 0, + 1, TPM_KEY_DELEGATE_CreateMigrationBlob, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CreateRevocableEK, + TPM_Process_Unused, TPM_Process_CreateRevocableEK, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_CreateWrapKey, + TPM_Process_CreateWrapKey, TPM_Process_CreateWrapKey, + TRUE, + TRUE, + 0, 0, + 1, TPM_KEY_DELEGATE_CreateWrapKey, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DAA_Join, + TPM_Process_Unused, TPM_Process_DAAJoin, + TRUE, + FALSE, + 1, TPM_DELEGATE_DAA_Join, + 0, 0, + sizeof(TPM_HANDLE), + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DAA_Sign, + TPM_Process_Unused, TPM_Process_DAASign, + TRUE, + FALSE, + 1, TPM_DELEGATE_DAA_Sign, + 0, 0, + sizeof(TPM_HANDLE), + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_CreateKeyDelegation, + TPM_Process_Unused, TPM_Process_DelegateCreateKeyDelegation, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Delegate_CreateKeyDelegation, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_CreateOwnerDelegation, + TPM_Process_Unused, TPM_Process_DelegateCreateOwnerDelegation, + TRUE, + FALSE, + 1, TPM_DELEGATE_Delegate_CreateOwnerDelegation, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_LoadOwnerDelegation, + TPM_Process_Unused, TPM_Process_DelegateLoadOwnerDelegation, + TRUE, + FALSE, + 1, TPM_DELEGATE_Delegate_LoadOwnerDelegation, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_Manage, + TPM_Process_Unused, TPM_Process_DelegateManage, + TRUE, + FALSE, + 1, TPM_DELEGATE_Delegate_Manage, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_ReadTable, + TPM_Process_Unused, TPM_Process_DelegateReadTable, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_UpdateVerification, + TPM_Process_Unused, TPM_Process_DelegateUpdateVerification, + TRUE, + FALSE, + 1, TPM_DELEGATE_Delegate_UpdateVerification, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Delegate_VerifyDelegation, + TPM_Process_Unused, TPM_Process_DelegateVerifyDelegation, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DirRead, + TPM_Process_DirRead, TPM_Process_DirRead, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DirWriteAuth, + TPM_Process_DirWriteAuth, TPM_Process_DirWriteAuth, + TRUE, + FALSE, + 1, TPM_DELEGATE_DirWriteAuth, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DisableForceClear, + TPM_Process_DisableForceClear, TPM_Process_DisableForceClear, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DisableOwnerClear, + TPM_Process_DisableOwnerClear, TPM_Process_DisableOwnerClear, + TRUE, + TRUE, + 1, TPM_DELEGATE_DisableOwnerClear, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DisablePubekRead, + TPM_Process_DisablePubekRead, TPM_Process_DisablePubekRead, + TRUE, + TRUE, + 1, TPM_DELEGATE_DisablePubekRead, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_DSAP, + TPM_Process_Unused, TPM_Process_DSAP, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_ENTITY_TYPE) + sizeof(TPM_KEY_HANDLE) + TPM_NONCE_SIZE + sizeof(uint32_t), + 0xffffffff, + sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE + TPM_NONCE_SIZE, + TRUE, + TRUE, + TRUE}, + + {TPM_ORD_EstablishTransport, + TPM_Process_Unused, TPM_Process_EstablishTransport, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_EstablishTransport, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + FALSE, + FALSE, + FALSE}, + + {TPM_ORD_EvictKey, + TPM_Process_EvictKey, TPM_Process_EvictKey, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ExecuteTransport, + TPM_Process_Unused, TPM_Process_ExecuteTransport, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + FALSE, + FALSE, + FALSE}, + + {TPM_ORD_Extend, + TPM_Process_Extend, TPM_Process_Extend, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_FieldUpgrade, + TPM_Process_Unused, TPM_Process_Unused, + TRUE, + FALSE, + 1, TPM_DELEGATE_FieldUpgrade, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_FlushSpecific, + TPM_Process_Unused, TPM_Process_FlushSpecific, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_HANDLE), + 0xffffffff, + 0, + TRUE, + TRUE, + TRUE}, + + {TPM_ORD_ForceClear, + TPM_Process_ForceClear, TPM_Process_ForceClear, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetAuditDigest, + TPM_Process_Unused, TPM_Process_GetAuditDigest, + FALSE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetAuditDigestSigned, + TPM_Process_Unused, TPM_Process_GetAuditDigestSigned, + FALSE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_GetAuditDigestSigned, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetAuditEvent, + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetAuditEventSigned, + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetCapability, + TPM_Process_GetCapability, TPM_Process_GetCapability, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_GetCapabilityOwner, + TPM_Process_GetCapabilityOwner, TPM_Process_GetCapabilityOwner, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetCapabilitySigned, + TPM_Process_GetCapabilitySigned, TPM_Process_Unused, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetOrdinalAuditStatus, + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetPubKey, + TPM_Process_GetPubKey, TPM_Process_GetPubKey, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_GetPubKey, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetRandom, + TPM_Process_GetRandom, TPM_Process_GetRandom, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetTestResult, + TPM_Process_GetTestResult, TPM_Process_GetTestResult, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_GetTicks, + TPM_Process_Unused, TPM_Process_GetTicks, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_IncrementCounter, + TPM_Process_Unused, TPM_Process_IncrementCounter, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Init, + TPM_Process_Init, TPM_Process_Init, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_KeyControlOwner, + TPM_Process_Unused, TPM_Process_KeyControlOwner, + TRUE, + FALSE, + 1, TPM_DELEGATE_KeyControlOwner, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_KillMaintenanceFeature, +#ifdef TPM_NOMAINTENANCE + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, +#else + TPM_Process_KillMaintenanceFeature, TPM_Process_KillMaintenanceFeature, + TRUE, + TRUE, +#endif + 1, TPM_DELEGATE_KillMaintenanceFeature, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadAuthContext, + TPM_Process_LoadAuthContext, TPM_Process_LoadAuthContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + sizeof(TPM_HANDLE), + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadContext, + TPM_Process_Unused, TPM_Process_LoadContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_HANDLE), + 0, + sizeof(TPM_HANDLE), + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_LoadKey, + TPM_Process_LoadKey, TPM_Process_LoadKey, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_LoadKey, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadKey2, + TPM_Process_Unused, TPM_Process_LoadKey2, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_LoadKey2, + sizeof(TPM_KEY_HANDLE), + 1, + sizeof(TPM_KEY_HANDLE), + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadKeyContext, + TPM_Process_LoadKeyContext, TPM_Process_LoadKeyContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + sizeof(TPM_KEY_HANDLE), + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadMaintenanceArchive, +#ifdef TPM_NOMAINTENANCE + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, +#else + TPM_Process_LoadMaintenanceArchive, TPM_Process_LoadMaintenanceArchive, + TRUE, + TRUE, +#endif + 1, TPM_DELEGATE_LoadMaintenanceArchive, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_LoadManuMaintPub, +#ifdef TPM_NOMAINTENANCE + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, +#else + TPM_Process_LoadManuMaintPub, TPM_Process_LoadManuMaintPub, + TRUE, + TRUE, +#endif + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_MakeIdentity, + TPM_Process_MakeIdentity, TPM_Process_MakeIdentity, + TRUE, + TRUE, + 1, TPM_DELEGATE_MakeIdentity, + 1, TPM_KEY_DELEGATE_MakeIdentity, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_MigrateKey, + TPM_Process_Unused, TPM_Process_MigrateKey, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_MigrateKey, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_NV_DefineSpace, + TPM_Process_Unused, TPM_Process_NVDefineSpace, + TRUE, + FALSE, + 1, TPM_DELEGATE_NV_DefineSpace, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_NV_ReadValue, + TPM_Process_Unused, TPM_Process_NVReadValue, + TRUE, + FALSE, + 1, TPM_DELEGATE_NV_ReadValue, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_NV_ReadValueAuth, + TPM_Process_Unused, TPM_Process_NVReadValueAuth, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_NV_WriteValue, + TPM_Process_Unused, TPM_Process_NVWriteValue, + TRUE, + FALSE, + 1, TPM_DELEGATE_NV_WriteValue, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_NV_WriteValueAuth, + TPM_Process_Unused, TPM_Process_NVWriteValueAuth, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_OIAP, + TPM_Process_OIAP, TPM_Process_OIAP, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE, + TRUE, + TRUE, + TRUE}, + + {TPM_ORD_OSAP, + TPM_Process_OSAP, TPM_Process_OSAP, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_ENTITY_TYPE) + sizeof(uint32_t) + TPM_NONCE_SIZE, + 0, /* TPM_OSAP: no input or output parameters are encrypted or logged */ + sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE + TPM_NONCE_SIZE, + TRUE, + TRUE, + TRUE}, + + {TPM_ORD_OwnerClear, + TPM_Process_OwnerClear, TPM_Process_OwnerClear, + TRUE, + TRUE, + 1, TPM_DELEGATE_OwnerClear, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_OwnerReadInternalPub, + TPM_Process_Unused, TPM_Process_OwnerReadInternalPub, + TRUE, + FALSE, + 1, TPM_DELEGATE_OwnerReadInternalPub, + 0, 0, + 0, + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_OwnerReadPubek, + TPM_Process_OwnerReadPubek, TPM_Process_OwnerReadPubek, + TRUE, + TRUE, + 1, TPM_DELEGATE_OwnerReadPubek, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_OwnerSetDisable, + TPM_Process_OwnerSetDisable, TPM_Process_OwnerSetDisable, + TRUE, + TRUE, + 1, TPM_DELEGATE_OwnerSetDisable, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_PCR_Reset, + TPM_Process_Unused, TPM_Process_PcrReset, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_PcrRead, + TPM_Process_PcrRead, TPM_Process_PcrRead, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_PhysicalDisable, + TPM_Process_PhysicalDisable, TPM_Process_PhysicalDisable, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_PhysicalEnable, + TPM_Process_PhysicalEnable, TPM_Process_PhysicalEnable, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_PhysicalSetDeactivated, + TPM_Process_PhysicalSetDeactivated, TPM_Process_PhysicalSetDeactivated, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_Quote, + TPM_Process_Quote, TPM_Process_Quote, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Quote, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + TRUE}, + + {TPM_ORD_Quote2, + TPM_Process_Unused, TPM_Process_Quote2, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Quote2, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + TRUE}, + + {TPM_ORD_ReadCounter, + TPM_Process_Unused, TPM_Process_ReadCounter, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ReadManuMaintPub, +#ifdef TPM_NOMAINTENANCE + TPM_Process_Unused, TPM_Process_Unused, + FALSE, + FALSE, +#else + TPM_Process_ReadManuMaintPub, TPM_Process_ReadManuMaintPub, + TRUE, + TRUE, +#endif + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ReadPubek, + TPM_Process_ReadPubek, TPM_Process_ReadPubek, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ReleaseCounter, + TPM_Process_Unused, TPM_Process_ReleaseCounter, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ReleaseCounterOwner, + TPM_Process_Unused, TPM_Process_ReleaseCounterOwner, + TRUE, + FALSE, + 1, TPM_DELEGATE_ReleaseCounterOwner, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ReleaseTransportSigned, + TPM_Process_Unused, TPM_Process_ReleaseTransportSigned, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_ReleaseTransportSigned, + 0, + 0, + 0, + FALSE, + FALSE, + FALSE}, + + {TPM_ORD_Reset, + TPM_Process_Reset, TPM_Process_Reset, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_ResetLockValue, + TPM_Process_Unused, TPM_Process_ResetLockValue, + TRUE, + FALSE, + 1, TPM_DELEGATE_ResetLockValue, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_RevokeTrust, + TPM_Process_Unused, TPM_Process_RevokeTrust, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SaveAuthContext, + TPM_Process_SaveAuthContext, TPM_Process_SaveAuthContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_AUTHHANDLE), + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SaveContext, + TPM_Process_Unused, TPM_Process_SaveContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_HANDLE), + 0xffffffff, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_SaveKeyContext, + TPM_Process_SaveKeyContext, TPM_Process_SaveKeyContext, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SaveState, + TPM_Process_SaveState, TPM_Process_SaveState, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_Seal, + TPM_Process_Seal, TPM_Process_Seal, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Seal, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Sealx, + TPM_Process_Unused, TPM_Process_Sealx, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Sealx, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SelfTestFull, + TPM_Process_SelfTestFull, TPM_Process_SelfTestFull, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetCapability, + TPM_Process_Unused, TPM_Process_SetCapability, + TRUE, + FALSE, + 1, TPM_DELEGATE_SetCapability, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_SetOperatorAuth, + TPM_Process_Unused, TPM_Process_SetOperatorAuth, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetOrdinalAuditStatus, + TPM_Process_SetOrdinalAuditStatus, TPM_Process_SetOrdinalAuditStatus, + TRUE, + TRUE, + 1, TPM_DELEGATE_SetOrdinalAuditStatus, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetOwnerInstall, + TPM_Process_SetOwnerInstall, TPM_Process_SetOwnerInstall, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetOwnerPointer, + TPM_Process_Unused, TPM_Process_SetOwnerPointer, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetRedirection, + TPM_Process_Unused, TPM_Process_Unused, + TRUE, + FALSE, + 1, TPM_DELEGATE_SetRedirection, + 0, 0, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SetTempDeactivated, + TPM_Process_SetTempDeactivated, TPM_Process_SetTempDeactivated, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SHA1Complete, + TPM_Process_SHA1Complete, TPM_Process_SHA1Complete, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SHA1CompleteExtend, + TPM_Process_SHA1CompleteExtend, TPM_Process_SHA1CompleteExtend, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SHA1Start, + TPM_Process_SHA1Start, TPM_Process_SHA1Start, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_SHA1Update, + TPM_Process_SHA1Update, TPM_Process_SHA1Update, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Sign, + TPM_Process_Sign, TPM_Process_Sign, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Sign, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Startup, + TPM_Process_Startup, TPM_Process_Startup, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TPM_ORD_StirRandom, + TPM_Process_StirRandom, TPM_Process_StirRandom, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_TakeOwnership, + TPM_Process_TakeOwnership, TPM_Process_TakeOwnership, + TRUE, + TRUE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Terminate_Handle, + TPM_Process_TerminateHandle, TPM_Process_TerminateHandle, + TRUE, + FALSE, + 0, 0, + 0, 0, + sizeof(TPM_AUTHHANDLE), + 0, + 0, + TRUE, + TRUE, + TRUE}, + + {TPM_ORD_TickStampBlob, + TPM_Process_Unused, TPM_Process_TickStampBlob, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_TickStampBlob, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_UnBind, + TPM_Process_UnBind, TPM_Process_UnBind, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_UnBind, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TPM_ORD_Unseal, + TPM_Process_Unseal, TPM_Process_Unseal, + TRUE, + FALSE, + 0, 0, + 1, TPM_KEY_DELEGATE_Unseal, + sizeof(TPM_KEY_HANDLE), + 1, + 0, + TRUE, + FALSE, + FALSE}, + + {TSC_ORD_PhysicalPresence, + TPM_Process_PhysicalPresence, TPM_Process_PhysicalPresence, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + TRUE, + FALSE}, + + {TSC_ORD_ResetEstablishmentBit, + TPM_Process_Unused, TPM_Process_ResetEstablishmentBit, + TRUE, + FALSE, + 0, 0, + 0, 0, + 0, + 0, + 0, + TRUE, + FALSE, + FALSE} + + + +}; + +/* + Ordinal Table Utilities +*/ + +/* TPM_OrdinalTable_GetEntry() gets the table entry for the ordinal. + + If the ordinal is not in the table, TPM_BAD_ORDINAL is returned +*/ + +TPM_RESULT TPM_OrdinalTable_GetEntry(TPM_ORDINAL_TABLE **entry, + TPM_ORDINAL_TABLE *ordinalTable, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = TPM_BAD_ORDINAL; + size_t i; + + /* printf(" TPM_OrdinalTable_GetEntry: Ordinal %08x\n", ordinal); */ + *entry = NULL; + for (i = 0 ; i < (sizeof(tpm_ordinal_table)/sizeof(TPM_ORDINAL_TABLE)) ; i++) { + if (ordinalTable[i].ordinal == ordinal) { /* if found */ + *entry = &(ordinalTable[i]); /* return the entry */ + rc = 0; /* return found */ + break; + } + } + return rc; +} + +/* TPM_OrdinalTable_GetProcessFunction() returns the processing function for the ordinal. + + If the ordinal is not in the table, the function TPM_Process_Unused() is returned. +*/ + +void TPM_OrdinalTable_GetProcessFunction(tpm_process_function_t *tpm_process_function, + TPM_ORDINAL_TABLE *ordinalTable, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_ORDINAL_TABLE *entry; + + printf(" TPM_OrdinalTable_GetProcessFunction: Ordinal %08x\n", ordinal); + + if (rc == 0) { + rc = TPM_OrdinalTable_GetEntry(&entry, ordinalTable, ordinal); + } + if (rc == 0) { /* if found */ +#ifdef TPM_V12 + *tpm_process_function = entry->process_function_v12; +#else + *tpm_process_function = entry->process_function_v11; +#endif + } + else { /* if not found, default processing function */ + *tpm_process_function = TPM_Process_Unused; + } + return; +} + +/* TPM_OrdinalTable_GetAuditable() determines whether the ordinal can ever be audited. + + Used by TPM_Process_SetOrdinalAuditStatus() +*/ + +void TPM_OrdinalTable_GetAuditable(TPM_BOOL *auditable, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_ORDINAL_TABLE *entry; + + printf(" TPM_OrdinalTable_GetAuditable: Ordinal %08x\n", ordinal); + if (rc == 0) { + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal); + } + /* if not found, unimplemented, not auditable */ + if (rc != 0) { + *auditable = FALSE; + } + /* if unimplemented, not auditable */ +#ifdef TPM_V12 + else if (entry->process_function_v12 == TPM_Process_Unused) { + *auditable = FALSE; + } +#else + else if (entry->process_function_v11 == TPM_Process_Unused) { + *auditable = FALSE; + } +#endif + /* if found an entry, use it */ + else { + *auditable = entry->auditable; + } + return; +} + +/* TPM_OrdinalTable_GetAuditDefault() determines whether the ordinal is audited by default. + + Used to initialize TPM_PERMANENT_DATA -> ordinalAuditStatus + + Returns FALSE if the ordinal is not in the ordinals table. +*/ + +void TPM_OrdinalTable_GetAuditDefault(TPM_BOOL *auditDefault, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_ORDINAL_TABLE *entry; + + if (rc == 0) { + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal); + } + /* if not found, unimplemented, not auditable */ + if (rc != 0) { + *auditDefault = FALSE; + } + /* found an entry, return it */ + else { + *auditDefault = entry->auditDefault; + } + return; +} + + +/* TPM_OrdinalTable_GetOwnerPermission() gets the owner permission block and the position within the + block for a permission bit based on the ordinal +*/ + +TPM_RESULT TPM_OrdinalTable_GetOwnerPermission(uint16_t *ownerPermissionBlock, + uint32_t *ownerPermissionPosition, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_ORDINAL_TABLE *entry; + + if (rc == 0) { + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal); + } + if (rc == 0) { + *ownerPermissionBlock = entry->ownerPermissionBlock; + *ownerPermissionPosition = entry->ownerPermissionPosition; + /* sanity check ordinal table entry value */ + if (*ownerPermissionPosition >= (sizeof(uint32_t) * CHAR_BIT)) { + printf("TPM_OrdinalTable_GetOwnerPermission: Error (fatal): " + "ownerPermissionPosition out of range %u\n", *ownerPermissionPosition); + rc = TPM_FAIL; /* should never occur */ + } + } + return rc; +} + +/* TPM_OrdinalTable_GetKeyPermission() gets the key permission block and the position within the + block for a permission bit based on the ordinal +*/ + +TPM_RESULT TPM_OrdinalTable_GetKeyPermission(uint16_t *keyPermissionBlock, + uint32_t *keyPermissionPosition, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; + TPM_ORDINAL_TABLE *entry; + + if (rc == 0) { + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal); + } + if (rc == 0) { + *keyPermissionBlock = entry->keyPermissionBlock; + *keyPermissionPosition = entry->keyPermissionPosition; + if (*keyPermissionPosition >= (sizeof(uint32_t) * CHAR_BIT)) { + printf("TPM_OrdinalTable_GetKeyPermission: Error (fatal): " + "keyPermissionPosition out of range %u\n", *keyPermissionPosition); + rc = TPM_FAIL; /* should never occur */ + } + } + return rc; +} + +/* TPM_OrdinalTable_ParseWrappedCmd() parses a transport wrapped command, extracting + + - index into DATAw + - length of DATAw + - number of key handles and their indexes + - ordinal + - transportWrappable FALSE if the command cannot be wrapped in a transport session + + FIXME if audit has to occur before command parsing, this command becomes more generally useful, + and might do the auditing and return the inParamDigest as well. + + This function cannot get the actual key handle(s) because the value may be encrypted, and the + decryption has not occurred yet. +*/ + +TPM_RESULT TPM_OrdinalTable_ParseWrappedCmd(uint32_t *datawStart, + uint32_t *datawLen, + uint32_t *keyHandles, + uint32_t *keyHandle1Index, + uint32_t *keyHandle2Index, + TPM_COMMAND_CODE *ordinal, + TPM_BOOL *transportWrappable, + TPM_SIZED_BUFFER *wrappedCmd) +{ + TPM_RESULT rc = 0; + uint32_t stream_size; + unsigned char *stream; + TPM_TAG tag = 0; + uint32_t paramSize = 0; + TPM_ORDINAL_TABLE *entry; /* table entry for the ordinal */ + uint32_t authLen; /* length of below the line parameters */ + + printf(" TPM_OrdinalTable_ParseWrappedCmd:\n"); + /* Extract the standard command parameters from the command stream. This also validates + paramSize against wrappedCmdSize */ + if (rc == 0) { + /* make temporary copies so the wrappedCmd is not touched */ + /* FIXME might want to return paramSize and tag and move the wrappedCmd pointers */ + stream = wrappedCmd->buffer; + stream_size = wrappedCmd->size; + /* parse the three standard input parameters, check paramSize against wrappedCmd->size */ + rc = TPM_Process_GetCommandParams(&tag, ¶mSize, ordinal, + &stream, &stream_size); + } + /* get the entry from the ordinal table */ + if (rc == 0) { + printf(" TPM_OrdinalTable_ParseWrappedCmd: ordinal %08x\n", *ordinal); + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, *ordinal); + } + if (rc == 0) { + /* datawStart indexes into the dataW area, skip the standard 3 inputs and the handles */ + *datawStart = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE) + + entry->inputHandleSize; + /* authLen is the length of the below-the-line auth parameters that are excluded from the + dataW area */ + switch (tag) { + case TPM_TAG_RQU_AUTH1_COMMAND: + authLen = sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE + + sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE; + break; + case TPM_TAG_RQU_AUTH2_COMMAND: + authLen = 2 * + (sizeof(TPM_AUTHHANDLE) + TPM_NONCE_SIZE + + sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE); + break; + case TPM_TAG_RQU_COMMAND: + /* if the tag is illegal, assume the dataW area goes to the end of the command */ + default: + authLen = 0; + break; + } + if (paramSize < *datawStart + authLen) { + printf("TPM_OrdinalTable_ParseWrappedCmd: Error, " + "paramSize %u less than datawStart %u + authLen %u\n", + paramSize, *datawStart, authLen); + rc = TPM_BAD_PARAM_SIZE; + } + } + if (rc == 0) { + /* subtract safe, cannot be negative after above check */ + *datawLen = paramSize - *datawStart - authLen; + printf(" TPM_OrdinalTable_ParseWrappedCmd: datawStart %u datawLen %u\n", + *datawStart, *datawLen); + /* determine whether the command can be wrapped in a transport session */ + *transportWrappable = entry->transportWrappable; + /* return the number of key handles */ + *keyHandles = entry->keyHandles; + } + if (rc == 0) { + printf(" TPM_OrdinalTable_ParseWrappedCmd: key handles %u\n", *keyHandles); + switch (*keyHandles) { + case 0: + /* no key handles */ + break; + case 1: + /* one key handle */ + *keyHandle1Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE); + break; + case 2: + /* first key handle */ + *keyHandle1Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE); + /* second key handle */ + *keyHandle2Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE) + + sizeof(TPM_KEY_HANDLE); + break; + case 0xffffffff: + printf(" TPM_OrdinalTable_ParseWrappedCmd: key handles special case\n"); + /* potential key handle */ + *keyHandle1Index = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE); + /* can't determine handle type here since resourceType is encrypted */ + break; + default: + /* sanity check ordinal table */ + printf("TPM_OrdinalTable_ParseWrappedCmd: Error (fatal), " + "invalid key handles for %08x for ordinal %08x\n", *keyHandles, *ordinal); + rc = TPM_FAIL; /* should never occur */ + break; + } + } + return rc; +} + +/* TPM_OrdinalTable_ParseWrappedRsp() parses a transport wrapped response, extracting + + - index into DATAw + - length of DATAw + - return code RCw + + FIXME this command might do the auditing and return the outParamDigest as well. +*/ + +TPM_RESULT TPM_OrdinalTable_ParseWrappedRsp(uint32_t *datawStart, + uint32_t *datawLen, + TPM_RESULT *rcw, + TPM_COMMAND_CODE ordinal, + const unsigned char *wrappedRspStream, + uint32_t wrappedRspStreamSize) +{ + TPM_RESULT rc = 0; + TPM_TAG tag = 0; + uint32_t paramSize = 0; + TPM_ORDINAL_TABLE *entry; /* table entry for the ordinal */ + uint32_t authLen; /* length of below the line parameters */ + + printf(" TPM_OrdinalTable_ParseWrappedRsp: ordinal %08x\n", ordinal); + /* Extract the standard response parameters from the response stream. This also validates + paramSize against wrappedRspSize */ + if (rc == 0) { + rc = TPM_Process_GetResponseParams(&tag, ¶mSize, rcw, + (unsigned char **)&wrappedRspStream, + &wrappedRspStreamSize); + } + /* get the entry from the ordinal table */ + if (rc == 0) { + printf(" TPM_OrdinalTable_ParseWrappedRsp: returnCode %08x\n", *rcw); + rc = TPM_OrdinalTable_GetEntry(&entry, tpm_ordinal_table, ordinal); + } + /* parse the success return code case */ + if ((rc == 0) && (*rcw == TPM_SUCCESS)) { + if (rc == 0) { + /* datawStart indexes into the dataW area, skip the standard 3 inputs and the handles */ + *datawStart = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT) + + entry->outputHandleSize; + /* authLen is the length of the below-the-line auth parameters that are excluded from + the dataW area */ + switch (tag) { + case TPM_TAG_RSP_AUTH1_COMMAND: + authLen = TPM_NONCE_SIZE + sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE; + break; + case TPM_TAG_RSP_AUTH2_COMMAND: + authLen = 2 * (TPM_NONCE_SIZE + sizeof(TPM_BOOL) + TPM_AUTHDATA_SIZE); + break; + case TPM_TAG_RSP_COMMAND: + /* if the tag is illegal, assume the dataW area goes to the end of the response */ + default: + authLen = 0; + break; + } + if (paramSize < *datawStart + authLen) { + printf("TPM_OrdinalTable_ParseWrappedRsp: Error, " + "paramSize %u less than datawStart %u + authLen %u\n", + paramSize, *datawStart, authLen); + rc = TPM_BAD_PARAM_SIZE; /* FIXME not clear what to do here */ + } + } + if (rc == 0) { + /* subtract safe, cannot be negative after about check */ + *datawLen = paramSize - *datawStart - authLen; + printf(" TPM_OrdinalTable_ParseWrappedRsp: datawStart %u datawLen %u\n", + *datawStart, *datawLen); + } + } + /* if the wrapped command failed, datawStart is not used, and datawLen is 0 */ + else if ((rc == 0) && (*rcw != TPM_SUCCESS)) { + *datawStart = sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT); + *datawLen = 0; + printf(" TPM_OrdinalTable_ParseWrappedRsp: datawLen %u\n", *datawLen); + } + return rc; +} + +void TPM_KeyHandleEntries_Trace(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries); + +void TPM_KeyHandleEntries_Trace(TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries) +{ + size_t i; + for (i = 0 ; (i < 4) && (i < TPM_KEY_HANDLES) ; i++) { + printf("TPM_KeyHandleEntries_Trace: %lu handle %08x tpm_key %p\n", + (unsigned long)i, tpm_key_handle_entries[i].handle, tpm_key_handle_entries[i].key); + } + return; +} + +void TPM_State_Trace(tpm_state_t *tpm_state); + +void TPM_State_Trace(tpm_state_t *tpm_state) +{ + printf("TPM_State_Trace: disable %u p_deactive %u v_deactive %u owned %u state %u\n", + tpm_state->tpm_permanent_flags.disable, + tpm_state->tpm_permanent_flags.deactivated, + tpm_state->tpm_stclear_flags.deactivated, + tpm_state->tpm_permanent_data.ownerInstalled, + tpm_state->testState); + return; +} + +/* TPM_ProcessA() is an alternate to TPM_Process() that uses standard C types. It provides an entry + point to the TPM without requiring the TPM_STORE_BUFFER class. + + The design pattern for the response is: + + - set '*response' to NULL at the first call + + - on subsequent calls, pass 'response' and 'response_total' back in. Set 'response_total' back + to 0. + + On input: + + '*response' - pointer to a buffer that was allocated (can be NULL) + + 'response_size' - the number of valid bytes in buffer (ignored if buffer is NULL, can be 0, + cannot be greater than total. Set to zero, unless one wants the TPM_Process() function to append + a response to some existing data. + + '*response_total' - the total number of allocated bytes (ignored if buffer is NULL) + + On output: + + '*response' - pointer to a buffer that was allocated or reallocated + + 'response_size' - the number of valid bytes in buffer + + '*response_total' - the total number of allocated or reallocated bytes +*/ + +TPM_RESULT TPM_ProcessA(unsigned char **response, + uint32_t *response_size, + uint32_t *response_total, + unsigned char *command, /* complete command array */ + uint32_t command_size) /* actual bytes in command */ + +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER responseSbuffer; + + /* set the sbuffer from the response parameters */ + if (rc == 0) { + rc = TPM_SBuffer_Set(&responseSbuffer, + *response, + *response_size, + *response_total); + } + if (rc == 0) { + rc = TPM_Process(&responseSbuffer, + command, /* complete command array */ + command_size); /* actual bytes in command */ + + } + /* get the response parameters from the sbuffer */ + if (rc == 0) { + TPM_Sbuffer_GetAll(&responseSbuffer, + response, + response_size, + response_total); + } + return rc; +} + +/* Process the command from the host to the TPM. + + 'command_size' is the actual size of the command stream. + + Returns: + 0 on success + + non-zero on a fatal error preventing the command from being processed. The response is + invalid in this case. +*/ + +TPM_RESULT TPM_Process(TPM_STORE_BUFFER *response, + unsigned char *command, /* complete command array */ + uint32_t command_size) /* actual bytes in command */ +{ + TPM_RESULT rc = 0; /* fatal error, no response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* fatal error in ordinal processing, + can be returned */ + TPM_TAG tag = 0; + uint32_t paramSize = 0; + TPM_COMMAND_CODE ordinal = 0; + tpm_process_function_t tpm_process_function = NULL; /* based on ordinal */ + tpm_state_t *targetInstance = NULL; /* TPM global state */ + TPM_STORE_BUFFER localBuffer; /* for response if instance was not found */ + TPM_STORE_BUFFER *sbuffer; /* either localBuffer or the instance response + buffer */ + + TPM_Sbuffer_Init(&localBuffer); /* freed @1 */ + /* get the global TPM state */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + targetInstance = tpm_instances[0]; + } + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + /* clear the response form the previous ordinal, the response buffer is reused */ + TPM_Sbuffer_Clear(&(targetInstance->tpm_stclear_data.ordinalResponse)); + /* extract the standard command parameters from the command stream */ + returnCode = TPM_Process_GetCommandParams(&tag, ¶mSize, &ordinal, + &command, &command_size); + } + /* preprocessing common to all ordinals */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_Process_Preprocess(targetInstance, ordinal, NULL); + } + /* NOTE Only for debugging */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + TPM_KeyHandleEntries_Trace(targetInstance->tpm_key_handle_entries); + } + /* process the ordinal */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + /* get the processing function from the ordinal table */ + TPM_OrdinalTable_GetProcessFunction(&tpm_process_function, tpm_ordinal_table, ordinal); + /* call the processing function to execute the command */ + returnCode = tpm_process_function(targetInstance, + &(targetInstance->tpm_stclear_data.ordinalResponse), + tag, command_size, ordinal, command, + NULL); /* not from encrypted transport */ + } + /* NOTE Only for debugging */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + TPM_KeyHandleEntries_Trace(targetInstance->tpm_key_handle_entries); + } + /* NOTE Only for debugging */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + TPM_State_Trace(targetInstance); + } +#ifdef TPM_VOLATILE_STORE + /* save the volatile state after each command to handle fail-over restart */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_VolatileAll_NVStore(targetInstance); + } +#endif /* TPM_VOLATILE_STORE */ + /* If the ordinal processing function returned without a fatal error, append its ordinalResponse + to the output response buffer */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_Sbuffer_AppendSBuffer(response, + &(targetInstance->tpm_stclear_data.ordinalResponse)); + } + if ((rc == 0) && (returnCode != TPM_SUCCESS)) { + /* gets here if: + + - there was an error before the ordinal was processed + - the ordinal returned a fatal error + - an error occurred appending the ordinal response + + returnCode should be the response + errors here are fatal, can't create an error response + */ + /* if it failed after the target instance was found, use the instance's response buffer */ + if (targetInstance != NULL) { + sbuffer = &(targetInstance->tpm_stclear_data.ordinalResponse); + } + /* if it failed before even the target instance was found, use a local buffer */ + else { + sbuffer = &localBuffer; + } + if (rc == 0) { + /* it's not even known whether the initial response was stored, so just start + over */ + TPM_Sbuffer_Clear(sbuffer); + /* store the tag, paramSize, and returnCode */ + printf("TPM_Process: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rc = TPM_Sbuffer_StoreInitialResponse(sbuffer, TPM_TAG_RQU_COMMAND, returnCode); + } + /* call this to handle the TPM_FAIL causing the TPM going into failure mode */ + if (rc == 0) { + rc = TPM_Sbuffer_StoreFinalResponse(sbuffer, returnCode, targetInstance); + } + if (rc == 0) { + rc = TPM_Sbuffer_AppendSBuffer(response, sbuffer); + } + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&localBuffer); /* @1 */ + return rc; +} + +/* TPM_Process_Wrapped() is called recursively to process a wrapped command. + + 'command_size' is the actual size of the command stream. + + 'targetInstance' is an input indicating the TPM instance being called. + + 'transportInternal' not NULL indicates that this function was called recursively from + TPM_ExecuteTransport + + For wrapped commands, this function cannot trust that command_size and the incoming paramSize in + the command stream are consistent. Therefore, this function checks for consistency. + + The processor ensures that the response bytes are set according to the outgoing paramSize on + return. + + Returns: + 0 on success + + non-zero on a fatal error preventing the command from being processed. The response is + invalid in this case. +*/ + +TPM_RESULT TPM_Process_Wrapped(TPM_STORE_BUFFER *response, + unsigned char *command, /* complete command array */ + uint32_t command_size, /* actual bytes in command */ + tpm_state_t *targetInstance, /* global TPM state */ + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rc = 0; /* fatal error, no response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* non-fatal error, returned in response */ + TPM_TAG tag = 0; + uint32_t paramSize = 0; + TPM_COMMAND_CODE ordinal = 0; + tpm_process_function_t tpm_process_function = NULL; /* based on ordinal */ + TPM_STORE_BUFFER ordinalResponse; /* response for this ordinal */ + + printf("TPM_Process_Wrapped:\n"); + TPM_Sbuffer_Init(&ordinalResponse); /* freed @1 */ + /* Set the tag, paramSize, and ordinal from the wrapped command stream */ + /* If paramSize does not equal the command stream size, return TPM_BAD_PARAM_SIZE */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_Process_GetCommandParams(&tag, ¶mSize, &ordinal, + &command, &command_size); + } + /* preprocessing common to all ordinals */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_Process_Preprocess(targetInstance, ordinal, transportInternal); + } + /* process the ordinal */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + /* get the processing function from the ordinal table */ + TPM_OrdinalTable_GetProcessFunction(&tpm_process_function, tpm_ordinal_table, ordinal); + /* call the processing function to execute the command */ + returnCode = tpm_process_function(targetInstance, &ordinalResponse, + tag, command_size, ordinal, command, + transportInternal); + } + /* If the ordinal processing function returned without a fatal error, append its ordinalResponse + to the output response buffer */ + if ((rc == 0) && (returnCode == TPM_SUCCESS)) { + returnCode = TPM_Sbuffer_AppendSBuffer(response, &ordinalResponse); + } + /* If: + + - an error in this function occurred before the ordinal was processed + - the ordinal processing function returned a fatal error + - an error occurred appending the ordinal response + + then use the return code of that failure as the final response. Failure here is fatal, since + no error code can be returned. + */ + if ((rc == 0) && (returnCode != TPM_SUCCESS)) { + rc = TPM_Sbuffer_StoreFinalResponse(response, returnCode, targetInstance); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&ordinalResponse); /* @1 */ + return rc; +} + +/* TPM_Process_GetCommandParams() gets the standard 3 parameters from the command input stream + + The stream is adjusted to point past the parameters. + + The resulting paramSize is checked against the stream size for consistency. paramSize is + returned for reference, but command_size reflects the remaining bytes in the stream. +*/ + +TPM_RESULT TPM_Process_GetCommandParams(TPM_TAG *tag, + uint32_t *paramSize , + TPM_COMMAND_CODE *ordinal, + unsigned char **command, + uint32_t *command_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Process_GetCommandParams:\n"); + /* get tag */ + if (rc == 0) { + rc = TPM_Load16(tag, command, command_size); + } + /* get paramSize */ + if (rc == 0) { + rc = TPM_Load32(paramSize, command, command_size); + } + /* get ordinal */ + if (rc == 0) { + rc = TPM_Load32(ordinal, command, command_size); + } + /* check the paramSize against the command_size */ + if (rc == 0) { + if (*paramSize != + *command_size + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE)) { + + printf("TPM_Process_GetCommandParams: Error, " + "command size %lu not equal to paramSize %u\n", + (unsigned long) + (*command_size + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_COMMAND_CODE)), + *paramSize); + rc = TPM_BAD_PARAM_SIZE; + } + else { + printf(" TPM_Process_GetCommandParams: tag %04x paramSize %u ordinal %08x\n", + *tag, *paramSize, *ordinal); + } + } + return rc; +} + +/* TPM_Process_GetResponseParams() gets the standard 3 parameters from the response output stream + + The stream is adjusted to point past the parameters. + + The resulting paramSize is checked against the stream size for consistency. paramSize is + returned for reference, but response_size reflects the remaining bytes in the stream. +*/ + +TPM_RESULT TPM_Process_GetResponseParams(TPM_TAG *tag, + uint32_t *paramSize , + TPM_RESULT *returnCode, + unsigned char **response, + uint32_t *response_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Process_GetResponseParams:\n"); + /* get tag */ + if (rc == 0) { + rc = TPM_Load16(tag, response, response_size); + } + /* get paramSize */ + if (rc == 0) { + rc = TPM_Load32(paramSize, response, response_size); + } + /* get returnCode */ + if (rc == 0) { + rc = TPM_Load32(returnCode, response, response_size); + } + /* check the paramSize against the response_size */ + if (rc == 0) { + if (*paramSize != (*response_size + sizeof(TPM_TAG) + + sizeof(uint32_t) + sizeof(TPM_RESULT))) { + + printf("TPM_Process_GetResponseParams: Error, " + "response size %lu not equal to paramSize %u\n", + (unsigned long) + (*response_size + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT)), + *paramSize); + rc = TPM_BAD_PARAM_SIZE; + } + else { + printf(" TPM_Process_GetResponseParams: tag %04x paramSize %u ordinal %08x\n", + *tag, *paramSize, *returnCode); + } + } + return rc; +} + +/* TPM_CheckRequestTagnnn() is common code to verify the command tag */ + +TPM_RESULT TPM_CheckRequestTag210(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if ((tpm_tag != TPM_TAG_RQU_AUTH2_COMMAND) && + (tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND) && + (tpm_tag != TPM_TAG_RQU_COMMAND)) { + printf("TPM_CheckRequestTag210: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_CheckRequestTag21(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if ((tpm_tag != TPM_TAG_RQU_AUTH2_COMMAND) && + (tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_CheckRequestTag21: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_CheckRequestTag2(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if (tpm_tag != TPM_TAG_RQU_AUTH2_COMMAND) { + printf("TPM_CheckRequestTag2: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_CheckRequestTag10(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if ((tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND) && + (tpm_tag != TPM_TAG_RQU_COMMAND)) { + printf("TPM_CheckRequestTag10: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_CheckRequestTag1(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if (tpm_tag != TPM_TAG_RQU_AUTH1_COMMAND) { + printf("TPM_CheckRequestTag1: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_CheckRequestTag0(TPM_TAG tpm_tag) +{ + TPM_RESULT rc = 0; + + if (tpm_tag != TPM_TAG_RQU_COMMAND) { + printf("TPM_CheckRequestTag0: Error, tag %04hx\n", tpm_tag); + rc = TPM_BADTAG; + } + return rc; +} + +TPM_RESULT TPM_Process_Unused(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; + + printf("TPM_Process_Unused:\n"); + tpm_state = tpm_state; /* not used */ + paramSize = paramSize; /* not used */ + ordinal = ordinal; /* not used */ + command = command; /* not used */ + transportInternal = transportInternal; /* not used */ + printf("TPM_Process_Unused: Ordinal returnCode %08x %u\n", + TPM_BAD_ORDINAL, TPM_BAD_ORDINAL); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, TPM_BAD_ORDINAL); + return rcf; +} + +/* TPM_CheckState() should be called by all commands. It checks a set of flags specified by + tpm_check_map to determine whether the command can execute in that state. + + Returns: 0 if the command can execute + non-zero error code that should be returned as a response +*/ + +TPM_RESULT TPM_CheckState(tpm_state_t *tpm_state, + TPM_TAG tag, + uint32_t tpm_check_map) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CheckState: Check map %08x\n", tpm_check_map); + /* check the dictionary attack lockout, only for authorized commands */ + if (rc == 0) { + if ((tpm_check_map & TPM_CHECK_NO_LOCKOUT) && (tag != TPM_TAG_RQU_COMMAND)) { + rc = TPM_Authdata_CheckState(tpm_state); + } + } + /* TPM_GetTestResult. This command can assist the TPM manufacturer in determining the cause of + the self-test failure. iii. All other operations will return the error code + TPM_FAILEDSELFTEST. */ + if (rc == 0) { + if (tpm_check_map & TPM_CHECK_NOT_SHUTDOWN) { + if (tpm_state->testState == TPM_TEST_STATE_FAILURE) { + printf("TPM_CheckState: Error, shutdown is TRUE\n"); + rc = TPM_FAILEDSELFTEST; + } + } + } + /* TPM_Startup SHALL execute as normal, and is the only function that does not call + TPM_CheckState(). All other commands SHALL return TPM_INVALID_POSTINIT */ + if (rc == 0) { + if (tpm_state->tpm_stany_flags.postInitialise) { + printf("TPM_CheckState: Error, postInitialise is TRUE\n"); + rc = TPM_INVALID_POSTINIT; + } + } + /* + For checking disabled and deactivated, the check is NOT done if it's one of the special NV + commands (indicated by TPM_CHECK_NV_NOAUTH) and nvLocked is FALSE, indicating that the NV + store does not require authorization + */ + /* For commands available only when enabled. */ + if (rc == 0) { + if ((tpm_check_map & TPM_CHECK_ENABLED) && + !((tpm_check_map & TPM_CHECK_NV_NOAUTH) && !tpm_state->tpm_permanent_flags.nvLocked)) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_CheckState: Error, disable is TRUE\n"); + rc = TPM_DISABLED; + } + } + } + /* For commands only available when activated. */ + if (rc == 0) { + if ((tpm_check_map & TPM_CHECK_ACTIVATED) && + !((tpm_check_map & TPM_CHECK_NV_NOAUTH) && !tpm_state->tpm_permanent_flags.nvLocked)) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_CheckState: Error, deactivated is TRUE\n"); + rc = TPM_DEACTIVATED; + } + } + } + /* For commands available only after an owner is installed. see Ordinals chart */ + if (rc == 0) { + if (tpm_check_map & TPM_CHECK_OWNER) { + if (!tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_CheckState: Error, ownerInstalled is FALSE\n"); + rc = TPM_NOSRK; + } + } + } + return rc; +} + +/* TPM_Process_Preprocess() handles check functions common to all ordinals + + 'transportPublic' not NULL indicates that this function was called recursively from + TPM_ExecuteTransport +*/ + +TPM_RESULT TPM_Process_Preprocess(tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rc = 0; /* fatal error, no response */ + + printf(" TPM_Process_Preprocess: Ordinal %08x\n", ordinal); + /* Preprocess to check if command can be run in limited operation mode */ + if (rc == 0) { + if (tpm_state->testState == TPM_TEST_STATE_LIMITED) { + /* 1. At startup, a TPM MUST self-test all internal functions that are necessary to do + TPM_SHA1Start, TPM_SHA1Update, TPM_SHA1Complete, TPM_SHA1CompleteExtend, TPM_Extend, + TPM_Startup, TPM_ContinueSelfTest, a subset of TPM_GetCapability, and + TPM_GetTestResult.. + */ + if (!((ordinal == TPM_ORD_Startup) || + (ordinal == TPM_ORD_SHA1Start) || + (ordinal == TPM_ORD_SHA1Update) || + (ordinal == TPM_ORD_SHA1Complete) || + (ordinal == TPM_ORD_SHA1CompleteExtend) || + (ordinal == TPM_ORD_Extend) || + (ordinal == TPM_ORD_Startup) || + (ordinal == TPM_ORD_ContinueSelfTest) || + /* a subset of TPM_GetCapability does not require self-test. The ordinal itself + decides whether to run TPM_ContinueSelfTest() */ + (ordinal == TPM_ORD_GetCapability) || + /* 3. The TPM MAY allow TPM_SelfTestFull to be used before completion of the + actions of TPM_ContinueSelfTest. */ + (ordinal == TPM_ORD_SelfTestFull) || + (ordinal == TPM_ORD_GetTestResult) || + /* 2. The TSC_PhysicalPresence and TSC_ResetEstablishmentBit commands do not + operate on shielded-locations and have no requirement to be self-tested before + any use. TPM's SHOULD test these functions before operation. */ + (ordinal == TSC_ORD_PhysicalPresence) || + (ordinal == TSC_ORD_ResetEstablishmentBit) + )) { + /* One of the optional actions. */ + /* rc = TPM_NEEDS_SELFTEST; */ + /* Alternatively, could run the actions of continue self-test */ + rc = TPM_ContinueSelfTestCmd(tpm_state); + } + } + } + /* special pre-processing for SHA1 context */ + if (rc == 0) { + rc = TPM_Check_SHA1Context(tpm_state, ordinal, transportInternal); + } + /* Special pre-processing to invalidate the saved state if it exists. Omit this processing for + TPM_Startup, since that function might restore the state first */ + if (rc == 0) { + if (tpm_state->tpm_stany_flags.stateSaved && + !((ordinal == TPM_ORD_Startup) || + (ordinal == TPM_ORD_Init))) { + /* For any other ordinal, invalidate the saved state if it exists. */ + rc = TPM_SaveState_NVDelete(tpm_state, TRUE); + } + } + /* When an exclusive session is running, execution of any command other then + TPM_ExecuteTransport or TPM_ReleaseTransportSigned targeting the exclusive session causes the + abnormal invalidation of the exclusive transport session. */ + if ((rc == 0) && (transportInternal == NULL)) { /* do test only for the outer ordinal */ + if ((tpm_state->tpm_stany_flags.transportExclusive != 0) && /* active exclusive */ + /* These two ordinals terminate the exclusive transport session if the transport handle + is not the specified handle. So the check is deferred until the command is parsed + for the transport handle. */ + !((ordinal == TPM_ORD_ExecuteTransport) || + (ordinal == TPM_ORD_ReleaseTransportSigned))) { + rc = TPM_TransportSessions_TerminateHandle + (tpm_state->tpm_stclear_data.transSessions, + tpm_state->tpm_stany_flags.transportExclusive, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + } + /* call platform specific code to set the localityModifier */ + if ((rc == 0) && (transportInternal == NULL)) { /* do only for the outer ordinal */ + rc = TPM_IO_GetLocality(&(tpm_state->tpm_stany_flags.localityModifier), + tpm_state->tpm_number); + } + return rc; +} + + +/* TPM_Check_SHA1Context() checks the current SHA1 context + + The TPM may not allow any other types of processing during the execution of a SHA-1 + session. There is only one SHA-1 session active on a TPM. After the execution of SHA1Start, and + prior to SHA1End, the receipt of any command other than SHA1Update will cause the invalidation of + the SHA-1 session. + + 2. After receipt of TPM_SHA1Start, and prior to the receipt of TPM_SHA1Complete or + TPM_SHA1CompleteExtend, receipt of any command other than TPM_SHA1Update invalidates the SHA-1 + session. + + a. If the command received is TPM_ExecuteTransport, the SHA-1 session invalidation is based on + the wrapped command, not the TPM_ExecuteTransport ordinal. + + b. A SHA-1 thread (start, update, complete) MUST take place either completely outside a transport + session or completely within a single transport session. +*/ + +TPM_RESULT TPM_Check_SHA1Context(tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rc = 0; + + if ((tpm_state->sha1_context != NULL) && /* if there was a SHA-1 context set up */ + (ordinal != TPM_ORD_ExecuteTransport)) /* depends on the wrapped command */ + { + /* the non-SHA1 ordinals invalidate the SHA-1 session */ + if ( + ((ordinal != TPM_ORD_SHA1Update) && + (ordinal != TPM_ORD_SHA1Complete) && + (ordinal != TPM_ORD_SHA1CompleteExtend)) || + + /* invalidate if the SHA1 ordinal is within a transport session and the session was not + set up within the same transport session. */ + ((transportInternal != NULL) && + (tpm_state->transportHandle != transportInternal->transHandle)) || + + /* invalidate if the SHA1 ordinal is not within a transport session and the session was + set up with a transport session */ + ((transportInternal == NULL) && + (tpm_state->transportHandle != 0)) + + ) { + + printf("TPM_Check_SHA1Context: Invalidating SHA1 context\n"); + TPM_SHA1Delete(&(tpm_state->sha1_context)); + } + } + return rc; +} + +/* TPM_GetInParamDigest() does common processing of input parameters. + + Common processing includes: + + - determining if the ordinal is being run within an encrypted transport session, since the + inParamDigest does not have to be calculated for audit in that case. + + - retrieving the audit status. It is determinant of whether the input parameter digest should be + calculated. + + - calculating the input parameter digest for HMAC authorization and/or auditing + + This function is called before authorization for several reasons. + + 1 - It makes ordinal processing code more uniform, since authorization sometimes occurs far into + the actions. + + 2 - It is a minor optimization, since the resulting inParamDigest can be used twice in an auth-2 + command, as well as extending the audit digest. +*/ + +TPM_RESULT TPM_GetInParamDigest(TPM_DIGEST inParamDigest, /* output */ + TPM_BOOL *auditStatus, /* output */ + TPM_BOOL *transportEncrypt, /* output */ + tpm_state_t *tpm_state, + TPM_TAG tag, + TPM_COMMAND_CODE ordinal, + unsigned char *inParamStart, + unsigned char *inParamEnd, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rc = 0; /* this function return code */ + TPM_COMMAND_CODE nOrdinal; /* ordinal in network byte order */ + + printf(" TPM_GetInParamDigest:\n"); + if (rc == 0) { + /* TRUE if called from encrypted transport session. This is currently only needed when + auditing, but it's safer to always initialize it */ + *transportEncrypt = + (transportInternal != NULL) && + (transportInternal->transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT); + printf(" TPM_GetInParamDigest: transportEncrypt %02x\n", *transportEncrypt); + /* Determine if the ordinal should be audited. */ + rc = TPM_OrdinalAuditStatus_GetAuditStatus(auditStatus, + ordinal, + &(tpm_state->tpm_permanent_data)); + } + /* If inParamDigest is needed for: + + 1 - for auditing (auditStatus == TRUE) and not called from an encrypted transport. Different + parameters are audited if the ordinal is called through an encrypted transport session. + + 2 - for authorization (tag != auth-0) + */ + if (rc == 0) { + if ((*auditStatus && !(*transportEncrypt)) || /* digest for auditing */ + (tag != TPM_TAG_RQU_COMMAND)) { /* digest for authorization */ + + /* convert ordinal to network byte order */ + nOrdinal = htonl(ordinal); + + /* a. Create inParamDigest - digest of inputs above the double line. NOTE: If there + are no inputs other than the ordinal, inParamEnd - inParamStart will be 0, + terminating the SHA1 vararg hash. It is important that the termination condition + be the length and not the NULL pointer. */ + rc = TPM_SHA1(inParamDigest, + sizeof(TPM_COMMAND_CODE), &nOrdinal, /* 1S */ + inParamEnd - inParamStart, inParamStart, /* 2S - ... */ + 0, NULL); + if (rc == 0) { + TPM_PrintFour(" TPM_GetInParamDigest: inParamDigest", inParamDigest); + } + } + } + return rc; +} + +/* TPM_GetOutParamDigest() does common processing of output parameters. + + It calculates the output parameter digest for HMAC generation and/or auditing if required. +*/ + +TPM_RESULT TPM_GetOutParamDigest(TPM_DIGEST outParamDigest, /* output */ + TPM_BOOL auditStatus, /* input audit status */ + TPM_BOOL transportEncrypt, /* wrapped in encrypt transport */ + TPM_TAG tag, + TPM_RESULT returnCode, + TPM_COMMAND_CODE ordinal, /* command ordinal (hbo) */ + unsigned char *outParamStart, /* starting point of param's */ + uint32_t outParamLength) /* length of param's */ +{ + TPM_RESULT rc = 0; + TPM_RESULT nreturnCode; /* returnCode in nbo */ + TPM_COMMAND_CODE nOrdinal; /* ordinal in network byte order */ + + printf(" TPM_GetOutParamDigest:\n"); + if (rc == 0) { + if ((auditStatus && !transportEncrypt) || (tag != TPM_TAG_RQU_COMMAND)) { + nreturnCode = htonl(returnCode); + nOrdinal = htonl(ordinal); + /* a. Create outParamDigest - digest of outputs above the double line. NOTE: If there + are no outputs other than the returnCode and ordinal, outParamLength + will be 0, terminating the SHA1 vararg hash. It is important that the termination + condition be the length and not the NULL pointer. */ + rc = TPM_SHA1(outParamDigest, + sizeof(TPM_RESULT), &nreturnCode, /* 1S */ + sizeof(TPM_COMMAND_CODE), &nOrdinal, /* 2S */ + outParamLength, outParamStart, /* 3S - ...*/ + 0, NULL); + if (rc == 0) { + TPM_PrintFour(" TPM_GetOutParamDigest: outParamDigest", outParamDigest); + } + } + } + return rc; +} + +/* TPM_ProcessAudit() rev 109 + + This function is called when command auditing is required. + + This function must be called after the output authorization, since it requires the (almost) final + return code. +*/ + +TPM_RESULT TPM_ProcessAudit(tpm_state_t *tpm_state, + TPM_BOOL transportEncrypt, /* wrapped in encrypt transport */ + TPM_DIGEST inParamDigest, + TPM_DIGEST outParamDigest, + TPM_COMMAND_CODE ordinal) +{ + TPM_RESULT rc = 0; /* audit return code */ + TPM_BOOL isZero; + TPM_RESULT nreturnCode; /* returnCode in nbo */ + TPM_COMMAND_CODE nOrdinal; /* ordinal in network byte order */ + TPM_DIGEST transportDigest; /* special case digest in encrypted transport */ + + printf(" TPM_ProcessAudit:\n"); + + /* The TPM will execute the ordinal and perform auditing in the following manner: */ + /* 1. Execute command */ + /* a. Execution implies the performance of the listed actions for the ordinal. */ + /* 2. If the command will return TPM_SUCCESS */ + /* a. If TPM_STANY_DATA -> auditDigest is all zeros */ + if (rc == 0) { + TPM_Digest_IsZero(&isZero, tpm_state->tpm_stclear_data.auditDigest); + if (isZero) { + /* i. Increment TPM_PERMANENT_DATA -> auditMonotonicCounter by 1 */ + tpm_state->tpm_permanent_data.auditMonotonicCounter.counter++; + printf(" TPM_ProcessAudit: Incrementing auditMonotonicCounter to %u\n", + tpm_state->tpm_permanent_data.auditMonotonicCounter.counter); + rc = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } + } + /* b. Create A1 a TPM_AUDIT_EVENT_IN structure */ + /* i. Set A1 -> inputParms to the digest of the input parameters from the command */ + /* (1) Digest value according to the HMAC digest rules of the "above the line" parameters + (i.e. the first HMAC digest calculation). */ + /* ii. Set A1 -> auditCount to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + /* c. Set TPM_STANY_DATA -> auditDigest to SHA-1 (TPM_STANY_DATA -> auditDigest || A1) */ + if (rc == 0) { + /* normal case, audit uses inParamDigest */ + if (!transportEncrypt) { + rc = TPM_AuditDigest_ExtendIn(tpm_state, inParamDigest); + } + /* 1. When the wrapped command requires auditing and the transport session specifies + encryption, the TPM MUST perform the audit. However, when computing the audit digest: + */ + else { + /* a. For input, only the ordinal is audited. */ + if (rc == 0) { + nOrdinal = htonl(ordinal); + rc = TPM_SHA1(transportDigest, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + 0, NULL); + } + if (rc == 0) { + rc = TPM_AuditDigest_ExtendIn(tpm_state, transportDigest); + } + } + } + /* d. Create A2 a TPM_AUDIT_EVENT_OUT structure */ + /* i. Set A2 -> outputParms to the digest of the output parameters from the command */ + /* (1). Digest value according to the HMAC digest rules of the "above the line" parameters + (i.e. the first HMAC digest calculation). */ + /* ii. Set A2 -> auditCount to TPM_PERMANENT_DATA -> auditMonotonicCounter */ + /* e. Set TPM_STANY_DATA -> auditDigest to SHA-1 (TPM_STANY_DATA -> auditDigest || A2) */ + + /* Audit Generation Corner cases 3.a. TPM_SaveState: Only the input parameters are audited, and + the audit occurs before the state is saved. If an error occurs while or after the state is + saved, the audit still occurs. + */ + if ((rc == 0) && (ordinal != TPM_ORD_SaveState)) { + /* normal case, audit uses outParamDigest */ + if (!transportEncrypt) { + rc = TPM_AuditDigest_ExtendOut(tpm_state, outParamDigest); + } + /* 1. When the wrapped command requires auditing and the transport session specifies + encryption, the TPM MUST perform the audit. However, when computing the audit digest: + */ + else { + /* b. For output, only the ordinal and return code are audited. */ + if (rc == 0) { + nreturnCode = htonl(TPM_SUCCESS); /* only called when TPM_SUCCESS */ + nOrdinal = htonl(ordinal); + rc = TPM_SHA1(transportDigest, + sizeof(TPM_RESULT), &nreturnCode, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + 0, NULL); + } + if (rc == 0) { + rc = TPM_AuditDigest_ExtendOut(tpm_state, transportDigest); + } + } + } + /* 1. When, in performing the audit process, the TPM has an internal failure (unable to write, + SHA-1 failure etc.) the TPM MUST set the internal TPM state such that the TPM returns the + TPM_FAILEDSELFTEST error on subsequent attempts to execute a command. */ + /* 2. The return code for the command uses the following rules */ + /* a. Command result success, audit success -> return TPM_SUCCESS */ + /* b. Command result failure, no audit -> return command result failure */ + /* c. Command result success, audit failure -> return TPM_AUDITFAIL_SUCCESSFUL */ + /* 3. If the TPM is permanently nonrecoverable after an audit failure, then the TPM MUST always + return TPM_FAILEDSELFTEST for every command other than TPM_GetTestResult. This state must + persist regardless of power cycling, the execution of TPM_Init or any other actions. */ + if (rc != 0) { + rc = TPM_AUDITFAIL_SUCCESSFUL; + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return rc; +} + +/* + Processing Functions +*/ + +/* 7.1 TPM_GetCapability rev 99 + + This command returns current information regarding the TPM. + + The limitation on what can be returned in failure mode restricts the information a manufacturer + may return when capArea indicates TPM_CAP_MFR. +*/ + +TPM_RESULT TPM_Process_GetCapability(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_TAG returnCode = 0; /* command return code */ + + /* input parameters */ + TPM_CAPABILITY_AREA capArea; /* Partition of capabilities to be interrogated */ + TPM_SIZED_BUFFER subCap; /* Further definition of information */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + uint16_t subCap16 = 0; /* the subCap as a uint16_t */ + uint32_t subCap32 = 0; /* the subCap as a uint32_t */ + TPM_STORE_BUFFER capabilityResponse; /* response */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_GetCapability: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&subCap); /* freed @1 */ + TPM_Sbuffer_Init(&capabilityResponse); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get capArea parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&capArea, &command, ¶mSize); + } + /* get subCap parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetCapability: capArea %08x\n", capArea); + returnCode = TPM_SizedBuffer_Load(&subCap, &command, ¶mSize); + } + /* subCap is often a uint16_t or uint32_t, create them now */ + if (returnCode == TPM_SUCCESS) { + TPM_GetSubCapInt(&subCap16, &subCap32, &subCap); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + /* The shutdown test is delayed until after the subcap is calculated */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_NO_LOCKOUT); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetCapability: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + check state + */ + /* 1. The TPM validates the capArea and subCap indicators. If the information is available, the + TPM creates the response field and fills in the actual information. */ + /* 2. The structure document contains the list of caparea and subCap values */ + if (returnCode == TPM_SUCCESS) { + /* 3. If the TPM is in failure mode or limited operation mode, the TPM MUST return */ + if ((tpm_state->testState == TPM_TEST_STATE_FAILURE) || + (tpm_state->testState == TPM_TEST_STATE_LIMITED)) { + /* a. TPM_CAP_VERSION */ + /* b. TPM_CAP_VERSION_VAL */ + /* c. TPM_CAP_MFR */ + /* d. TPM_CAP_PROPERTY -> TPM_CAP_PROP_MANUFACTURER */ + /* e. TPM_CAP_PROPERTY -> TPM_CAP_PROP_DURATION */ + /* f. TPM_CAP_PROPERTY -> TPM_CAP_PROP_TIS_TIMEOUT */ + /* g. The TPM MAY return any other capability. */ + if ( + !(capArea == TPM_CAP_VERSION) && + !(capArea == TPM_CAP_VERSION_VAL) && + !(capArea == TPM_CAP_MFR) && + !((capArea == TPM_CAP_PROPERTY) && (subCap32 == TPM_CAP_PROP_MANUFACTURER)) && + !((capArea == TPM_CAP_PROPERTY) && (subCap32 == TPM_CAP_PROP_DURATION)) && + !((capArea == TPM_CAP_PROPERTY) && (subCap32 == TPM_CAP_PROP_TIS_TIMEOUT)) + ) { + if (tpm_state->testState == TPM_TEST_STATE_FAILURE) { + printf("TPM_Process_GetCapability: Error, shutdown capArea %08x subCap %08x\n", + capArea, subCap32); + returnCode = TPM_FAILEDSELFTEST; + } + else { + printf("TPM_Process_GetCapability: Limited operation, run self-test\n"); + returnCode = TPM_ContinueSelfTestCmd(tpm_state); + } + } + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetCapability: capArea %08x subCap32 subCap16 %08x %04x\n", + capArea, subCap32, subCap16); + returnCode = TPM_GetCapabilityCommon(&capabilityResponse, tpm_state, + capArea, subCap16, subCap32, &subCap); + } + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_GetCapability: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* store the capabilityResponse */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &capabilityResponse); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&subCap); /* @1 */ + TPM_Sbuffer_Delete(&capabilityResponse); /* @2 */ + return rcf; +} + +/* TPM_GetSubCapInt() converts from a TPM_SIZED_BUFFER to either a uint16_t or uint32_t as + applicable + + No return code is needed. If the size it not applicable, a 0 value is returned, which is + (fortunately) always illegal for subCap integral values. +*/ + +void TPM_GetSubCapInt(uint16_t *subCap16, + uint32_t *subCap32, + TPM_SIZED_BUFFER *subCap) +{ + *subCap16 = 0; /* default, means was not a uint16_t */ + *subCap32 = 0; /* default, means was not a uint32_t */ + if (subCap->size == sizeof(uint32_t)) { + *subCap32 = htonl(*(uint32_t *)subCap->buffer); + printf(" TPM_GetSubCapInt: subCap %08x\n", *subCap32); + } + else if (subCap->size == sizeof(uint16_t)) { + *subCap16 = htons(*(uint16_t *)subCap->buffer); + printf(" TPM_GetSubCapInt: subCap %04x\n", *subCap16); + } +} + + +/* TPM_GetCapabilityCommon() is common code for getting a capability. + + It loads the result to 'capabilityResponse' + + A previously called TPM_GetSubCapInt() converts the subCap buffer into a subCap16 if the size is + 2 or subCap32 if the size is 4. If the values are used, this function checks the size to ensure + that the incoming subCap parameter was correct for the capArea. +*/ + +TPM_RESULT TPM_GetCapabilityCommon(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_CAPABILITY_AREA capArea, + uint16_t subCap16, + uint32_t subCap32, + TPM_SIZED_BUFFER *subCap) + +{ + TPM_RESULT rc = 0; + + printf(" TPM_GetCapabilityCommon: capArea %08x\n", capArea); + switch (capArea) { + case TPM_CAP_ORD: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapOrd(capabilityResponse, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_ALG: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapAlg(capabilityResponse, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_PID: + if (subCap->size == sizeof(uint16_t)) { + rc = TPM_GetCapability_CapPid(capabilityResponse, subCap16); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_FLAG: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapFlag(capabilityResponse, tpm_state, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_PROPERTY: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapProperty(capabilityResponse, tpm_state, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_VERSION: + rc = TPM_GetCapability_CapVersion(capabilityResponse); + break; + case TPM_CAP_KEY_HANDLE: + /* This is command is available for backwards compatibility. It is the same as + TPM_CAP_HANDLE with a resource type of keys. */ + rc = TPM_KeyHandleEntries_StoreHandles(capabilityResponse, + tpm_state->tpm_key_handle_entries); + break; + case TPM_CAP_CHECK_LOADED: + rc = TPM_GetCapability_CapCheckLoaded(capabilityResponse, + tpm_state->tpm_key_handle_entries, + subCap); + break; + case TPM_CAP_SYM_MODE: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapSymMode(capabilityResponse, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_KEY_STATUS: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapKeyStatus(capabilityResponse, + tpm_state->tpm_key_handle_entries, + subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_NV_LIST: + rc = TPM_NVIndexEntries_GetNVList(capabilityResponse, &(tpm_state->tpm_nv_index_entries)); + break; + case TPM_CAP_MFR: + rc = TPM_GetCapability_CapMfr(capabilityResponse, tpm_state, subCap); + break; + case TPM_CAP_NV_INDEX: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapNVIndex(capabilityResponse, tpm_state, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_TRANS_ALG: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapTransAlg(capabilityResponse, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_HANDLE: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapHandle(capabilityResponse, tpm_state, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_TRANS_ES: + if (subCap->size == sizeof(uint16_t)) { + rc = TPM_GetCapability_CapTransEs(capabilityResponse, subCap16); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_AUTH_ENCRYPT: + if (subCap->size == sizeof(uint32_t)) { + rc = TPM_GetCapability_CapAuthEncrypt(capabilityResponse, subCap32); + } + else { + printf("TPM_GetCapabilityCommon: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; + case TPM_CAP_SELECT_SIZE: + rc = TPM_GetCapability_CapSelectSize(capabilityResponse, subCap); + break; +#if (TPM_REVISION >= 103) /* added for rev 103 */ + case TPM_CAP_DA_LOGIC: + rc = TPM_GetCapability_CapDaLogic(capabilityResponse, subCap, tpm_state); + break; +#endif + case TPM_CAP_VERSION_VAL: + rc = TPM_GetCapability_CapVersionVal(capabilityResponse, + &(tpm_state->tpm_permanent_data)); + break; + default: + printf("TPM_GetCapabilityCommon: Error, unsupported capArea %08x", capArea); + rc = TPM_BAD_MODE; + break; + } + return rc; +} + +/* Boolean value. + + TRUE indicates that the TPM supports the ordinal. + + FALSE indicates that the TPM does not support the ordinal. +*/ + +static TPM_RESULT TPM_GetCapability_CapOrd(TPM_STORE_BUFFER *capabilityResponse, + uint32_t ordinal) +{ + TPM_RESULT rc = 0; + tpm_process_function_t tpm_process_function; + TPM_BOOL supported; + + TPM_OrdinalTable_GetProcessFunction(&tpm_process_function, tpm_ordinal_table, ordinal); + /* determine of the ordinal is supported */ + if (tpm_process_function != TPM_Process_Unused) { + supported = TRUE; + } + /* if the processing function is 'Unused', it's not supported */ + else { + supported = FALSE; + } + printf(" TPM_GetCapability_CapOrd: Ordinal %08x, result %02x\n", + ordinal, supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* algorithmID is TPM_ALG_XX: A value from TPM_ALGORITHM_ID + + Boolean value. TRUE means that the TPM supports the asymmetric algorithm for TPM_Sign, TPM_Seal, + TPM_UnSeal and TPM_UnBind and related commands. FALSE indicates that the asymmetric algorithm is + not supported for these types of commands. The TPM MAY return TRUE or FALSE for other than + asymmetric algoroithms that it supports. Unassigned and unsupported algorithm IDs return FALSE. +*/ + +static TPM_RESULT TPM_GetCapability_CapAlg(TPM_STORE_BUFFER *capabilityResponse, + uint32_t algorithmID) +{ + TPM_RESULT rc = 0; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapAlg: algorithmID %08x\n", algorithmID); + if (algorithmID == TPM_ALG_RSA) { + supported = TRUE; + } + else { + supported = FALSE; + } + printf(" TPM_GetCapability_CapAlg: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* Boolean value. + + TRUE indicates that the TPM supports the protocol, + + FALSE indicates that the TPM does not support the protocol. +*/ + +static TPM_RESULT TPM_GetCapability_CapPid(TPM_STORE_BUFFER *capabilityResponse, + uint16_t protocolID) +{ + TPM_RESULT rc = 0; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapPid: protocolID %04hx\n", protocolID); + switch (protocolID) { + /* supported protocols */ + case TPM_PID_OIAP: + case TPM_PID_OSAP: + case TPM_PID_ADIP: + case TPM_PID_ADCP: + case TPM_PID_DSAP: + case TPM_PID_TRANSPORT: + case TPM_PID_OWNER: + supported = TRUE; + break; + /* unsupported protocols */ + default: + supported = FALSE; + break; + } + printf(" TPM_GetCapability_CapPid: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* + Either of the next two subcaps + + TPM_CAP_FLAG_PERMANENT Return the TPM_PERMANENT_FLAGS structure + + TPM_CAP_FLAG_VOLATILE Return the TPM_STCLEAR_FLAGS structure +*/ + +static TPM_RESULT TPM_GetCapability_CapFlag(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t capFlag) +{ + TPM_RESULT rc = 0; + + printf(" TPM_GetCapability_CapFlag: capFlag %08x\n", capFlag); + switch (capFlag) { + case TPM_CAP_FLAG_PERMANENT: + printf(" TPM_GetCapability_CapFlag: TPM_CAP_FLAG_PERMANENT\n");; + rc = TPM_PermanentFlags_StoreBytes(capabilityResponse, &(tpm_state->tpm_permanent_flags)); + break; + case TPM_CAP_FLAG_VOLATILE: + printf(" TPM_GetCapability_CapFlag: TPM_CAP_FLAG_VOLATILE\n"); + rc = TPM_StclearFlags_Store(capabilityResponse, &(tpm_state->tpm_stclear_flags)); + break; + default: + printf("TPM_GetCapability_CapFlag: Error, illegal capFlag %08x\n", capFlag); + rc = TPM_BAD_MODE; + break; + } + return rc; +} + +/* TPM_GetCapability_CapProperty() handles Subcap values for CAP_PROPERTY rev 100 + */ + +static TPM_RESULT TPM_GetCapability_CapProperty(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t capProperty) +{ + TPM_RESULT rc = 0; + uint32_t uint32; + uint32_t uint32a; + uint32_t dummy; /* to hold unused response parameter */ + + printf(" TPM_GetCapability_CapProperty: capProperty %08x\n", capProperty); + switch (capProperty) { + case TPM_CAP_PROP_PCR: /* Returns the number of PCR registers supported by the TPM */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_PCR %u\n", TPM_NUM_PCR); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_NUM_PCR); + break; + case TPM_CAP_PROP_DIR: /* Returns the number of DIR registers under control of the TPM + owner supported by the TPM. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DIR %u\n", TPM_AUTHDIR_SIZE); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_AUTHDIR_SIZE); + break; + case TPM_CAP_PROP_MANUFACTURER: /* Returns the Identifier of the TPM manufacturer. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MANUFACTURER %.4s\n", + TPM_MANUFACTURER); + rc = TPM_Sbuffer_Append(capabilityResponse, (const unsigned char *)TPM_MANUFACTURER, 4); + break; + case TPM_CAP_PROP_KEYS: /* Returns the number of 2048-bit RSA keys that can be loaded. This + MAY vary with time and circumstances. */ + TPM_KeyHandleEntries_GetSpace(&uint32, tpm_state->tpm_key_handle_entries); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_KEYS %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_MIN_COUNTER: /* uint32_t. The minimum amount of time in 10ths of a second + that must pass between invocations of incrementing the + monotonic counter. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MIN_COUNTER\n"); + rc = TPM_Sbuffer_Append32(capabilityResponse, 0); + break; + case TPM_CAP_PROP_AUTHSESS: /* The number of available authorization sessions. This MAY + vary with time and circumstances. */ + TPM_AuthSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.authSessions); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_AUTHSESS space %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_TRANSESS: /* The number of available transport sessions. This MAY vary + with time and circumstances. */ + TPM_TransportSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.transSessions); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_TRANSESS space %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_COUNTERS: /* The number of available monotonic counters. This MAY vary + with time and circumstances. */ + TPM_Counters_GetSpace(&uint32, tpm_state->tpm_permanent_data.monotonicCounter); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_COUNTERS %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_MAX_AUTHSESS: /* The maximum number of loaded authorization sessions the + TPM supports. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_AUTHSESS %u\n", + TPM_MIN_AUTH_SESSIONS); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_AUTH_SESSIONS); + break; + case TPM_CAP_PROP_MAX_TRANSESS: /* The maximum number of loaded transport sessions the TPM + supports. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_TRANSESS %u\n", + TPM_MIN_TRANS_SESSIONS); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_TRANS_SESSIONS); + break; + case TPM_CAP_PROP_MAX_COUNTERS: /* The maximum number of monotonic counters under control of + TPM_CreateCounter */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_COUNTERS %u\n", + TPM_MIN_COUNTERS); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_COUNTERS); + break; + case TPM_CAP_PROP_MAX_KEYS: /* The maximum number of 2048 RSA keys that the TPM can + support. The number does not include the EK or SRK. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_KEYS %u\n", TPM_KEY_HANDLES); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_KEY_HANDLES); + break; + case TPM_CAP_PROP_OWNER: /* A value of TRUE indicates that the TPM has successfully installed + an owner. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_OWNER %02x\n", + tpm_state->tpm_permanent_data.ownerInstalled); + rc = TPM_Sbuffer_Append(capabilityResponse, + &(tpm_state->tpm_permanent_data.ownerInstalled), sizeof(TPM_BOOL)); + break; + case TPM_CAP_PROP_CONTEXT: /* The number of available saved session slots. This MAY + vary with time and circumstances. */ + TPM_ContextList_GetSpace(&uint32, &dummy, tpm_state->tpm_stclear_data.contextList); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_CONTEXT %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_MAX_CONTEXT: /* The maximum number of saved session slots. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_CONTEXT %u\n", + TPM_MIN_SESSION_LIST); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_SESSION_LIST); + break; + case TPM_CAP_PROP_FAMILYROWS: /* The number of rows in the family table */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_FAMILYROWS %u\n", + TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + break; + case TPM_CAP_PROP_TIS_TIMEOUT: + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_TIS_TIMEOUT\n"); + rc = TPM_GetCapability_CapPropTisTimeout(capabilityResponse); + break; + case TPM_CAP_PROP_STARTUP_EFFECT: /* The TPM_STARTUP_EFFECTS structure */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_STARTUP_EFFECT %08x\n", + TPM_STARTUP_EFFECTS_VALUE); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_STARTUP_EFFECTS_VALUE); + break; + case TPM_CAP_PROP_DELEGATE_ROW: /* The size of the delegate table in rows. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DELEGATE_ENTRIES %u\n", + TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + break; + case TPM_CAP_PROP_MAX_DAASESS: /* The maximum number of loaded DAA sessions (join or sign) + that the TPM supports */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DAA_MAX\n"); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MIN_DAA_SESSIONS); + break; + case TPM_CAP_PROP_DAASESS: /* The number of available DAA sessions. This may vary with + time and circumstances */ + TPM_DaaSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.daaSessions); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_SESSION_DAA space %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_CONTEXT_DIST: /* The maximum distance between context count values. This + MUST be at least 2^16-1. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_CONTEXT_DIST\n"); + rc = TPM_Sbuffer_Append32(capabilityResponse, 0xffffffff); + break; + case TPM_CAP_PROP_DAA_INTERRUPT: /* BOOL. 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 */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DAA_INTERRUPT\n"); + rc = TPM_Sbuffer_Append8(capabilityResponse, TRUE); + break; + case TPM_CAP_PROP_SESSIONS: /* UNIT32. The number of available authorization and transport + sessions from the pool. This may vary with time and + circumstances. */ + TPM_AuthSessions_GetSpace(&uint32, tpm_state->tpm_stclear_data.authSessions); + TPM_TransportSessions_GetSpace(&uint32a, tpm_state->tpm_stclear_data.transSessions); + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_SESSIONS %u + %u\n", uint32, uint32a); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32 + uint32a); + break; + case TPM_CAP_PROP_MAX_SESSIONS: /* uint32_t. The maximum number of sessions the + TPM supports. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_SESSIONS\n"); + rc = TPM_Sbuffer_Append32(capabilityResponse, + TPM_MIN_AUTH_SESSIONS + TPM_MIN_TRANS_SESSIONS); + break; + case TPM_CAP_PROP_CMK_RESTRICTION: /* uint32_t TPM_Permanent_Data -> restrictDelegate */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_CMK_RESTRICTION %08x\n", + tpm_state->tpm_permanent_data.restrictDelegate); + rc = TPM_Sbuffer_Append32(capabilityResponse, + tpm_state->tpm_permanent_data.restrictDelegate); + break; + case TPM_CAP_PROP_DURATION: + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_DURATION\n"); + rc = TPM_GetCapability_CapPropDuration(capabilityResponse); + break; + case TPM_CAP_PROP_ACTIVE_COUNTER: /* TPM_COUNT_ID. The id of the current counter. 0xff..ff if + no counter is active */ + TPM_Counters_GetActiveCounter(&uint32, tpm_state->tpm_stclear_data.countID); + /* The illegal value after releasing an active counter must be mapped back to the null + value */ + if (uint32 == TPM_COUNT_ID_ILLEGAL) { + uint32 = TPM_COUNT_ID_NULL; + } + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_ACTIVE_COUNTER %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + break; + case TPM_CAP_PROP_MAX_NV_AVAILABLE: /* uint32_t. Deprecated. The maximum number of NV space + that can be allocated, MAY vary with time and + circumstances. This capability was not implemented + consistently, and is replaced by + TPM_NV_INDEX_TRIAL. */ + rc = TPM_NVIndexEntries_GetFreeSpace(&uint32, &(tpm_state->tpm_nv_index_entries)); + if (rc == 0) { + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_MAX_NV_AVAILABLE %u\n", uint32); + rc = TPM_Sbuffer_Append32(capabilityResponse, uint32); + } + /* There should always be free space >= 0. If the call fails here, there is an internal + error. */ + else { + printf(" TPM_GetCapability_CapProperty: Error (fatal) " + "in TPM_CAP_PROP_MAX_NV_AVAILABLE\n"); + rc = TPM_FAIL; + } + break; + case TPM_CAP_PROP_INPUT_BUFFER: /* uint32_t. The size of the TPM input and output buffers in + bytes. */ + printf(" TPM_GetCapability_CapProperty: TPM_CAP_PROP_INPUT_BUFFER %u\n", + TPM_BUFFER_MAX); + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_BUFFER_MAX); + break; + default: + printf("TPM_GetCapability_CapProperty: Error, illegal capProperty %08x\n", capProperty); + rc = TPM_BAD_MODE; + break; + } + return rc; +} + +/* TPM_VERSION structure. The Major and Minor must indicate 1.1. + + The manufacturer information MUST indicate the firmware version of the TPM. + + Any software using this structure MUST be aware that when included in a structure the value MUST + be 1.1.0.0, when reported by this command the manufacturer information MAY include firmware + versions. The use of this value is deprecated, new software SHOULD use TPM_CAP_VERSION_VAL to + obtain version information regarding the TPM. + + Return 0.0 for revision for 1.1 backward compatibility, since TPM_PERMANENT_DATA now holds the + new type TPM_VERSION_BYTE. +*/ + +static TPM_RESULT TPM_GetCapability_CapVersion(TPM_STORE_BUFFER *capabilityResponse) +{ + TPM_RESULT rc = 0; + TPM_STRUCT_VER tpm_struct_ver; + + TPM_StructVer_Init(&tpm_struct_ver); + printf(" TPM_GetCapability_CapVersion: %u.%u.%u.%u\n", + tpm_struct_ver.major, tpm_struct_ver.minor, + tpm_struct_ver.revMajor, tpm_struct_ver.revMinor); + rc = TPM_StructVer_Store(capabilityResponse, &tpm_struct_ver); + return rc; +} + +/* A Boolean value. + + TRUE indicates that the TPM has enough memory available to load a key of the type specified by + ALGORITHM. + + FALSE indicates that the TPM does not have enough memory. +*/ + +static TPM_RESULT TPM_GetCapability_CapCheckLoaded(TPM_STORE_BUFFER *capabilityResponse, + const TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry, + TPM_SIZED_BUFFER *subCap) +{ + TPM_RESULT rc = 0; + uint32_t stream_size; + unsigned char *stream; + TPM_KEY_PARMS keyParms; + TPM_BOOL isSpace; + uint32_t index; + + TPM_KeyParms_Init(&keyParms); /* freed @1 */ + if (rc == 0) { + /* make temporary copies so the subCap is not touched */ + stream = subCap->buffer; + stream_size = subCap->size; + rc = TPM_KeyParms_Load(&keyParms, &stream, &stream_size); + } + if (rc == 0) { + if (keyParms.algorithmID == TPM_ALG_RSA) { + TPM_KeyHandleEntries_IsSpace(&isSpace, &index, tpm_key_handle_entry); + } + else { + printf(" TPM_GetCapability_CapCheckLoaded: algorithmID %08x is not TPM_ALG_RSA %08x\n", + keyParms.algorithmID, TPM_ALG_RSA); + isSpace = FALSE; + } + } + if (rc == 0) { + printf(" TPM_GetCapability_CapCheckLoaded: Return %02x\n", isSpace); + rc = TPM_Sbuffer_Append(capabilityResponse, &isSpace, sizeof(TPM_BOOL)); + } + TPM_KeyParms_Delete(&keyParms); /* @1 */ + return rc; +} + +/* (Deprecated) This indicates the mode of a symmetric encryption. Mode is Electronic CookBook (ECB) + or some other such mechanism. +*/ + +static TPM_RESULT TPM_GetCapability_CapSymMode(TPM_STORE_BUFFER *capabilityResponse, + TPM_SYM_MODE symMode) +{ + TPM_RESULT rc = 0; + + symMode = symMode; /* not currently used */ + printf(" TPM_GetCapability_CapSymMode: Return %02x\n", FALSE); + rc = TPM_Sbuffer_Append8(capabilityResponse, FALSE); + return rc; +} + +/* Boolean value of ownerEvict. The handle MUST point to a valid key handle. + */ + +static TPM_RESULT TPM_GetCapability_CapKeyStatus(TPM_STORE_BUFFER *capabilityResponse, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entries, + uint32_t tpm_key_handle) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* corresponding to handle */ + TPM_BOOL ownerEvict; + + printf(" TPM_GetCapability_CapKeyStatus: key handle %08x\n", tpm_key_handle); + /* map from the handle to the TPM_KEY structure */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_key_handle_entries, + tpm_key_handle); + if (rc != 0) { + printf("TPM_GetCapability_CapKeyStatus: Error, key handle %08x not found\n", + tpm_key_handle); + } + } + /* test the ownerEvict bit */ + if (rc == 0) { + ownerEvict = (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) ? + TRUE : FALSE;; + printf(" TPM_GetCapability_CapKeyStatus: return %02x\n", ownerEvict); + rc = TPM_Sbuffer_Append(capabilityResponse, &ownerEvict, sizeof(TPM_BOOL)); + } + return rc; +} + +/* Manufacturer specific. The manufacturer may provide any additional information regarding the TPM + and the TPM state but MUST not expose any sensitive information. +*/ + +static TPM_RESULT TPM_GetCapability_CapMfr(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_SIZED_BUFFER *subCap) +{ + TPM_RESULT rc = 0; + uint32_t subCap32; + + /* all of the subCaps are at least a uint32_t. Some have more data */ + if (rc == 0) { + if (subCap->size >= sizeof(uint32_t)) { + subCap32 = htonl(*(uint32_t *)subCap->buffer); + printf(" TPM_GetCapability_CapMfr: subCap %08x\n", subCap32); + } + else { + printf("TPM_GetCapability_CapMfr: Error, subCap size %u < %lu\n", + subCap->size, (unsigned long)sizeof(uint32_t)); + rc = TPM_BAD_MODE; + } + } + /* switch on the subCap and append the get capability response to the capabilityResponse + buffer */ + if (rc == 0) { + switch(subCap32) { +#ifdef TPM_POSIX + case TPM_CAP_PROCESS_ID: + if (subCap->size == sizeof(uint32_t)) { + pid_t pid = getpid(); + printf(" TPM_GetCapability_CapMfr: TPM_CAP_PROCESS_ID %u\n", (uint32_t)pid); + rc = TPM_Sbuffer_Append32(capabilityResponse, (uint32_t)pid); + } + else { + printf("TPM_GetCapability_CapMfr: Error, Bad subCap size %u\n", subCap->size); + rc = TPM_BAD_MODE; + } + break; +#endif + default: + capabilityResponse = capabilityResponse; /* not used */ + tpm_state = tpm_state; /* not used */ + printf("TPM_GetCapability_CapMfr: Error, unsupported subCap %08x\n", subCap32); + rc = TPM_BAD_MODE; + break; + } + } + return rc; +} + +/* Returns a TPM_NV_DATA_PUBLIC structure that indicates the values for the TPM_NV_INDEX +*/ + +static TPM_RESULT TPM_GetCapability_CapNVIndex(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + uint32_t nvIndex) +{ + TPM_RESULT rc = 0; + TPM_NV_DATA_PUBLIC *tpm_nv_data_public; + + printf(" TPM_GetCapability_CapNVIndex: nvIndex %08x\n", nvIndex); + /* map from the nvIndex to the TPM_NV_DATA_PUBLIC structure */ + if (rc == 0) { + rc = TPM_NVIndexEntries_GetDataPublic(&tpm_nv_data_public, + &(tpm_state->tpm_nv_index_entries), + nvIndex); + } + /* serialize the structure */ + if (rc == 0) { + rc = TPM_NVDataPublic_Store(capabilityResponse, tpm_nv_data_public, + FALSE); /* do not optimize digestAtRelease */ + } + return rc; +} + +/* Returns a Boolean value. + + TRUE means that the TPM supports the algorithm for TPM_EstablishTransport, TPM_ExecuteTransport + and TPM_ReleaseTransportSigned. + + FALSE indicates that for these three commands the algorithm is not supported." +*/ + +static TPM_RESULT TPM_GetCapability_CapTransAlg(TPM_STORE_BUFFER *capabilityResponse, + TPM_ALGORITHM_ID algorithmID) +{ + TPM_RESULT rc = 0; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapTransAlg: algorithmID %08x\n", algorithmID); + TPM_TransportPublic_CheckAlgId(&supported, algorithmID); + printf(" TPM_GetCapability_CapTransAlg: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* Returns a TPM_KEY_HANDLE_LIST structure that enumerates all handles currently loaded in the TPM + for the given resource type. + + TPM_KEY_HANDLE_LIST is the number of handles followed by a list of the handles. + + When describing keys the handle list only contains the number of handles that an external manager + can operate with and does not include the EK or SRK. + + Legal resources are TPM_RT_KEY, TPM_RT_AUTH, TPM_RT_TRANS, TPM_RT_COUNTER + + TPM_RT_CONTEXT is valid and returns not a list of handles but a list of the context count values. +*/ + +static TPM_RESULT TPM_GetCapability_CapHandle(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_RESOURCE_TYPE resourceType) +{ + TPM_RESULT rc = 0; + + printf(" TPM_GetCapability_CapHandle: resourceType %08x\n", resourceType); + switch (resourceType) { + case TPM_RT_KEY: + printf(" TPM_GetCapability_CapHandle: TPM_RT_KEY\n"); + rc = TPM_KeyHandleEntries_StoreHandles(capabilityResponse, + tpm_state->tpm_key_handle_entries); + break; + case TPM_RT_AUTH: + printf(" TPM_GetCapability_CapHandle: TPM_RT_AUTH\n"); + rc = TPM_AuthSessions_StoreHandles(capabilityResponse, + tpm_state->tpm_stclear_data.authSessions); + break; + case TPM_RT_TRANS: + printf(" TPM_GetCapability_CapHandle: TPM_RT_TRANS\n"); + rc = TPM_TransportSessions_StoreHandles(capabilityResponse, + tpm_state->tpm_stclear_data.transSessions); + break; + case TPM_RT_CONTEXT: + printf(" TPM_GetCapability_CapHandle: TPM_RT_CONTEXT\n"); + rc = TPM_ContextList_StoreHandles(capabilityResponse, + tpm_state->tpm_stclear_data.contextList); + break; + case TPM_RT_COUNTER: + printf(" TPM_GetCapability_CapHandle: TPM_RT_COUNTER\n"); + rc = TPM_Counters_StoreHandles(capabilityResponse, + tpm_state->tpm_permanent_data.monotonicCounter); + break; + case TPM_RT_DAA_TPM: + printf(" TPM_GetCapability_CapHandle: TPM_RT_DAA_TPM\n"); + rc = TPM_DaaSessions_StoreHandles(capabilityResponse, + tpm_state->tpm_stclear_data.daaSessions); + break; + default: + printf("TPM_GetCapability_CapHandle: Error, illegal resource type %08x\n", + resourceType); + rc = TPM_BAD_PARAMETER; + } + return rc; +} + +/* Returns Boolean value. + + TRUE means the TPM supports the encryption scheme in a transport session. +*/ + +static TPM_RESULT TPM_GetCapability_CapTransEs(TPM_STORE_BUFFER *capabilityResponse, + TPM_ENC_SCHEME encScheme) +{ + TPM_RESULT rc = 0; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapTransEs: encScheme %04hx\n", encScheme); + switch (encScheme) { + /* supported protocols */ + case TPM_ES_SYM_CTR: + case TPM_ES_SYM_OFB: + supported = TRUE; + break; + /* unsupported protocols */ + case TPM_ES_RSAESPKCSv15: + case TPM_ES_RSAESOAEP_SHA1_MGF1: + default: + supported = FALSE; + break; + } + printf(" TPM_GetCapability_CapTransEs: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* Boolean value. + + TRUE indicates that the TPM supports the encryption algorithm in OSAP encryption of AuthData + values +*/ + +static TPM_RESULT TPM_GetCapability_CapAuthEncrypt(TPM_STORE_BUFFER *capabilityResponse, + TPM_ALGORITHM_ID algorithmID) +{ + TPM_RESULT rc = 0; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapAuthEncrypt: algorithmID %08x\n", algorithmID); + switch (algorithmID) { + case TPM_ALG_XOR: + case TPM_ALG_AES128: + /* supported protocols */ + supported = TRUE; + break; + case TPM_ALG_RSA: + case TPM_ALG_SHA: + case TPM_ALG_HMAC: + case TPM_ALG_MGF1: + case TPM_ALG_AES192: + case TPM_ALG_AES256: + default: + /* unsupported protocols */ + supported = FALSE; + break; + } + printf(" TPM_GetCapability_CapAuthEncrypt: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + return rc; +} + +/* Boolean value. + + TRUE indicates that the TPM supports the size for the given version. + + For instance a request could ask for version 1.1 size 2 and the TPM would indicate TRUE. For 1.1 + size 3 the TPM would indicate FALSE. For 1.2 size 3 the TPM would indicate TRUE. +*/ + +static TPM_RESULT TPM_GetCapability_CapSelectSize(TPM_STORE_BUFFER *capabilityResponse, + TPM_SIZED_BUFFER *subCap) +{ + TPM_RESULT rc = 0; + TPM_SELECT_SIZE tpm_select_size; + unsigned char *stream; + uint32_t stream_size; + TPM_BOOL supported; + + printf(" TPM_GetCapability_CapSelectSize:\n"); + TPM_SelectSize_Init(&tpm_select_size); /* no free required */ + /* deserialize the subCap to the structure */ + if (rc == 0) { + stream = subCap->buffer; + stream_size = subCap->size; + rc = TPM_SelectSize_Load(&tpm_select_size, &stream , &stream_size); + } + if (rc == 0) { + /* The TPM MUST return an error if sizeOfSelect is 0 */ + printf(" TPM_GetCapability_CapSelectSize: subCap reqSize %u\n", + tpm_select_size.reqSize); + if ((tpm_select_size.reqSize > (TPM_NUM_PCR/CHAR_BIT)) || + (tpm_select_size.reqSize == 0)) { + supported = FALSE; + } + else { + supported = TRUE; + } + } + if (rc == 0) { + printf(" TPM_GetCapability_CapSelectSize: Result %08x\n", supported); + rc = TPM_Sbuffer_Append(capabilityResponse, &supported, sizeof(TPM_BOOL)); + } + return rc; +} + +#if (TPM_REVISION >= 103) /* added for rev 103 */ +/* TPM_GetCapability_CapDaLogic() rev 100 + + A TPM_DA_INFO or TPM_DA_INFO_LIMITED structure that returns data according to the selected entity + type (e.g., TPM_ET_KEYHANDLE, TPM_ET_OWNER, TPM_ET_SRK, TPM_ET_COUNTER, TPM_ET_OPERATOR, + etc.). If the implemented dictionary attack logic does not support different secret types, the + entity type can be ignored. +*/ + +static TPM_RESULT TPM_GetCapability_CapDaLogic(TPM_STORE_BUFFER *capabilityResponse, + TPM_SIZED_BUFFER *subCap, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_DA_INFO_LIMITED tpm_da_info_limited; + TPM_DA_INFO tpm_da_info; + + printf(" TPM_GetCapability_CapDaLogic:\n"); + TPM_DaInfoLimited_Init(&tpm_da_info_limited); /* freed @1 */ + TPM_DaInfo_Init(&tpm_da_info); /* freed @2 */ + subCap = subCap; /* dictionary attack mitigation not per entity type in this + implementation. */ + /* if disableFullDALogicInfo is TRUE, the full dictionary attack TPM_GetCapability info is + deactivated. The returned structure is TPM_DA_INFO_LIMITED. */ + if (tpm_state->tpm_permanent_flags.disableFullDALogicInfo) { + TPM_DaInfoLimited_Set(&tpm_da_info_limited, tpm_state); + rc = TPM_DaInfoLimited_Store(capabilityResponse, &tpm_da_info_limited); + + } + /* if disableFullDALogicInfo is FALSE, the full dictionary attack TPM_GetCapability + info is activated. The returned structure is + TPM_DA_INFO. */ + else { + TPM_DaInfo_Set(&tpm_da_info, tpm_state); + rc = TPM_DaInfo_Store(capabilityResponse, &tpm_da_info); + } + TPM_DaInfoLimited_Delete(&tpm_da_info_limited); /* @1 */ + TPM_DaInfo_Delete(&tpm_da_info); /* @2 */ + return rc; +} +#endif + +/* Returns TPM_CAP_VERSION_INFO structure. + + The TPM fills in the structure and returns the information indicating what the TPM currently + supports. +*/ + +static TPM_RESULT TPM_GetCapability_CapVersionVal(TPM_STORE_BUFFER *capabilityResponse, + TPM_PERMANENT_DATA *tpm_permanent_data) +{ + TPM_RESULT rc = 0; + TPM_CAP_VERSION_INFO tpm_cap_version_info; + + printf(" TPM_GetCapability_CapVersionVal:\n"); + TPM_CapVersionInfo_Set(&tpm_cap_version_info, tpm_permanent_data); /* freed @1 */ + printf(" TPM_GetCapability_CapVersionVal: specLevel %04hx\n", tpm_cap_version_info.specLevel); + printf(" TPM_GetCapability_CapVersionVal: errataRev %02x\n", tpm_cap_version_info.errataRev); + printf(" TPM_GetCapability_CapVersionVal: revMajor %02x revMinor %02x\n", + tpm_cap_version_info.version.revMajor, tpm_cap_version_info.version.revMinor); + printf(" TPM_GetCapability_CapVersionVal: tpmVendorID %02x %02x %02x %02x\n", + tpm_cap_version_info.tpmVendorID[0], + tpm_cap_version_info.tpmVendorID[1], + tpm_cap_version_info.tpmVendorID[2], + tpm_cap_version_info.tpmVendorID[3]); + rc = TPM_CapVersionInfo_Store(capabilityResponse, &tpm_cap_version_info); + TPM_CapVersionInfo_Delete(&tpm_cap_version_info); /* @1 */ + return rc; +} + +/* Returns a 4 element array of uint32_t values each denoting the timeout value in microseconds for + the following in this order: + + TIMEOUT_A, TIMEOUT_B, TIMEOUT_C, TIMEOUT_D + + Where these timeouts are to be used is determined by the platform specific TPM Interface + Specification. +*/ + +static TPM_RESULT TPM_GetCapability_CapPropTisTimeout(TPM_STORE_BUFFER *capabilityResponse) +{ + TPM_RESULT rc = 0; + + printf(" TPM_GetCapability_CapPropTisTimeout:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_A); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_B); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_C); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_TIMEOUT_D); + } + return rc; +} + +/* Returns a 3 element array of uint32_t values each denoting the duration value in microseconds of + the duration of the three classes of commands: Small, Medium and Long in the following in this + order: + + SMALL_DURATION, MEDIUM_DURATION, LONG_DURATION +*/ + +static TPM_RESULT TPM_GetCapability_CapPropDuration(TPM_STORE_BUFFER *capabilityResponse) +{ + TPM_RESULT rc = 0; + + printf(" TPM_GetCapability_CapPropDuration:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_SMALL_DURATION); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_MEDIUM_DURATION); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(capabilityResponse, TPM_LONG_DURATION); + } + return rc; +} + +/* 7.3 TPM_GetCapabilityOwner rev 98 + + TPM_GetCapabilityOwner enables the TPM Owner to retrieve all the non-volatile flags and the + volatile flags in a single operation. This command is deprecated, mandatory. + + The flags summarize many operational aspects of the TPM. The information represented by some + flags is private to the TPM Owner. So, for simplicity, proof of ownership of the TPM must be + presented to retrieve the set of flags. When necessary, the flags that are not private to the + Owner can be deduced by Users via other (more specific) means. + + The normal TPM authentication mechanisms are sufficient to prove the integrity of the + response. No additional integrity check is required. + + For 31>=N>=0 + + 1. Bit-N of the TPM_PERMANENT_FLAGS structure is the Nth bit after the opening bracket in the + definition of TPM_PERMANENT_FLAGS in the version of the specification indicated by the parameter + "version". The bit immediately after the opening bracket is the 0th bit. + + 2. Bit-N of the TPM_STCLEAR_FLAGS structure is the Nth bit after the opening bracket in the + definition of TPM_STCLEAR_FLAGS in the version of the specification indicated by the parameter + "version". The bit immediately after the opening bracket is the 0th bit. + + 3. Bit-N of non_volatile_flags corresponds to the Nth bit in TPM_PERMANENT_FLAGS, and the lsb of + non_volatile_flags corresponds to bit0 of TPM_PERMANENT_FLAGS + + 4. Bit-N of volatile_flags corresponds to the Nth bit in TPM_STCLEAR_FLAGS, and the lsb of + volatile_flags corresponds to bit0 of TPM_STCLEAR_FLAGS +*/ + +TPM_RESULT TPM_Process_GetCapabilityOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for Owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session */ + TPM_AUTHDATA ownerAuth; /* The authorization session digest for inputs and owner + authentication. HMAC key: ownerAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_VERSION version; /* A properly filled out version structure. */ + uint32_t non_volatile_flags; /* The current state of the non-volatile flags. */ + uint32_t volatile_flags; /* The current state of the volatile flags. */ + + printf("TPM_Process_GetCapabilityOwner: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetCapabilityOwner: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. The TPM validates that the TPM Owner authorizes the command. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. The TPM creates the parameter non_volatile_flags by setting each bit to the same state as + the corresponding bit in TPM_PERMANENT_FLAGS. Bits in non_volatile_flags for which there is + no corresponding bit in TPM_PERMANENT_FLAGS are set to zero. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentFlags_StoreBitmap(&non_volatile_flags, + &(tpm_state->tpm_permanent_flags)); + } + /* 3. The TPM creates the parameter volatile_flags by setting each bit to the same state as the + corresponding bit in TPM_STCLEAR_FLAGS. Bits in volatile_flags for which there is no + corresponding bit in TPM_STCLEAR_FLAGS are set to zero. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_StclearFlags_StoreBitmap(&volatile_flags, + &(tpm_state->tpm_stclear_flags)); + } + /* 4. The TPM generates the parameter "version". */ + if (returnCode == TPM_SUCCESS) { + TPM_Version_Set(&version, &(tpm_state->tpm_permanent_data)); + } + /* 5. The TPM returns non_volatile_flags, volatile_flags and version to the caller. */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetCapabilityOwner: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the version */ + returnCode = TPM_Version_Store(response, &version); + } + /* return the non_volatile_flags */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, non_volatile_flags); + } + /* return the volatile_flags */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, volatile_flags); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + return rcf; +} + +/* 29.1 TPM_GetCapabilitySigned rev 94 + + TPM_GetCapabilitySigned is almost the same as TPM_GetCapability. The differences are that the + input includes a challenge (a nonce) and the response includes a digital signature to vouch for + the source of the answer. + + If a caller itself requires proof, it is sufficient to use any signing key for which only the TPM + and the caller have AuthData. + + If a caller requires proof for a third party, the signing key must be one whose signature is + trusted by the third party. A TPM-identity key may be suitable. +*/ + +TPM_RESULT TPM_Process_GetCapabilitySigned(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The handle of a loaded key that can perform digital + signatures. */ + TPM_NONCE antiReplay; /* Nonce provided to allow caller to defend against replay + of messages */ + TPM_CAPABILITY_AREA capArea = 0; /* Partition of capabilities to be interrogated */ + TPM_SIZED_BUFFER subCap; /* Further definition of information */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the use + of keyHandle. HMAC key: key.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + uint16_t subCap16; /* the subCap as a uint16_t */ + uint32_t subCap32; /* the subCap as a uint32_t */ + TPM_STORE_BUFFER r1Response; /* capability response */ + const unsigned char *r1_buffer; /* r1 serialization */ + uint32_t r1_length; + TPM_DIGEST s1; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_VERSION version; /* A properly filled out version structure. */ + TPM_SIZED_BUFFER resp; /* The capability response */ + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_GetCapabilitySigned: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&subCap); /* freed @1 */ + TPM_SizedBuffer_Init(&resp); /* freed @2 */ + TPM_SizedBuffer_Init(&sig); /* freed @3 */ + TPM_Sbuffer_Init(&r1Response); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetCapabilitySigned: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get capArea parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&capArea, &command, ¶mSize); + } + /* get get subCap parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&subCap, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetCapabilitySigned: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* 1. The TPM validates the authority to use keyHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_GetCapabilitySigned: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM MUST validate the authorization to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + + + /* subCap is often a uint16_t or uint32_t, create them now */ + if (returnCode == TPM_SUCCESS) { + TPM_GetSubCapInt(&subCap16, &subCap32, &subCap); + } + /* 2. The TPM calls TPM_GetCapability passing the capArea and subCap fields and saving the resp + field as R1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetCapabilityCommon(&r1Response, tpm_state, + capArea, subCap16, subCap32, &subCap); + } + if (returnCode == TPM_SUCCESS) { + /* get the capability r1 serialization */ + TPM_Sbuffer_Get(&r1Response, &r1_buffer, &r1_length); + printf("TPM_Process_GetCapabilitySigned: resp length %08x\n", r1_length); + TPM_PrintFour("TPM_Process_GetCapabilitySigned: Hashing resp", r1_buffer); + TPM_PrintFour("TPM_Process_GetCapabilitySigned: antiReplay", antiReplay); + /* 3. The TPM creates S1 by taking a SHA1 hash of the concatenation (r1 || antiReplay). */ + returnCode = TPM_SHA1(s1, + r1_length, r1_buffer, + TPM_NONCE_SIZE, antiReplay, + 0, NULL); + } + /* 4. The TPM validates the authority to use keyHandle */ + /* The key in keyHandle MUST have a KEYUSAGE value of type TPM_KEY_SIGNING or TPM_KEY_LEGACY or + TPM_KEY_IDENTITY. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + ((sigKey->keyUsage) != TPM_KEY_IDENTITY) && + ((sigKey->keyUsage) != TPM_KEY_LEGACY)) { + printf("TPM_Process_GetCapabilitySigned: Error, keyUsage %04hx is invalid\n", + sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. The TPM creates a digital signature of S1 using the key in keyHandle and returns the + result in sig. */ + if (returnCode == TPM_SUCCESS) { + if (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) { + printf("TPM_Process_GetCapabilitySigned: Error, inappropriate signature scheme %04x\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INAPPROPRIATE_SIG; + } + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_GetCapabilitySigned: Signing s1", s1); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + s1, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* signing key and parameters */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetCapabilitySigned: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the version */ + TPM_Version_Set(&version, &(tpm_state->tpm_permanent_data)); + returnCode = TPM_Version_Store(response, &version); + } + /* return the capability response size */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, r1_length); + } + /* return the capability response */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, r1_buffer, r1_length); + } + /* return the signature */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&subCap); /* @1 */ + TPM_SizedBuffer_Delete(&resp); /* @2 */ + TPM_SizedBuffer_Delete(&sig); /* @3 */ + TPM_Sbuffer_Delete(&r1Response); /* @4 */ + return rcf; +} + +/* 7.2 TPM_SetCapability rev 96 + + This command sets values in the TPM +*/ + +TPM_RESULT TPM_Process_SetCapability(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_TAG returnCode = 0; /* command return code */ + + /* input parameters */ + TPM_CAPABILITY_AREA capArea; /* Partition of capabilities to be set */ + TPM_SIZED_BUFFER subCap; /* Further definition of information */ + TPM_SIZED_BUFFER setValue; /* The value to set */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA ownerAuth; /* Authorization. HMAC key: owner.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data; /* session data for authHandle */ + TPM_SECRET *hmacKey; + uint16_t subCap16; /* the subCap as a uint16_t */ + uint32_t subCap32; /* the subCap as a uint32_t */ + TPM_BOOL ownerAuthorized = FALSE; /* TRUE if owner authorization validated */ + TPM_BOOL presenceAuthorized = FALSE; /* TRUE if physicalPresence validated */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetCapability: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&subCap); /* freed @1 */ + TPM_SizedBuffer_Init(&setValue); /* freed @2 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get capArea parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&capArea, &command, ¶mSize); + } + /* get subCap parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetCapability: capArea %08x \n", capArea); + returnCode = TPM_SizedBuffer_Load(&subCap, &command, ¶mSize); + } + /* get setValue parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&setValue , &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + ownerAuthorized = TRUE; + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetCapability: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. If tag = TPM_TAG_RQU_AUTH1_COMMAND, validate the command and parameters using ownerAuth, + return TPM_AUTHFAIL on error */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Global_GetPhysicalPresence(&presenceAuthorized, tpm_state); + } + /* 2. The TPM validates the capArea and subCap indicators, including the ability to set value + based on any set restrictions */ + /* 3. If the capArea and subCap indicators conform with one of the entries in the structure + TPM_CAPABILITY_AREA (Values for TPM_SetCapability) */ + /* a. The TPM sets the relevant flag/data to the value of setValue parameter. */ + /* 4. Else */ + /* a. Return the error code TPM_BAD_PARAMETER. */ + if (returnCode == TPM_SUCCESS) { + /* subCap is often a uint16_t or uint32_t, create them now */ + TPM_GetSubCapInt(&subCap16, &subCap32, &subCap); + returnCode = TPM_SetCapabilityCommon(tpm_state, ownerAuthorized, presenceAuthorized, + capArea, subCap16, subCap32, &subCap, + &setValue); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetCapability: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, terminate the session. */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&subCap); /* @1 */ + TPM_SizedBuffer_Delete(&setValue); /* @2 */ + return rcf; +} + +/* TPM_SetCapabilityCommon() is common code for setting a capability from setValue + + NOTE: This function assumes that the caller has validated either owner authorization or physical + presence! +*/ + +TPM_RESULT TPM_SetCapabilityCommon(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + TPM_CAPABILITY_AREA capArea, + uint16_t subCap16, + uint32_t subCap32, + TPM_SIZED_BUFFER *subCap, + TPM_SIZED_BUFFER *setValue) +{ + TPM_RESULT rc = 0; + TPM_BOOL valueBool; + uint32_t valueUint32 = 0; /* start with illegal value */ + + printf(" TPM_SetCapabilityCommon:\n"); + subCap16 = subCap16; /* not used */ + subCap = subCap; /* not used */ + if (rc == 0) { + if ((capArea == TPM_SET_PERM_FLAGS) || + (capArea == TPM_SET_STCLEAR_FLAGS) || + (capArea == TPM_SET_STANY_FLAGS)) { + rc = TPM_SizedBuffer_GetBool(&valueBool, setValue); + } + else if (((capArea == TPM_SET_PERM_DATA) && (subCap32 != TPM_PD_DAAPROOF)) || + (capArea == TPM_SET_STCLEAR_DATA)) { /* deferredPhysicalPresence */ + rc = TPM_SizedBuffer_GetUint32(&valueUint32, setValue); + } + } + if (rc == 0) { + switch (capArea) { + case TPM_SET_PERM_FLAGS: + rc = TPM_SetCapability_CapPermFlags(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, valueBool); + break; + case TPM_SET_PERM_DATA: + rc = TPM_SetCapability_CapPermData(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, valueUint32); + break; + case TPM_SET_STCLEAR_FLAGS: + rc = TPM_SetCapability_CapStclearFlags(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, valueBool); + break; + case TPM_SET_STCLEAR_DATA: + rc = TPM_SetCapability_CapStclearData(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, valueUint32); + break; + case TPM_SET_STANY_FLAGS: + rc = TPM_SetCapability_CapStanyFlags(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, valueBool); + break; + case TPM_SET_STANY_DATA: + rc = TPM_SetCapability_CapStanyData(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, setValue); + break; + case TPM_SET_VENDOR: + rc = TPM_SetCapability_CapVendor(tpm_state, ownerAuthorized, presenceAuthorized, + subCap32, setValue); + break; + default: + printf("TPM_SetCapabilityCommon: Error, unsupported capArea %08x", capArea); + rc = TPM_BAD_MODE; + break; + } + } + return rc; +} + +/* TPM_SetCapability_Flag() tests if the values are not already equal. If they are not, 'flag' is + set to 'value' and 'altered' is set TRUE. Otherwise 'altered' is returned unchanged. + + The 'altered' flag is used by the caller to determine if an NVRAM write is required. +*/ + +void TPM_SetCapability_Flag(TPM_BOOL *altered, + TPM_BOOL *flag, + TPM_BOOL value) +{ + /* If the values are not already equal. Can't use != since there are many values for TRUE. */ + if ((value && !*flag) || + (!value && *flag)) { + *altered = TRUE; + *flag = value; + } + return; +} + +/* TPM_SetCapability_CapPermFlags() rev 100 + + Sets TPM_PERMANENT_FLAGS values +*/ + +static TPM_RESULT TPM_SetCapability_CapPermFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool) +{ + TPM_RESULT rc = 0; + TPM_BOOL altered = FALSE; /* TRUE if the structure has been changed */ + + printf(" TPM_SetCapability_CapPermFlags: valueBool %02x\n", valueBool); + if (rc == 0) { + switch (subCap32) { + case TPM_PF_DISABLE: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_DISABLE\n"); + /* Owner authorization or physical presence + TPM_OwnerSetDisable + TPM_PhysicalEnable + TPM_PhysicalDisable + */ + if (rc == 0) { + if (!ownerAuthorized && !presenceAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, no authorization\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.disable), + valueBool); + } + break; + case TPM_PF_OWNERSHIP: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_OWNERSHIP\n"); + /* No authorization. No ownerInstalled. Physical presence asserted + Not available when TPM deactivated or disabled + TPM_SetOwnerInstall + */ + if (rc == 0) { + if (tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_SetCapability_CapPermFlags: Error, owner installed\n"); + rc = TPM_OWNER_SET; + } + } + if (rc == 0) { + if (!presenceAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, no physicalPresence\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.ownership), + valueBool); + } + break; + case TPM_PF_DEACTIVATED: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_DEACTIVATED\n"); + /* No authorization, physical presence assertion + Not available when TPM disabled + TPM_PhysicalSetDeactivated + */ + if (rc == 0) { + if (!presenceAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, no physicalPresence\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.deactivated), + valueBool); + } + break; + case TPM_PF_READPUBEK: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_READPUBEK\n"); + /* Owner authorization + Not available when TPM deactivated or disabled + */ + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.readPubek), + valueBool); + } + if (rc == 0) { + printf(" TPM_SetCapability_CapPermFlags : readPubek %02x\n", + tpm_state->tpm_permanent_flags.readPubek); + } + break; + case TPM_PF_DISABLEOWNERCLEAR: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_DISABLEOWNERCLEAR\n"); + /* Owner authorization. Can only set to TRUE, FALSE invalid value. + After being set only ForceClear resets back to FALSE. + Not available when TPM deactivated or disabled + TPM_DisableOwnerClear */ + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (!valueBool) { + printf("TPM_SetCapability_CapPermFlags: Error, cannot set FALSE\n"); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.disableOwnerClear), + valueBool); + } + break; + case TPM_PF_ALLOWMAINTENANCE: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_ALLOWMAINTENANCE\n"); + /* Owner authorization. Can only set to FALSE, TRUE invalid value. + After being set only changing TPM owner resets back to TRUE + Not available when TPM deactivated or disabled + TPM_KillMaintenanceFeature + */ + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (valueBool) { + printf("TPM_SetCapability_CapPermFlags: Error, cannot set TRUE\n"); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.allowMaintenance), + valueBool); + } + break; + case TPM_PF_READSRKPUB: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_READSRKPUB\n"); + /* Owner Authorization + Not available when TPM deactivated or disabled + TPM_SetCapability + */ + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermFlags: Error, disable is TRUE\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermFlags: Error, deactivated is TRUE\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.readSRKPub), + valueBool); + } + break; + case TPM_PF_TPMESTABLISHED: + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_TPMESTABLISHED\n"); + /* Locality 3 or locality 4 + Can only set to FALSE + TPM_ResetEstablishmentBit + */ + if (rc == 0) { + rc = TPM_Locality_Check(TPM_LOC_THREE | TPM_LOC_FOUR, /* BYTE bitmap */ + tpm_state->tpm_stany_flags.localityModifier); + } + if (rc == 0) { + if (valueBool) { + printf("TPM_SetCapability_CapPermFlags: Error, can only set to FALSE\n"); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.tpmEstablished), + valueBool); + } + break; +#if (TPM_REVISION >= 103) /* added for rev 103 */ + case TPM_PF_DISABLEFULLDALOGICINFO: + /* Owner Authorization + TPM_SetCapability + */ + printf(" TPM_SetCapability_CapPermFlags: TPM_PF_DISABLEFULLDALOGICINFO\n"); + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermFlags: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.disableFullDALogicInfo), + valueBool); + } + break; +#endif + case TPM_PF_PHYSICALPRESENCELIFETIMELOCK: + case TPM_PF_PHYSICALPRESENCEHWENABLE: + case TPM_PF_PHYSICALPRESENCECMDENABLE: + case TPM_PF_CEKPUSED: + case TPM_PF_TPMPOST: + case TPM_PF_TPMPOSTLOCK: + case TPM_PF_FIPS: + case TPM_PF_OPERATOR: + case TPM_PF_ENABLEREVOKEEK: + case TPM_PF_NV_LOCKED: + case TPM_PF_MAINTENANCEDONE: + default: + printf("TPM_SetCapability_CapPermFlags: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + rc = TPM_PermanentAll_NVStore(tpm_state, + altered, + rc); + return rc; +} + +/* TPM_SetCapability_CapPermData() rev 105 + + Sets TPM_PERMANENT_DATA values +*/ + +static TPM_RESULT TPM_SetCapability_CapPermData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + uint32_t valueUint32) +{ + TPM_RESULT rc = 0; + TPM_BOOL writeAllNV = FALSE; /* TRUE if the structure has been changed */ + + printf(" TPM_SetCapability_CapPermData:\n"); + presenceAuthorized = presenceAuthorized; /* not used */ + if (rc == 0) { + switch (subCap32) { + case TPM_PD_RESTRICTDELEGATE: + printf(" TPM_SetCapability_CapPermData: TPM_PD_RESTRICTDELEGATE\n"); + /* Owner authorization. Not available when TPM deactivated or disabled */ + /* TPM_CMK_SetRestrictions */ + if (rc == 0) { + if (!ownerAuthorized) { + printf("TPM_SetCapability_CapPermData: Error, not owner authorized\n"); + rc = TPM_AUTHFAIL; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapPermData: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapPermData: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + if (rc == 0) { + if (tpm_state->tpm_permanent_data.restrictDelegate != valueUint32) { + tpm_state->tpm_permanent_data.restrictDelegate = valueUint32; + writeAllNV = TRUE; + } + } + break; + case TPM_PD_DAAPROOF: + /* TPM_PD_DAAPROOF This capability has no value. When specified by TPM_SetCapability, a + new daaProof, tpmDAASeed, and daaBlobKey are generated. */ + rc = TPM_PermanentData_InitDaa(&(tpm_state->tpm_permanent_data)); + writeAllNV = TRUE; + break; + case TPM_PD_REVMAJOR: + case TPM_PD_REVMINOR: + case TPM_PD_TPMPROOF: + case TPM_PD_OWNERAUTH: + case TPM_PD_OPERATORAUTH: + case TPM_PD_MANUMAINTPUB: + case TPM_PD_ENDORSEMENTKEY: + case TPM_PD_SRK: + case TPM_PD_DELEGATEKEY: + case TPM_PD_CONTEXTKEY: + case TPM_PD_AUDITMONOTONICCOUNTER: + case TPM_PD_MONOTONICCOUNTER: + case TPM_PD_PCRATTRIB: + case TPM_PD_ORDINALAUDITSTATUS: + case TPM_PD_AUTHDIR: + case TPM_PD_RNGSTATE: + case TPM_PD_FAMILYTABLE: + case TPM_DELEGATETABLE: + case TPM_PD_EKRESET: + case TPM_PD_LASTFAMILYID: + case TPM_PD_NOOWNERNVWRITE: + case TPM_PD_TPMDAASEED: + default: + printf("TPM_SetCapability_CapPermData: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + rc = TPM_PermanentAll_NVStore(tpm_state, + writeAllNV, + rc); + return rc; +} + +/* TPM_SetCapability_CapStclearFlags() rev 85 + + Sets TPM_STCLEAR_FLAGS values +*/ + +static TPM_RESULT TPM_SetCapability_CapStclearFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SetCapability_CapStclearFlags: valueBool %02x\n", valueBool); + ownerAuthorized = ownerAuthorized; /* not used */ + presenceAuthorized = presenceAuthorized; /* not used */ + if (rc == 0) { + switch (subCap32) { + case TPM_SF_DISABLEFORCECLEAR: + printf(" TPM_SetCapability_CapStclearFlags: TPM_SF_DISABLEFORCECLEAR\n"); + /* Not available when TPM deactivated or disabled */ + /* TPM_DisableForceClear */ + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapStclearFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapStclearFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + /* Can only set to TRUE */ + if (rc == 0) { + if (!valueBool) { + printf("TPM_SetCapability_CapStclearFlags: Error, cannot set FALSE\n"); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + tpm_state->tpm_stclear_flags.disableForceClear = TRUE; + } + break; + case TPM_SF_DEACTIVATED: + case TPM_SF_PHYSICALPRESENCE: + case TPM_SF_PHYSICALPRESENCELOCK: + case TPM_SF_BGLOBALLOCK: + default: + printf("TPM_SetCapability_CapStclearFlags: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_SetCapability_CapStclearData() rev 100 + + Sets TPM_STCLEAR_DATA values +*/ + +static TPM_RESULT TPM_SetCapability_CapStclearData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + uint32_t valueUint32) +{ + TPM_RESULT rc = 0; +#if (TPM_REVISION < 103) /* added for rev 103 */ + tpm_state = tpm_state; /* to quiet the compiler */ + presenceAuthorized = presenceAuthorized; + valueUint32 = valueUint32; +#endif + + printf(" TPM_SetCapability_CapStclearData:\n"); + ownerAuthorized = ownerAuthorized; /* not used */ + if (rc == 0) { + switch (subCap32) { +#if (TPM_REVISION >= 103) /* added for rev 103 */ + case TPM_SD_DEFERREDPHYSICALPRESENCE: + printf(" TPM_SetCapability_CapStclearData: TPM_SD_DEFERREDPHYSICALPRESENCE\n"); + /* Can only set to TRUE if PhysicalPresence is asserted. Can set to FALSE at any + time. */ + /* 1. If physical presence is not asserted */ + /* a. If TPM_SetCapability -> setValue has a bit set that is not already set in + TPM_STCLEAR_DATA -> deferredPhysicalPresence, return TPM_BAD_PRESENCE. */ + if (rc == 0) { + if (!presenceAuthorized) { + if (~(tpm_state->tpm_stclear_data.deferredPhysicalPresence) & valueUint32) { + printf("TPM_SetCapability_CapStclearData: " + "Error, no physicalPresence and deferredPhysicalPresence %08x\n", + tpm_state->tpm_stclear_data.deferredPhysicalPresence); + rc = TPM_BAD_PRESENCE; + } + } + } + /* 2.Set TPM_STCLEAR_DATA -> deferredPhysicalPresence to TPM_SetCapability -> setValue. + */ + if (rc == 0) { + printf(" TPM_SetCapability_CapStclearData: deferredPhysicalPresence now %08x\n", + valueUint32); + tpm_state->tpm_stclear_data.deferredPhysicalPresence = valueUint32; + } + break; +#endif + case TPM_SD_CONTEXTNONCEKEY: + case TPM_SD_COUNTID: + case TPM_SD_OWNERREFERENCE: + case TPM_SD_DISABLERESETLOCK: + case TPM_SD_PCR: + default: + printf("TPM_SetCapability_CapStclearData: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_SetCapability_CapStanyFlags() rev 85 + + Sets TPM_STANY_FLAGS values +*/ + +static TPM_RESULT TPM_SetCapability_CapStanyFlags(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_BOOL valueBool) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SetCapability_CapStanyFlags:\n"); + ownerAuthorized = ownerAuthorized; /* not used */ + presenceAuthorized = presenceAuthorized; /* not used */ + if (rc == 0) { + switch (subCap32) { + case TPM_AF_TOSPRESENT: + printf(" TPM_SetCapability_CapStanyFlags: TPM_AF_TOSPRESENT\n"); + /* locality 3 or 4 */ + /* Not available when TPM deactivated or disabled */ + if (rc == 0) { + rc = TPM_Locality_Check(TPM_LOC_THREE | TPM_LOC_FOUR, + tpm_state->tpm_stany_flags.localityModifier); + } + if (rc == 0) { + if (tpm_state->tpm_permanent_flags.disable) { + printf("TPM_SetCapability_CapStanyFlags: Error, disabled\n"); + rc = TPM_DISABLED; + } + } + if (rc == 0) { + if (tpm_state->tpm_stclear_flags.deactivated) { + printf("TPM_SetCapability_CapStanyFlags: Error, deactivated\n"); + rc = TPM_DEACTIVATED; + } + } + /* can only be set to FALSE */ + if (rc == 0) { + if (valueBool) { + printf("TPM_SetCapability_CapStanyFlags: Error, cannot set TRUE\n"); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + tpm_state->tpm_stany_flags.TOSPresent = FALSE; + } + break; + case TPM_AF_POSTINITIALISE: + case TPM_AF_LOCALITYMODIFIER: + case TPM_AF_TRANSPORTEXCLUSIVE: + default: + printf("TPM_SetCapability_CapStanyFlags: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* TPM_SetCapability_CapStanyData() rev 85 + + Sets TPM_STANY_DATA values +*/ + +static TPM_RESULT TPM_SetCapability_CapStanyData(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_SIZED_BUFFER *setValue) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SetCapability_CapStanyData:\n"); + tpm_state = tpm_state; /* not used */ + ownerAuthorized = ownerAuthorized; /* not used */ + presenceAuthorized = presenceAuthorized; /* not used */ + setValue = setValue; /* not used */ + if (rc == 0) { + switch (subCap32) { + case TPM_AD_CONTEXTNONCESESSION: + case TPM_AD_AUDITDIGEST: + case TPM_AD_CURRENTTICKS: + case TPM_AD_CONTEXTCOUNT: + case TPM_AD_CONTEXTLIST: + case TPM_AD_SESSIONS: + default: + printf("TPM_SetCapability_CapStanyData: Error, bad subCap32 %u\n", + subCap32); + rc = TPM_BAD_PARAMETER; + } + } + return rc; +} + +/* These are subCaps to TPM_SetCapability -> TPM_SET_VENDOR capArea, the vendor specific area. +*/ + +static TPM_RESULT TPM_SetCapability_CapVendor(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + uint32_t subCap32, + TPM_SIZED_BUFFER *setValue) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SetCapability_CapVendor:\n"); + ownerAuthorized = ownerAuthorized; /* not used */ + presenceAuthorized = presenceAuthorized; /* not used */ + setValue = setValue; + /* make temporary copies so the setValue is not touched */ + if (rc == 0) { + switch(subCap32) { + default: + printf("TPM_SetCapability_CapVendor: Error, unsupported subCap %08x\n", subCap32); + tpm_state = tpm_state; /* not used */ + rc = TPM_BAD_PARAMETER; + break; + + } + } + return rc; +} diff --git a/src/tpm_process.h b/src/tpm_process.h new file mode 100644 index 00000000..dfe7b3c3 --- /dev/null +++ b/src/tpm_process.h @@ -0,0 +1,298 @@ +/********************************************************************************/ +/* */ +/* TPM Command Processor */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_process.h 4120 2010-10-26 22:00:40Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_PROCESS_H +#define TPM_PROCESS_H + +#include + +/* Commented out. This is not a standard header. If needed for a particular platform, replace but + also add comments and ifdef. */ +/* #include */ + +#include "tpm_global.h" +#include "tpm_store.h" + +/* + TPM_CAP_VERSION_INFO +*/ + +void TPM_CapVersionInfo_Init(TPM_CAP_VERSION_INFO *tpm_cap_version_info); +TPM_RESULT TPM_CapVersionInfo_Load(TPM_CAP_VERSION_INFO *tpm_cap_version_info, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CapVersionInfo_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CAP_VERSION_INFO *tpm_cap_version_info); +void TPM_CapVersionInfo_Delete(TPM_CAP_VERSION_INFO *tpm_cap_version_info); +void TPM_CapVersionInfo_Set(TPM_CAP_VERSION_INFO *tpm_cap_version_info, + TPM_PERMANENT_DATA *tpm_permanent_data); + +/* + Capability Common Code +*/ + +void TPM_SetCapability_Flag(TPM_BOOL *altered, + TPM_BOOL *flag, + TPM_BOOL value); +void TPM_GetSubCapInt(uint16_t *subCap16, + uint32_t *subCap32, + TPM_SIZED_BUFFER *subCap); + +TPM_RESULT TPM_GetCapabilityCommon(TPM_STORE_BUFFER *capabilityResponse, + tpm_state_t *tpm_state, + TPM_CAPABILITY_AREA capArea, + uint16_t subCap16, + uint32_t subCap32, + TPM_SIZED_BUFFER *subCap); +TPM_RESULT TPM_SetCapabilityCommon(tpm_state_t *tpm_state, + TPM_BOOL ownerAuthorized, + TPM_BOOL presenceAuthorized, + TPM_CAPABILITY_AREA capArea, + uint16_t subCap16, + uint32_t subCap32, + TPM_SIZED_BUFFER *subCap, + TPM_SIZED_BUFFER *setValue); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_ProcessA(unsigned char **response, + uint32_t *response_size, + uint32_t *response_total, + unsigned char *command, + uint32_t command_size); +TPM_RESULT TPM_Process(TPM_STORE_BUFFER *response, + unsigned char *command, + uint32_t command_size); +TPM_RESULT TPM_Process_Wrapped(TPM_STORE_BUFFER *response, + unsigned char *command, + uint32_t command_size, + tpm_state_t *targetInstance, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_GetCommandParams(TPM_TAG *tag, + uint32_t *paramSize , + TPM_COMMAND_CODE *ordinal, + unsigned char **command, + uint32_t *command_size); +TPM_RESULT TPM_Process_GetResponseParams(TPM_TAG *tag, + uint32_t *paramSize , + TPM_RESULT *returnCode, + unsigned char **response, + uint32_t *response_size); + +TPM_RESULT TPM_Process_Unused(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_GetCapability(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_GetCapabilityOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_GetCapabilitySigned(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_SetCapability(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +/* + Processing Utilities +*/ + +/* tag checking */ + +TPM_RESULT TPM_CheckRequestTag210(TPM_TAG tpm_tag); +TPM_RESULT TPM_CheckRequestTag21 (TPM_TAG tpm_tag); +TPM_RESULT TPM_CheckRequestTag2 (TPM_TAG tpm_tag); +TPM_RESULT TPM_CheckRequestTag10 (TPM_TAG tpm_tag); +TPM_RESULT TPM_CheckRequestTag1 (TPM_TAG tpm_tag); +TPM_RESULT TPM_CheckRequestTag0 (TPM_TAG tpm_tag); + +/* TPM state checking */ + +TPM_RESULT TPM_CheckState(tpm_state_t *tpm_state, + TPM_TAG tag, + uint32_t tpm_check_map); +TPM_RESULT TPM_Process_Preprocess(tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Check_SHA1Context(tpm_state_t *tpm_state, + TPM_COMMAND_CODE ordinal, + TPM_TRANSPORT_INTERNAL *transportInternal); + +/* ordinal processing */ + +/* Prototype for all ordinal processing functions + + tpm_state: the entire TPM instance non-volatile and volatile state + response: the buffer to hold the ordinal response + tag: the command tag + paramSize: bytes left after the tag, paramSize, and ordinal + ordinal: the ordinal being called (could be hard coded, but eliminates cut/paste errors) + command: the remainder of the command packet + transportInternal: if not NULL, indicates that this function was called recursively from + TPM_ExecuteTransport +*/ + +typedef TPM_RESULT (*tpm_process_function_t)(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +typedef struct tdTPM_ORDINAL_TABLE { + TPM_COMMAND_CODE ordinal; + tpm_process_function_t process_function_v11; /* processing function for TPM 1.1 */ + tpm_process_function_t process_function_v12; /* processing function for TPM 1.2 */ + TPM_BOOL auditable; /* FALSE for functions never audited */ + TPM_BOOL auditDefault; /* TRUE if auditing is enabled by default */ + uint16_t ownerPermissionBlock; /* 0:unused, 1:per1 2:per2 */ + uint32_t ownerPermissionPosition; /* owner permission bit position */ + uint16_t keyPermissionBlock; /* 0:unused, 1:per1 2:per2 */ + uint32_t keyPermissionPosition; /* key permission bit position */ + uint32_t inputHandleSize; /* bytes of input handles (or other bytes + not to be encrypted or transport + audited) */ + uint32_t keyHandles; /* number of input key handles */ + uint32_t outputHandleSize; /* bytes of output handles (or other bytes + not to be encrypted or transport + audited */ + TPM_BOOL transportWrappable; /* can be wrapped in transport session */ + TPM_BOOL instanceWrappable; /* ordinal can be wrapped and called by + a parent instance */ + TPM_BOOL hardwareWrappable; /* ordinal can be wrapped and call the + hardware TPM instance */ +} TPM_ORDINAL_TABLE; + +TPM_RESULT TPM_OrdinalTable_GetEntry(TPM_ORDINAL_TABLE **entry, + TPM_ORDINAL_TABLE *ordinalTable, + TPM_COMMAND_CODE ordinal); +void TPM_OrdinalTable_GetProcessFunction(tpm_process_function_t *tpm_process_function, + TPM_ORDINAL_TABLE *ordinalTable, + TPM_COMMAND_CODE ordinal); +void TPM_OrdinalTable_GetAuditable(TPM_BOOL *auditable, + TPM_COMMAND_CODE ordinal); +void TPM_OrdinalTable_GetAuditDefault(TPM_BOOL *auditDefault, + TPM_COMMAND_CODE ordinal); +TPM_RESULT TPM_OrdinalTable_GetOwnerPermission(uint16_t *ownerPermissionBlock, + uint32_t *ownerPermissionPosition, + TPM_COMMAND_CODE ordinal); +TPM_RESULT TPM_OrdinalTable_GetKeyPermission(uint16_t *keyPermissionBlock, + uint32_t *keyPermissionPosition, + TPM_COMMAND_CODE ordinal); +TPM_RESULT TPM_OrdinalTable_ParseWrappedCmd(uint32_t *datawStart, + uint32_t *datawLen, + uint32_t *keyHandles, + uint32_t *keyHandle1Index, + uint32_t *keyHandle2Index, + TPM_COMMAND_CODE *ordinal, + TPM_BOOL *transportWrappable, + TPM_SIZED_BUFFER *wrappedCmd); +TPM_RESULT TPM_OrdinalTable_ParseWrappedRsp(uint32_t *datawStart, + uint32_t *datawLen, + TPM_RESULT *rcw, + TPM_COMMAND_CODE ordinal, + const unsigned char *wrappedRspStream, + uint32_t wrappedRspStreamSize); + + +TPM_RESULT TPM_GetInParamDigest(TPM_DIGEST inParamDigest, + TPM_BOOL *auditStatus, + TPM_BOOL *transportEncrypt, + tpm_state_t *tpm_state, + TPM_TAG tag, + TPM_COMMAND_CODE ordinal, + unsigned char *inParamStart, + unsigned char *inParamEnd, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_GetOutParamDigest(TPM_DIGEST outParamDigest, + TPM_BOOL auditStatus, + TPM_BOOL transportEncrypt, + TPM_TAG tag, + TPM_RESULT returnCode, + TPM_COMMAND_CODE ordinal, + unsigned char *outParamStart, + uint32_t outParamLength); +TPM_RESULT TPM_ProcessAudit(tpm_state_t *tpm_state, + TPM_BOOL transportEncrypt, + TPM_DIGEST inParamDigest, + TPM_DIGEST outParamDigest, + TPM_COMMAND_CODE ordinal); + +/* + defines for TPM_CheckState check map +*/ + +#define TPM_CHECK_NOT_SHUTDOWN 0x00000001 +#define TPM_CHECK_ENABLED 0x00000004 +#define TPM_CHECK_ACTIVATED 0x00000008 +#define TPM_CHECK_OWNER 0x00000010 +#define TPM_CHECK_NO_LOCKOUT 0x00000020 +#define TPM_CHECK_NV_NOAUTH 0x00000040 + +/* default conditions to check */ +#define TPM_CHECK_ALL 0x0000003f /* all state */ +#define TPM_CHECK_ALLOW_NO_OWNER 0x0000002f /* all state but owner installed */ + +#endif diff --git a/src/tpm_secret.c b/src/tpm_secret.c new file mode 100644 index 00000000..8dedf145 --- /dev/null +++ b/src/tpm_secret.c @@ -0,0 +1,166 @@ +/********************************************************************************/ +/* */ +/* Secret Data Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_secret.c 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_store.h" + +#include "tpm_secret.h" + +void TPM_Secret_Init(TPM_SECRET tpm_secret) +{ + printf(" TPM_Secret_Init:\n"); + memset(tpm_secret, 0, TPM_SECRET_SIZE); + return; +} + +/* TPM_Secret_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + After use, call TPM_Secret_Delete() to free memory +*/ + +TPM_RESULT TPM_Secret_Load(TPM_SECRET tpm_secret, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Secret_Load:\n"); + rc = TPM_Loadn(tpm_secret, TPM_SECRET_SIZE, stream, stream_size); + return rc; +} + +/* TPM_Secret_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + After use, call TPM_Sbuffer_Delete() to free memory +*/ + +TPM_RESULT TPM_Secret_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SECRET tpm_secret) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Secret_Store:\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_secret, TPM_SECRET_SIZE); + return rc; +} + +/* TPM_Secret_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the secret + sets pointers to NULL + calls TPM_Secret_Init to set members back to default values + The secret itself is not freed + returns 0 or error codes +*/ + +void TPM_Secret_Delete(TPM_SECRET tpm_secret) +{ + printf(" TPM_Secret_Delete:\n"); + if (tpm_secret != NULL) { + TPM_Secret_Init(tpm_secret); + } + return; +} + +/* TPM_Secret_Copy() copies the source to the destination + */ + +void TPM_Secret_Copy(TPM_SECRET destination, const TPM_SECRET source) +{ + printf(" TPM_Secret_Copy:\n"); + memcpy(destination, source, TPM_SECRET_SIZE); + return; +} + +/* TPM_Secret_Compare() compares the source to the destination. + + Returns TPM_AUTHFAIL if the nonces are not equal +*/ + +TPM_RESULT TPM_Secret_Compare(TPM_SECRET expect, const TPM_SECRET actual) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Secret_Compare:\n"); + rc = memcmp(expect, actual, TPM_SECRET_SIZE); + if (rc != 0) { + printf("TPM_Secret_Compare: Error comparing secret\n"); + rc = TPM_AUTHFAIL; + } + return rc; +} + +/* TPM_Secret_Generate() generates a new TPM_SECRET from the random number generator + */ + +TPM_RESULT TPM_Secret_Generate(TPM_SECRET tpm_secret) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Secret_Generate:\n"); + rc = TPM_Random(tpm_secret, TPM_SECRET_SIZE); + return rc; +} + +/* TPM_Secret_XOR() XOR's the source and the destination, and returns the result on output. + */ + +void TPM_Secret_XOR(TPM_SECRET output, TPM_SECRET input1, TPM_SECRET input2) +{ + size_t i; + + printf(" TPM_Secret_XOR:\n"); + for (i = 0 ; i < TPM_SECRET_SIZE ; i++) { + output[i] = input1[i] ^ input2[i]; + } + return; +} diff --git a/src/tpm_secret.h b/src/tpm_secret.h new file mode 100644 index 00000000..5621b2ec --- /dev/null +++ b/src/tpm_secret.h @@ -0,0 +1,62 @@ +/********************************************************************************/ +/* */ +/* Secret Data Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_secret.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_SECRET_H +#define TPM_SECRET_H + +#include "tpm_store.h" +#include "tpm_structures.h" +#include "tpm_types.h" + +void TPM_Secret_Init(TPM_SECRET tpm_secret); +TPM_RESULT TPM_Secret_Load(TPM_SECRET tpm_secret, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Secret_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SECRET tpm_secret); +void TPM_Secret_Delete(TPM_SECRET tpm_secret); + + +void TPM_Secret_Copy(TPM_SECRET destination, const TPM_SECRET source); +TPM_RESULT TPM_Secret_Compare(TPM_SECRET expect, const TPM_SECRET actual); +TPM_RESULT TPM_Secret_Generate(TPM_SECRET tpm_secret); +void TPM_Secret_XOR(TPM_SECRET output, TPM_SECRET input1, TPM_SECRET input2); + + +#endif diff --git a/src/tpm_session.c b/src/tpm_session.c new file mode 100644 index 00000000..f7064c52 --- /dev/null +++ b/src/tpm_session.c @@ -0,0 +1,5540 @@ +/********************************************************************************/ +/* */ +/* Session Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_session.c 4584 2011-06-22 15:49:41Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_counter.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_daa.h" +#include "tpm_debug.h" +#include "tpm_delegate.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_nvram.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_permanent.h" +#include "tpm_secret.h" +#include "tpm_transport.h" +#include "tpm_types.h" + +#include "tpm_session.h" + +/* local function prototypes */ + +static TPM_RESULT TPM_OSAPDelegate(TPM_DIGEST **entityDigest, + TPM_SECRET **authData, + TPM_AUTH_SESSION_DATA *authSession, + tpm_state_t *tpm_state, + uint32_t delegateRowIndex); + +static TPM_RESULT TPM_LoadContext_CheckKeyLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest); +static TPM_RESULT TPM_LoadContext_CheckKeyLoadedByDigest(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest); +static TPM_RESULT TPM_LoadContext_CheckOwnerLoaded(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest); +static TPM_RESULT TPM_LoadContext_CheckSrkLoaded(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest); +static TPM_RESULT TPM_LoadContext_CheckCounterLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest); +static TPM_RESULT TPM_LoadContext_CheckNvLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest); + +/* + TPM_AUTH_SESSION_DATA (one element of the array) +*/ + +/* TPM_AuthSessionData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_AuthSessionData_Init(TPM_AUTH_SESSION_DATA *tpm_auth_session_data) +{ + printf(" TPM_AuthSessionData_Init:\n"); + tpm_auth_session_data->handle = 0; + tpm_auth_session_data->protocolID = 0; + tpm_auth_session_data->entityTypeByte = 0; + tpm_auth_session_data->adipEncScheme = 0; + TPM_Nonce_Init(tpm_auth_session_data->nonceEven); + TPM_Secret_Init(tpm_auth_session_data->sharedSecret); + TPM_Digest_Init(tpm_auth_session_data->entityDigest); + TPM_DelegatePublic_Init(&(tpm_auth_session_data->pub)); + tpm_auth_session_data->valid = FALSE; + return; +} + +/* TPM_AuthSessionData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_AuthSessionData_Init() + After use, call TPM_AuthSessionData_Delete() to free memory +*/ + +TPM_RESULT TPM_AuthSessionData_Load(TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuthSessionData_Load:\n"); + /* load handle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_auth_session_data->handle), stream, stream_size); + } + /* load protocolID */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_auth_session_data->protocolID), stream, stream_size); + } + /* load entityTypeByte */ + if (rc == 0) { + rc = TPM_Loadn(&(tpm_auth_session_data->entityTypeByte), sizeof(BYTE), stream, stream_size); + } + /* load adipEncScheme */ + if (rc == 0) { + rc = TPM_Loadn(&(tpm_auth_session_data->adipEncScheme), sizeof(BYTE), stream, stream_size); + } + /* load nonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_auth_session_data->nonceEven, stream, stream_size); + } + /* load sharedSecret */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_auth_session_data->sharedSecret, stream, stream_size); + } + /* load entityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_auth_session_data->entityDigest, stream, stream_size); + } + /* load pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Load(&(tpm_auth_session_data->pub), stream, stream_size); + } + /* set valid */ + if (rc == 0) { + tpm_auth_session_data->valid = TRUE; + } + return rc; +} + +/* TPM_AuthSessionData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_AuthSessionData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUTH_SESSION_DATA *tpm_auth_session_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuthSessionData_Store:\n"); + /* store handle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_auth_session_data->handle); + } + /* store protocolID */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_auth_session_data->protocolID); + } + /* store entityTypeByte */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_auth_session_data->entityTypeByte), sizeof(BYTE)); + } + /* store adipEncScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_auth_session_data->adipEncScheme), sizeof(BYTE)); + } + /* store nonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_auth_session_data->nonceEven); + } + /* store sharedSecret */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_auth_session_data->sharedSecret); + } + /* store entityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_auth_session_data->entityDigest); + } + /* store pub */ + if (rc == 0) { + rc = TPM_DelegatePublic_Store(sbuffer, &(tpm_auth_session_data->pub)); + } + return rc; +} + +/* TPM_AuthSessionData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_AuthSessionData_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_AuthSessionData_Delete(TPM_AUTH_SESSION_DATA *tpm_auth_session_data) +{ + printf(" TPM_AuthSessionData_Delete:\n"); + if (tpm_auth_session_data != NULL) { + TPM_DelegatePublic_Delete(&(tpm_auth_session_data->pub)); + TPM_AuthSessionData_Init(tpm_auth_session_data); + } + return; +} + +/* TPM_AuthSessionData_Copy() copies the source to the destination. The source handle is ignored, + since it might already be used. +*/ + +void TPM_AuthSessionData_Copy(TPM_AUTH_SESSION_DATA *dest_auth_session_data, + TPM_HANDLE tpm_handle, + TPM_AUTH_SESSION_DATA *src_auth_session_data) +{ + dest_auth_session_data->handle = tpm_handle; + dest_auth_session_data->protocolID = src_auth_session_data->protocolID; + dest_auth_session_data->entityTypeByte = src_auth_session_data->entityTypeByte; + dest_auth_session_data-> adipEncScheme = src_auth_session_data->adipEncScheme; + TPM_Nonce_Copy(dest_auth_session_data->nonceEven, src_auth_session_data->nonceEven); + TPM_Secret_Copy(dest_auth_session_data->sharedSecret, src_auth_session_data->sharedSecret); + TPM_Digest_Copy(dest_auth_session_data->entityDigest, src_auth_session_data->entityDigest); + TPM_DelegatePublic_Copy(&(dest_auth_session_data->pub), &(src_auth_session_data->pub)); + dest_auth_session_data->valid= src_auth_session_data->valid; +} + +/* TPM_AuthSessionData_GetDelegatePublic() */ + +TPM_RESULT TPM_AuthSessionData_GetDelegatePublic(TPM_DELEGATE_PUBLIC **delegatePublic, + TPM_AUTH_SESSION_DATA *auth_session_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuthSessionData_GetDelegatePublic:\n"); + if (rc == 0) { + *delegatePublic = &(auth_session_data->pub); + } + return rc; +} + +/* TPM_AuthSessionData_CheckEncScheme() checks that the encryption scheme specified by + TPM_ENTITY_TYPE is supported by the TPM (by TPM_AuthSessionData_Decrypt) +*/ + +TPM_RESULT TPM_AuthSessionData_CheckEncScheme(TPM_ADIP_ENC_SCHEME adipEncScheme, + TPM_BOOL FIPS) +{ + TPM_RESULT rc = 0; + + printf(" TPM_AuthSessionData_CheckEncScheme: adipEncScheme %02x\n", adipEncScheme); + switch (adipEncScheme) { + case TPM_ET_XOR: + /* i.If TPM_PERMANENT_FLAGS -> FIPS is TRUE */ + /* (1) All encrypted authorizations MUST use a symmetric key encryption scheme. */ + if (FIPS) { + rc = TPM_INAPPROPRIATE_ENC; + } + break; + case TPM_ET_AES128_CTR: + break; + default: + printf("TPM_AuthSessionData_CheckEncScheme: Error, unsupported adipEncScheme\n"); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + return rc; +} + +/* TPM_AuthSessionData_Decrypt() decrypts the encAuth secret using the algorithm indicated in the + OSAP or DSAP session + + If 'odd' is FALSE, one decrypt of encAuthEven to a1Even. + If 'odd' is TRUE, a second decrypt of encAuthOdd to a1Odd is also performed. +*/ + +TPM_RESULT TPM_AuthSessionData_Decrypt(TPM_DIGEST a1Even, + TPM_DIGEST a1Odd, + TPM_ENCAUTH encAuthEven, + TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + TPM_NONCE nonceOdd, + TPM_ENCAUTH encAuthOdd, + TPM_BOOL odd) +{ + TPM_RESULT rc = 0; + TPM_DIGEST x1Even; + TPM_DIGEST x2Odd; + + printf(" TPM_AuthSessionData_Decrypt:\n"); + /* sanity check - the session must be OSAP or DSAP */ + if (rc == 0) { + if ((tpm_auth_session_data->protocolID != TPM_PID_OSAP) && + (tpm_auth_session_data->protocolID != TPM_PID_DSAP)) { + printf("TPM_AuthSessionData_Decrypt: Error, protocolID should be OSAP, is %04hx\n", + tpm_auth_session_data->protocolID); + rc = TPM_BAD_MODE; + } + } + if (rc == 0) { + /* algorithm indicated in the OSAP session */ + switch(tpm_auth_session_data->adipEncScheme) { + case TPM_ET_XOR: + /* 4. If the entity type indicates XOR encryption for the AuthData secret */ + /* a.Create X1 the SHA-1 of the concatenation of (authHandle -> sharedSecret || + authLastNonceEven). */ + if (rc == 0) { + rc = TPM_SHA1(x1Even, + TPM_SECRET_SIZE, tpm_auth_session_data->sharedSecret, + TPM_NONCE_SIZE, tpm_auth_session_data->nonceEven, + 0, NULL); + } + /* b. Create the decrypted AuthData the XOR of X1 and the encrypted AuthData. */ + if (rc == 0) { + TPM_Digest_XOR(a1Even, encAuthEven, x1Even); + } + /* c. If the command ordinal contains a second AuthData2 secret + (e.g. TPM_CreateWrapKey) */ + /* i. Create X2 the SHA-1 of the concatenation of (authHandle -> sharedSecret || + nonceOdd). */ + if ((rc == 0) && (odd)) { + rc = TPM_SHA1(x2Odd, + TPM_SECRET_SIZE, tpm_auth_session_data->sharedSecret, + TPM_NONCE_SIZE, nonceOdd, + 0, NULL); + } + /* ii. Create the decrypted AuthData2 the XOR of X2 and the encrypted AuthData2. */ + if ((rc == 0) && (odd)) { + TPM_Digest_XOR(a1Odd, encAuthOdd, x2Odd); + } + break; +#ifdef TPM_AES /* if AES is supported */ + case TPM_ET_AES128_CTR: + /* 5. If the entity type indicates symmetric key encryption */ + /* a. The key for the encryption algorithm is the first bytes of the OSAP shared + secret. */ + /* i. E.g., For AES128, the key is the first 16 bytes of the OSAP shared secret. */ + /* ii. There is no support for AES keys greater than 128 bits. */ + /* b. If the entity type indicates CTR mode */ + /* i. The initial counter value for AuthData is the first bytes of authLastNonceEven. */ + /* (1) E.g., For AES128, the initial counter value is the first 16 bytes of + authLastNonceEven. */ + /* b. Create the decrypted AuthData from the encrypted AuthData. */ + if (rc == 0) { + rc = TPM_SymmetricKeyData_CtrCrypt(a1Even, /* output data */ + encAuthEven, /* input data */ + TPM_AUTHDATA_SIZE, /* data size */ + tpm_auth_session_data->sharedSecret, /* key */ + TPM_SECRET_SIZE, + tpm_auth_session_data->nonceEven, /* CTR */ + TPM_NONCE_SIZE); + } + /* ii. If the command ordinal contains a second AuthData2 secret + (e.g. TPM_CreateWrapKey) */ + /* (1) The initial counter value for AuthData2 is the first bytes of + nonceOdd. */ + /* ii. Create the decrypted AuthData2 from the the encrypted AuthData2. */ + if ((rc == 0) && (odd)) { + rc = TPM_SymmetricKeyData_CtrCrypt(a1Odd, /* output data */ + encAuthOdd, /* input data */ + TPM_AUTHDATA_SIZE, /* data size */ + tpm_auth_session_data->sharedSecret, /* key */ + TPM_SECRET_SIZE, + nonceOdd, /* CTR */ + TPM_NONCE_SIZE); + } + /* iii. Additional counter values as required are generated by incrementing the + entire counter value as a big endian number. */ + break; +#endif /* TPM_AES */ + default: + printf("TPM_AuthSessionData_Decrypt: Error, entityType %02x not supported\n", + tpm_auth_session_data->adipEncScheme); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + } + return rc; +} + +/* + TPM_AUTH_SESSION_DATA (the entire array) +*/ + +void TPM_AuthSessions_Init(TPM_AUTH_SESSION_DATA *authSessions) +{ + size_t i; + + printf(" TPM_AuthSessions_Init:\n"); + for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + TPM_AuthSessionData_Init(&(authSessions[i])); + } + return; +} + +/* TPM_AuthSessions_Load() reads a count of the number of stored sessions and then loads those + sessions. + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_AuthSessions_Init() +*/ + +TPM_RESULT TPM_AuthSessions_Load(TPM_AUTH_SESSION_DATA *authSessions, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t activeCount; + + printf(" TPM_AuthSessions_Load:\n"); + /* load active count */ + if (rc == 0) { + rc = TPM_Load32(&activeCount, stream, stream_size); + } + /* load authorization sessions */ + if (rc == 0) { + if (activeCount > TPM_MIN_AUTH_SESSIONS) { + printf("TPM_AuthSessions_Load: Error (fatal) %u sessions, %u slots\n", + activeCount, TPM_MIN_AUTH_SESSIONS); + rc = TPM_FAIL; + } + } + if (rc == 0) { + printf(" TPM_AuthSessions_Load: Loading %u sessions\n", activeCount); + } + for (i = 0 ; (rc == 0) && (i < activeCount) ; i++) { + rc = TPM_AuthSessionData_Load(&(authSessions[i]), stream, stream_size); + } + return rc; +} + +/* TPM_AuthSessions_Store() stores a count of the active sessions, followed by the sessions. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_AuthSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_AUTH_SESSION_DATA *authSessions) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t space; /* free authorization session slots */ + uint32_t activeCount; /* used authorization session slots */ + + /* store active count */ + if (rc == 0) { + TPM_AuthSessions_GetSpace(&space, authSessions); + activeCount = TPM_MIN_AUTH_SESSIONS - space; + printf(" TPM_AuthSessions_Store: Storing %u sessions\n", activeCount); + rc = TPM_Sbuffer_Append32(sbuffer, activeCount); + } + /* store auth sessions */ + for (i = 0 ; (rc == 0) && (i < TPM_MIN_AUTH_SESSIONS) ; i++) { + if ((authSessions[i]).valid) { /* if the session is active */ + printf(" TPM_AuthSessions_Store: Storing %08x\n", authSessions[i].handle); + rc = TPM_AuthSessionData_Store(sbuffer, &(authSessions[i])); + } + } + return rc; +} + +/* TPM_AuthSessions_Delete() terminates all sessions + +*/ + +void TPM_AuthSessions_Delete(TPM_AUTH_SESSION_DATA *authSessions) +{ + size_t i; + + printf(" TPM_AuthSessions_Delete:\n"); + for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + TPM_AuthSessionData_Delete(&(authSessions[i])); + } + return; +} + +/* TPM_AuthSessions_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not. + + If TRUE, 'index' holds the first free position. +*/ + +void TPM_AuthSessions_IsSpace(TPM_BOOL *isSpace, + uint32_t *index, + TPM_AUTH_SESSION_DATA *authSessions) +{ + printf(" TPM_AuthSessions_IsSpace:\n"); + for (*index = 0, *isSpace = FALSE ; *index < TPM_MIN_AUTH_SESSIONS ; (*index)++) { + if (!((authSessions[*index]).valid)) { + printf(" TPM_AuthSessions_IsSpace: Found space at %u\n", *index); + *isSpace = TRUE; + break; + } + } + return; +} + +void TPM_AuthSessions_Trace(TPM_AUTH_SESSION_DATA *authSessions) +{ + size_t i; + for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + if ((authSessions[i]).valid) { + printf(" TPM_AuthSessions_Trace: %lu handle %08x\n", + (unsigned long)i, authSessions[i].handle); + } + } + return; +} + +/* TPM_AuthSessions_GetSpace() returns the number of unused authHandle's. + +*/ + +void TPM_AuthSessions_GetSpace(uint32_t *space, + TPM_AUTH_SESSION_DATA *authSessions) +{ + uint32_t i; + + printf(" TPM_AuthSessions_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + if (!((authSessions[i]).valid)) { + (*space)++; + } + } + return; +} + +/* TPM_AuthSessions_StoreHandles() stores + + - the number of loaded sessions + - a list of session handles +*/ + +TPM_RESULT TPM_AuthSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_AUTH_SESSION_DATA *authSessions) +{ + TPM_RESULT rc = 0; + uint16_t i; + uint32_t space; + + printf(" TPM_AuthSessions_StoreHandles:\n"); + /* get the number of loaded handles */ + if (rc == 0) { + TPM_AuthSessions_GetSpace(&space, authSessions); + /* store loaded handle count. Cast safe because of TPM_MIN_AUTH_SESSIONS value */ + rc = TPM_Sbuffer_Append16(sbuffer, (uint16_t)(TPM_MIN_AUTH_SESSIONS - space)); + } + for (i = 0 ; (rc == 0) && (i < TPM_MIN_AUTH_SESSIONS) ; i++) { + if ((authSessions[i]).valid) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, (authSessions[i]).handle); /* store it */ + } + } + return rc; +} + +/* TPM_AuthSessions_GetNewHandle() checks for space in the authorization sessions table. + + If there is space, it returns a TPM_AUTH_SESSION_DATA entry in 'tpm_auth_session_data' and its + handle in 'authHandle'. The entry is marked 'valid'. + + If *authHandle non-zero, the suggested value is tried first. + + Returns TPM_RESOURCES if there is no space in the sessions table. +*/ + +TPM_RESULT TPM_AuthSessions_GetNewHandle(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, + TPM_AUTHHANDLE *authHandle, + TPM_AUTH_SESSION_DATA *authSessions) +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_AuthSessions_GetNewHandle:\n"); + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_AuthSessions_IsSpace(&isSpace, &index, authSessions); + if (!isSpace) { + printf("TPM_AuthSessions_GetNewHandle: Error, no space in authSessions table\n"); + TPM_AuthSessions_Trace(authSessions); + rc = TPM_RESOURCES; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(authHandle, /* I/O */ + authSessions, /* handle array */ + FALSE, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_AuthSessions_GetEntry); + } + if (rc == 0) { + printf(" TPM_AuthSessions_GetNewHandle: Assigned handle %08x\n", *authHandle); + *tpm_auth_session_data = &(authSessions[index]); + /* assign the handle */ + (*tpm_auth_session_data)->handle = *authHandle; + (*tpm_auth_session_data)->valid = TRUE; + } + return rc; +} + +/* TPM_AuthSessions_GetEntry() searches all entries for the entry matching the handle, and + returns the TPM_AUTH_SESSION_DATA entry associated with the handle. + + Returns + 0 for success + TPM_INVALID_AUTHHANDLE if the handle is not found +*/ + +TPM_RESULT TPM_AuthSessions_GetEntry(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, /* session for + authHandle */ + TPM_AUTH_SESSION_DATA *authSessions, /* points to first session + */ + TPM_AUTHHANDLE authHandle) /* input */ +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_AuthSessions_GetEntry: authHandle %08x\n", authHandle); + for (i = 0, found = FALSE ; (i < TPM_MIN_AUTH_SESSIONS) && !found ; i++) { + if ((authSessions[i].valid) && + (authSessions[i].handle == authHandle)) { /* found */ + found = TRUE; + *tpm_auth_session_data = &(authSessions[i]); + } + } + if (!found) { + printf(" TPM_AuthSessions_GetEntry: session handle %08x not found\n", + authHandle); + rc = TPM_INVALID_AUTHHANDLE; + } + return rc; +} + +/* TPM_AuthSessions_AddEntry() adds an TPM_AUTH_SESSION_DATA object to the list. + + If *tpm_handle == 0, a value is assigned. If *tpm_handle != 0, that value is used if it it not + currently in use. + + The handle is returned in tpm_handle. +*/ + +TPM_RESULT TPM_AuthSessions_AddEntry(TPM_HANDLE *tpm_handle, /* i/o */ + TPM_BOOL keepHandle, /* input */ + TPM_AUTH_SESSION_DATA *authSessions, /* input */ + TPM_AUTH_SESSION_DATA *tpm_auth_session_data) /* input */ +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_AuthSessions_AddEntry: handle %08x, keepHandle %u\n", + *tpm_handle, keepHandle); + /* check for valid TPM_AUTH_SESSION_DATA */ + if (rc == 0) { + if (tpm_auth_session_data == NULL) { /* NOTE: should never occur */ + printf("TPM_AuthSessions_AddEntry: Error (fatal), NULL TPM_AUTH_SESSION_DATA\n"); + rc = TPM_FAIL; + } + } + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_AuthSessions_IsSpace(&isSpace, &index, authSessions); + if (!isSpace) { + printf("TPM_AuthSessions_AddEntry: Error, session entries full\n"); + TPM_AuthSessions_Trace(authSessions); + rc = TPM_RESOURCES; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(tpm_handle, /* I/O */ + authSessions, /* handle array */ + keepHandle, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_AuthSessions_GetEntry); + } + if (rc == 0) { + TPM_AuthSessionData_Copy(&(authSessions[index]), *tpm_handle, tpm_auth_session_data); + authSessions[index].valid = TRUE; + printf(" TPM_AuthSessions_AddEntry: Index %u handle %08x\n", + index, authSessions[index].handle); + } + return rc; +} + +/* TPM_AuthSessions_GetData() checks that authHandle indexes a valid TPM_AUTH_SESSION_DATA object. + If so, a pointer to the object is returned in tpm_auth_session_data. + + If required protocolID is either TPM_PID_OIAP or TPM_PID_OSAP, the object is checked for that + type. TPM_PID_OSAP will accept DSAP as well. If it is TPM_PID_NONE, either is accepted. Any + other value is unsupported. + + If the session protocolID is OIAP, the input entityAuth is echoed back as the HMAC key. + entityDigest is ignored and may be NULL. + + If the session protocolID is OSAP or DSAP, the function must check that the entity used to set up + the session is the same as the entity specified in the processing command. It does that by + comparing the entityDigest to that saved during setup of the OSAP session. The shared secret is + returned as the HMAC key. entityAuth is ignored and may be NULL. + + If the session protocolID is DSAP, the TPM_DELEGATE_PUBLIC saved during the TPM_DSAP session + setup is checked for permission and PCR's. The entityType (TPM_ET_KEYHANDLE or TPM_ET_OWNER) is + checked against the TPM_DELEGATE_PUBLIC -> TPM_DELEGATIONS delegateType. Then the bit map is + fetched from the ordinals table and verified against the per1 or per 2 values. The pcrInfo is + checked against the current PCR values. + + The saved entityDigest depends upon the entity type: + + TPM_ET_KEYHANDLE: pubDataDigest + TPM_ET_OWNER: ownerAuth + TPM_ET_SRK: TPM_KEY -> key_digest + TPM_ET_COUNTER: TPM_COUNTER_VALUE -> digest + TPM_ET_NV: TPM_NV_DATA_SENSITIVE -> digest +*/ + +TPM_RESULT TPM_AuthSessions_GetData(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, /* session for + authHandle */ + TPM_SECRET **hmacKey, /* output */ + tpm_state_t *tpm_state, /* input */ + TPM_AUTHHANDLE authHandle, /* input */ + TPM_PROTOCOL_ID protocolID, /* input: required protocol */ + TPM_ENT_TYPE entityType, /* input: entity type */ + TPM_COMMAND_CODE ordinal, /* input: for delegation */ + TPM_KEY *tpmKey, /* input, for delegate restrictions */ + TPM_SECRET *entityAuth, /* input OIAP hmac key */ + TPM_DIGEST entityDigest) /* input OSAP session setup auth */ +{ + TPM_RESULT rc = 0; + TPM_DELEGATE_TABLE_ROW *delegateTableRow; + + printf(" TPM_AuthSessions_GetData: authHandle %08x\n", authHandle); + if (rc == 0) { + rc = TPM_AuthSessions_GetEntry(tpm_auth_session_data, + tpm_state->tpm_stclear_data.authSessions, + authHandle); + if (rc != 0) { + printf("TPM_AuthSessions_GetData: Error, authHandle %08x not found\n", authHandle); + } + } + /* If a specific protocol is required, check that the handle points to the correct session type + */ + if (rc == 0) { + switch (protocolID) { /* what protocol is required */ + case TPM_PID_NONE: /* accept any protocol */ + break; + case TPM_PID_OIAP: + if ((*tpm_auth_session_data)->protocolID != TPM_PID_OIAP) { + printf("TPM_AuthSessions_GetData: Error, " + "session protocolID should be OIAP, is %04hx\n", + (*tpm_auth_session_data)->protocolID); + rc = TPM_BAD_MODE; + } + break; + case TPM_PID_OSAP: + /* Any ordinal requiring OSAP should also accept DSAP */ + if (((*tpm_auth_session_data)->protocolID != TPM_PID_OSAP) && + ((*tpm_auth_session_data)->protocolID != TPM_PID_DSAP)) { + printf("TPM_AuthSessions_GetData: Error, " + "session protocolID should be OSAP or DSAP, is %04hx\n", + (*tpm_auth_session_data)->protocolID); + rc = TPM_BAD_MODE; + } + break; + default: /* should not occur */ + printf("TPM_AuthSessions_GetData: Error, required protocolID %04hx unsupported\n", + protocolID); + rc = TPM_BAD_MODE; + break; + } + } + /* if the entity is owner auth, verify that an owner is installed */ + if (rc == 0) { + if (entityType == TPM_ET_OWNER) { + if (!tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_AuthSessions_GetData: Error, no owner installed\n"); + rc = TPM_AUTHFAIL; + } + } + } + /* session protocol specific processing */ + if (rc == 0) { + switch ((*tpm_auth_session_data)->protocolID) { + case TPM_PID_OIAP: + /* a. If the command using the OIAP session requires owner authorization */ + /* i. If TPM_STCLEAR_DATA -> ownerReference is TPM_KH_OWNER, the secret AuthData is + TPM_PERMANENT_DATA -> ownerAuth */ + /* ii. If TPM_STCLEAR_DATA -> ownerReference is pointing to a delegate row */ + if ((entityType == TPM_ET_OWNER) && + (tpm_state->tpm_stclear_data.ownerReference != TPM_KH_OWNER)) { + printf(" TPM_AuthSessions_GetData: Delegating to row %u\n", + tpm_state->tpm_stclear_data.ownerReference); + /* (1) Set R1 a row index to TPM_STCLEAR_DATA -> ownerReference */ + /* (2) Set D1 a TPM_DELEGATE_TABLE_ROW to TPM_PERMANENT_DATA -> delegateTable -> + delRow[R1] */ + if (rc == 0) { + rc = TPM_DelegateTable_GetValidRow + (&delegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + tpm_state->tpm_stclear_data.ownerReference); + } + /* (4) Validate the TPM_DELEGATE_PUBLIC D1 -> pub based on the command ordinal */ + /* (a) Validate D1 -> pub -> permissions based on the command ordinal */ + /* (b) Validate D1 -> pub -> pcrInfo based on the PCR values */ + if (rc == 0) { + rc = TPM_Delegations_CheckPermission(tpm_state, + &(delegateTableRow->pub), + entityType, + ordinal); + } + /* (3) Set the secret AuthData to D1 -> authValue */ + if (rc == 0) { + *hmacKey = &(delegateTableRow->authValue); + } + } + /* not owner or owner but not delegated */ + else { + /* the hmac key is the input authorization secret */ + *hmacKey = entityAuth; + } + break; + case TPM_PID_OSAP: + case TPM_PID_DSAP: /* the first part of DSAP is the same as OSAP */ + /* ensure that the OSAP shared secret is that derived from the entity using OSAP */ + if (rc == 0) { + rc = TPM_Digest_Compare(entityDigest, (*tpm_auth_session_data)->entityDigest); + } + /* extra processing for DSAP sessions */ + if ((*tpm_auth_session_data)->protocolID == TPM_PID_DSAP) { + /* check that delegation is allowed for the ordinal */ + if (rc == 0) { + rc = TPM_Delegations_CheckPermission(tpm_state, + &((*tpm_auth_session_data)->pub), + entityType, /* required for ordinal */ + ordinal); + } + /* check restrictions on delegation of a certified migration key */ + if ((rc == 0) && (entityType == TPM_ET_KEYHANDLE)) { + rc = TPM_Key_CheckRestrictDelegate + (tpmKey, + tpm_state->tpm_permanent_data.restrictDelegate); + } + } + /* the HMAC key is the shared secret calculated during OSAP setup */ + if (rc == 0) { + *hmacKey = &((*tpm_auth_session_data)->sharedSecret); + } + break; + default: /* should not occur */ + printf("TPM_AuthSessions_GetData: session protocolID %04hx unsupported\n", + (*tpm_auth_session_data)->protocolID); + rc = TPM_AUTHFAIL; + break; + } + } + return rc; +} + +/* TPM_AuthSessions_TerminateHandle() terminates the session associated with 'authHandle'. + +*/ + +TPM_RESULT TPM_AuthSessions_TerminateHandle(TPM_AUTH_SESSION_DATA *authSessions, + TPM_AUTHHANDLE authHandle) +{ + TPM_RESULT rc = 0; + TPM_AUTH_SESSION_DATA *tpm_auth_session_data; + + printf(" TPM_AuthSessions_TerminateHandle: Handle %08x\n", authHandle); + /* get the TPM_AUTH_SESSION_DATA associated with the TPM_AUTHHANDLE */ + if (rc == 0) { + rc = TPM_AuthSessions_GetEntry(&tpm_auth_session_data, authSessions, authHandle); + } + /* invalidate the valid handle */ + if (rc == 0) { + TPM_AuthSessionData_Delete(tpm_auth_session_data); + } + return rc; +} + +/* TPM_AuthSessions_TerminateEntity() terminates all OSAP and DSAP sessions connected to the + entityType. + + If the session associated with authHandle is terminated, continueAuthSession is set to FALSE for + the ordinal response. + + If the entityDigest is NULL, all sessions are terminated. If entityDigest is not NULL, only + those with a matching entityDigest are terminated. + */ + +void TPM_AuthSessions_TerminateEntity(TPM_BOOL *continueAuthSession, + TPM_AUTHHANDLE authHandle, + TPM_AUTH_SESSION_DATA *authSessions, + TPM_ENT_TYPE entityType, + TPM_DIGEST *entityDigest) +{ + uint32_t i; + TPM_BOOL terminate; + TPM_RESULT match; + + printf(" TPM_AuthSessions_TerminateEntity: entityType %04x\n", entityType); + for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + terminate = FALSE; + if ((authSessions[i].valid) && /* if the entry is valid */ + ((authSessions[i].protocolID == TPM_PID_OSAP) || /* if it's OSAP or DSAP */ + (authSessions[i].protocolID == TPM_PID_DSAP)) && + (authSessions[i].entityTypeByte == entityType)) { /* connected to entity type */ + /* if entityDigest is NULL, terminate all matching entityType */ + if (entityDigest == NULL) { + terminate = TRUE; + } + /* if entityDigest is not NULL, terminate only those matching entityDigest */ + else { + match = TPM_Digest_Compare(*entityDigest, authSessions[i].entityDigest); + if (match == 0) { + terminate = TRUE; + } + } + } + if (terminate) { + printf(" TPM_AuthSessions_TerminateEntity: Terminating handle %08x\n", + authSessions[i].handle); + /* if terminating the ordinal's session */ + if (authSessions[i].handle == authHandle) { + *continueAuthSession = FALSE; /* for the ordinal response */ + } + TPM_AuthSessionData_Delete(&authSessions[i]); + } + } + return; +} + +/* TPM_AuthSessions_TerminatexSAP terminates all OSAP and DSAP sessions + + If the session associated with authHandle is terminated, continueAuthSession is set to FALSE for + the ordinal response. + + It is safe to call this function during ordinal processing provided a copy of the shared secret + is first saved for the response HMAC calculation. + + The evenNonce is newly created for the response. The oddNonce and continueAuthSession are + command inputs, not part of the session data structure. +*/ + +void TPM_AuthSessions_TerminatexSAP(TPM_BOOL *continueAuthSession, + TPM_AUTHHANDLE authHandle, + TPM_AUTH_SESSION_DATA *authSessions) +{ + uint32_t i; + + printf(" TPM_AuthSessions_TerminatexSAP:\n"); + for (i = 0 ; i < TPM_MIN_AUTH_SESSIONS ; i++) { + if ((authSessions[i].protocolID == TPM_PID_OSAP) || + (authSessions[i]. protocolID == TPM_PID_DSAP)) { + /* if terminating the ordinal's session */ + if (authSessions[i].handle == authHandle) { + *continueAuthSession = FALSE; /* for the ordinal response */ + } + printf(" TPM_AuthSessions_TerminatexSAP: Terminating handle %08x\n", + authSessions[i].handle); + TPM_AuthSessionData_Delete(&authSessions[i]); + } + } + return; +} + +/* + Context List + + Methods to manipulate the TPM_STANY_DATA->contextList[TPM_MAX_SESSION_LIST] array +*/ + +/* TPM_ContextList_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_ContextList_Init(uint32_t *contextList) +{ + size_t i; + + printf(" TPM_ContextList_Init:\n"); + for (i = 0 ; i < TPM_MIN_SESSION_LIST ; i++) { + contextList[i] = 0; + } + return; +} + +/* TPM_ContextList_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_ContextList_Init() +*/ + +TPM_RESULT TPM_ContextList_Load(uint32_t *contextList, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_ContextList_Load:\n"); + for (i = 0 ; (rc == 0) && (i < TPM_MIN_SESSION_LIST) ; i++) { + rc = TPM_Load32(&(contextList[i]), stream, stream_size); + } + return rc; +} + +/* TPM_ContextList_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_ContextList_Store(TPM_STORE_BUFFER *sbuffer, + const uint32_t *contextList) +{ + TPM_RESULT rc = 0; + size_t i; + + printf(" TPM_ContextList_Store: Storing %u contexts\n", TPM_MIN_SESSION_LIST); + for (i = 0 ; (rc == 0) && (i < TPM_MIN_SESSION_LIST) ; i++) { + rc = TPM_Sbuffer_Append32(sbuffer, contextList[i]); + } + return rc; +} + +/* TPM_ContextList_GetSpace() returns 'space', the number of unused context list entries. + + If 'space' is non-zero, 'entry' points to the first unused index. +*/ + +void TPM_ContextList_GetSpace(uint32_t *space, + uint32_t *entry, + const uint32_t *contextList) +{ + uint32_t i; + + printf(" TPM_ContextList_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_MIN_SESSION_LIST ; i++) { + if (contextList[i] == 0) { /* zero values are free space */ + if (*space == 0) { + *entry = i; /* point to the first non-zero entry */ + } + (*space)++; + } + } + return; +} + +/* TPM_ContextList_GetEntry() gets the entry index corresponding to the value + +*/ + +TPM_RESULT TPM_ContextList_GetEntry(uint32_t *entry, + const uint32_t *contextList, + uint32_t value) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ContextList_GetEntry:\n"); + if (rc == 0) { + if (value == 0) { + printf("TPM_ContextList_GetEntry: Error, value %d never found\n", value); + rc = TPM_BADCONTEXT; + } + } + if (rc == 0) { + for (*entry = 0 ; *entry < TPM_MIN_SESSION_LIST ; (*entry)++) { + if (contextList[*entry] == value) { + break; + } + } + if (*entry == TPM_MIN_SESSION_LIST) { + printf("TPM_ContextList_GetEntry: Error, value %d not found\n", value); + rc = TPM_BADCONTEXT; + } + } + return rc; +} + +/* TPM_ContextList_StoreHandles() stores + + - the number of loaded context entries + - a list of context handles +*/ + +TPM_RESULT TPM_ContextList_StoreHandles(TPM_STORE_BUFFER *sbuffer, + const uint32_t *contextList) +{ + TPM_RESULT rc = 0; + uint16_t i; + uint16_t loaded; + + printf(" TPM_ContextList_StoreHandles:\n"); + if (rc == 0) { + loaded = 0; + /* count the number of loaded handles */ + for (i = 0 ; i < TPM_MIN_SESSION_LIST ; i++) { + if (contextList[i] != 0) { + loaded++; + } + } + /* store 'loaded' handle count */ + rc = TPM_Sbuffer_Append16(sbuffer, loaded); + } + for (i = 0 ; (rc == 0) && (i < TPM_MIN_SESSION_LIST ) ; i++) { + if (contextList[i] != 0) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, contextList[i]); /* store it */ + } + } + return rc; +} + +/* + TPM_CONTEXT_BLOB +*/ + +/* TPM_ContextBlob_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_ContextBlob_Init(TPM_CONTEXT_BLOB *tpm_context_blob) +{ + printf(" TPM_ContextBlob_Init:\n"); + tpm_context_blob->resourceType = 0; + tpm_context_blob->handle = 0; + memset(tpm_context_blob->label, 0, TPM_CONTEXT_LABEL_SIZE); + tpm_context_blob->contextCount = 0; + TPM_Digest_Init(tpm_context_blob->integrityDigest); + TPM_SizedBuffer_Init(&(tpm_context_blob->additionalData)); + TPM_SizedBuffer_Init(&(tpm_context_blob->sensitiveData)); + return; +} + +/* TPM_ContextBlob_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_ContextBlob_Init() + After use, call TPM_ContextBlob_Delete() to free memory +*/ + +TPM_RESULT TPM_ContextBlob_Load(TPM_CONTEXT_BLOB *tpm_context_blob, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ContextBlob_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CONTEXTBLOB, stream, stream_size); + } + /* load resourceType */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_context_blob->resourceType), stream, stream_size); + } + /* load handle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_context_blob->handle), stream, stream_size); + } + /* load label */ + if (rc == 0) { + rc = TPM_Loadn(tpm_context_blob->label, TPM_CONTEXT_LABEL_SIZE, stream, stream_size); + } + /* load contextCount */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_context_blob->contextCount), stream, stream_size); + } + /* load integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_context_blob->integrityDigest, stream, stream_size); + } + /* load additionalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_context_blob->additionalData), stream, stream_size); + } + /* load sensitiveData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_context_blob->sensitiveData), stream, stream_size); + } + return rc; +} + +/* TPM_ContextBlob_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_ContextBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CONTEXT_BLOB *tpm_context_blob) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ContextBlob_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CONTEXTBLOB); + } + /* store resourceType */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_context_blob->resourceType); + } + /* store handle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_context_blob->handle); + } + /* store label */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_context_blob->label, TPM_CONTEXT_LABEL_SIZE); + } + /* store contextCount */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_context_blob->contextCount); + } + /* store integrityDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_context_blob->integrityDigest); + } + /* store additionalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_context_blob->additionalData)); + } + /* store sensitiveData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_context_blob->sensitiveData)); + } + return rc; +} + +/* TPM_ContextBlob_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_ContextBlob_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_ContextBlob_Delete(TPM_CONTEXT_BLOB *tpm_context_blob) +{ + printf(" TPM_ContextBlob_Delete:\n"); + if (tpm_context_blob != NULL) { + TPM_SizedBuffer_Delete(&(tpm_context_blob->additionalData)); + TPM_SizedBuffer_Delete(&(tpm_context_blob->sensitiveData)); + TPM_ContextBlob_Init(tpm_context_blob); + } + return; +} + +/* + TPM_CONTEXT_SENSITIVE +*/ + +/* TPM_ContextSensitive_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_ContextSensitive_Init(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive) +{ + printf(" TPM_ContextSensitive_Init:\n"); + TPM_Nonce_Init(tpm_context_sensitive->contextNonce); + TPM_SizedBuffer_Init(&(tpm_context_sensitive->internalData)); + return; +} + +/* TPM_ContextSensitive_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_ContextSensitive_Init() + After use, call TPM_ContextSensitive_Delete() to free memory +*/ + +TPM_RESULT TPM_ContextSensitive_Load(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ContextSensitive_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CONTEXT_SENSITIVE, stream, stream_size); + } + /* load contextNonce */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_context_sensitive->contextNonce, stream, stream_size); + } + /* load internalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_context_sensitive->internalData), stream, stream_size); + } + return rc; +} + +/* TPM_ContextSensitive_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_ContextSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CONTEXT_SENSITIVE *tpm_context_sensitive) +{ + TPM_RESULT rc = 0; + + printf(" TPM_ContextSensitive_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CONTEXT_SENSITIVE); + } + /* store contextNonce */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_context_sensitive->contextNonce); + } + /* store internalData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_context_sensitive->internalData)); + } + return rc; +} + +/* TPM_ContextSensitive_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_ContextSensitive_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_ContextSensitive_Delete(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive) +{ + printf(" TPM_ContextSensitive_Delete:\n"); + if (tpm_context_sensitive != NULL) { + TPM_SizedBuffer_Delete(&(tpm_context_sensitive->internalData)); + TPM_ContextSensitive_Init(tpm_context_sensitive); + } + return; +} + +/* + Processing Functions +*/ + + +/* 18.1 TPM_OIAP rev 87 + +*/ + +TPM_RESULT TPM_Process_OIAP(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *authSession; /* the empty structure to be filled */ + TPM_BOOL got_handle = FALSE; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_AUTHHANDLE authHandle = 0; /* 0, no suggested value */ + + printf("TPM_Process_OIAP: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OIAP: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM_OIAP command allows the creation of an authorization session handle and the + tracking of the handle by the TPM. The TPM generates the handle and nonce. */ + /* 2. The TPM has an internal limit as to the number of handles that may be open at one time, so + the request for a new handle may fail if there is insufficient space available. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetNewHandle(&authSession, + &authHandle, + tpm_state->tpm_stclear_data.authSessions); + } + /* 3. Internally the TPM will do the following: */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OIAP: Using authHandle %08x\n", authHandle); + got_handle = TRUE; + /* a. TPM allocates space to save handle, protocol identification, both nonces and any other + information the TPM needs to manage the session. */ + authSession->protocolID = TPM_PID_OIAP; + /* b. TPM generates authHandle and nonceEven, returns these to caller */ + returnCode = TPM_Nonce_Generate(authSession->nonceEven); + } + /* 4. On each subsequent use of the OIAP session the TPM MUST generate a new nonceEven value. */ + /* 5. When TPM_OIAP is wrapped in an encrypted transport session no input or output + parameters encrypted */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OIAP: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + /* append authHandle */ + returnCode = TPM_Sbuffer_Append32(response, authHandle); + } + /* append nonceEven */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, authSession->nonceEven); + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if the handle is not being returned, it should be terminated */ + if (((returnCode != 0) || (rcf != 0)) && got_handle) { + TPM_AuthSessionData_Delete(authSession); + } + return rcf; +} + +/* 18.2 TPM_OSAP rev 98 + + The TPM_OSAP command creates the authorization handle, the shared secret and generates nonceEven + and nonceEvenOSAP. + + 1 The TPM_OSAP command allows the creation of an authorization handle and the tracking of the + handle by the TPM. The TPM generates the handle, nonceEven and nonceEvenOSAP. + + 2. The TPM has an internal limit on the number of handles that may be open at one time, so the + request for a new handle may fail if there is insufficient space available. + + 3. The TPM_OSAP allows the binding of an authorization to a specific entity. This allows the + caller to continue to send in authorization data for each command but not have to request the + information or cache the actual authorization data. + + 4. When TPM_OSAP is wrapped in an encrypted transport session, no input or output parameters are + encrypted + + 5. If the owner pointer is pointing to a delegate row, the TPM internally MUST treat the OSAP + session as a DSAP session + + 6. TPM_ET_SRK or TPM_ET_KEYHANDLE with a value of TPM_KH_SRK MUST specify the SRK. + + 7. If the entity is tied to PCR values, the PCR's are not validated during the TPM_OSAP ordinal + session creation. The PCR's are validated when the OSAP session is used. +*/ + +TPM_RESULT TPM_Process_OSAP(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_ENTITY_TYPE entityType; /* The type of entity in use */ + uint32_t entityValue = 0; /* The selection value based on entityType, e.g. a + keyHandle # */ + TPM_NONCE nonceOddOSAP; /* The nonce generated by the caller associated with + the shared secret. */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *authSession; /* the empty structure to be filled */ + TPM_BOOL got_handle = FALSE; + TPM_SECRET *authData; /* usageAuth for the entity */ + TPM_DIGEST *entityDigest = NULL; /* digest of the entity establishing the OSAP + session, initialize to silence compiler */ + TPM_KEY *authKey; /* key to authorize */ + TPM_BOOL parentPCRStatus; + TPM_COUNTER_VALUE *counterValue; /* associated with entityValue */ + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; /* associated with entityValue */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_AUTHHANDLE authHandle = 0; /* Handle that TPM creates that points to the authorization + state. */ + TPM_NONCE nonceEvenOSAP; /* Nonce generated by TPM and associated with shared + secret. */ + + printf("TPM_Process_OSAP: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* get entityType */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&entityType, &command, ¶mSize); + } + /* get entityValue */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityType %04hx\n", entityType); + returnCode = TPM_Load32(&entityValue, &command, ¶mSize); + } + /* get nonceOddOSAP */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityValue %08x\n", entityValue); + returnCode = TPM_Nonce_Load(nonceOddOSAP, &command, ¶mSize); + } + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_OWNER | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_OSAP: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM creates S1 a storage area that keeps track of the information associated with the + authorization. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetNewHandle(&authSession, + &authHandle, + tpm_state->tpm_stclear_data.authSessions); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: Using authHandle %08x\n", authHandle); + got_handle = TRUE; + /* 2. S1 MUST track the following information: */ + /* a. Protocol identification */ + authSession->protocolID = TPM_PID_OSAP; /* save protocol identification */ + authSession->entityTypeByte = entityType & 0x00ff; /* save entity type LSB */ + /* b. nonceEven */ + /* i. Initialized to the next value from the TPM RNG */ + TPM_Nonce_Generate(authSession->nonceEven); + /* c. shared secret NOTE: determined below */ + /* d. ADIP encryption scheme from TPM_ENTITY_TYPE entityType */ + authSession->adipEncScheme = (entityType >> 8) & 0x00ff; /* save entity type MSB */ + /* e. Any other internal TPM state the TPM needs to manage the session */ + /* 3. The TPM MUST create and MAY track the following information */ + /* a. nonceEvenOSAP */ + /* i. Initialized to the next value from the TPM RNG */ + TPM_Nonce_Generate(nonceEvenOSAP); + /* 4. HMAC, shared secret NOTE: determined below */ + /* 5. Check if the ADIP encryption scheme specified by entityType is supported, if not + return TPM_INAPPROPRIATE_ENC. */ + returnCode = TPM_AuthSessionData_CheckEncScheme(authSession->adipEncScheme, + tpm_state->tpm_permanent_flags.FIPS); + } + if (returnCode == TPM_SUCCESS) { + switch (authSession->entityTypeByte) { + case TPM_ET_KEYHANDLE: + /* 6. If entityType = TPM_ET_KEYHANDLE */ + /* a. The entity to authorize is a key held in the TPM. entityValue contains the + keyHandle that holds the key. */ + /* b. If entityValue is TPM_KH_OPERATOR return TPM_BAD_HANDLE */ + if (returnCode == TPM_SUCCESS) { + if (entityValue == TPM_KH_OPERATOR) { + printf("TPM_Process_OSAP: Error, " + "entityType TPM_ET_KEYHANDLE entityValue TPM_KH_OPERATOR\n"); + returnCode = TPM_BAD_HANDLE; + } + } + /* look up and get the TPM_KEY authorization data */ + if (returnCode == TPM_SUCCESS) { + /* get the TPM_KEY, entityValue is the handle */ + printf("TPM_Process_OSAP: entityType TPM_ET_KEYHANDLE entityValue %08x\n", + entityValue); + /* TPM_KeyHandleEntries_GetKey() does the mapping from TPM_KH_SRK to the SRK */ + returnCode = TPM_KeyHandleEntries_GetKey(&authKey, + &parentPCRStatus, + tpm_state, + entityValue, + TRUE, /* read only */ + TRUE, /* ignore PCRs */ + FALSE); /* cannot use EK */ + } + if (returnCode == TPM_SUCCESS) { + /* get the entityDigest for the key */ + entityDigest = &(authKey->tpm_store_asymkey->pubDataDigest); + /* get the usageAuth for the key */ + returnCode = TPM_Key_GetUsageAuth(&authData, authKey); + } + break; + case TPM_ET_OWNER: + /* 7. else if entityType = TPM_ET_OWNER */ + /* a. This value indicates that the entity is the TPM owner. entityValue is ignored. */ + /* b. The HMAC key is the secret pointed to by ownerReference (owner secret or delegated + secret) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityType TPM_ET_OWNER, ownerReference %08x\n", + tpm_state->tpm_stclear_data.ownerReference); + /* verify that an owner is installed */ + if (!tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_Process_OSAP: Error, no owner\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + /* owner reference is owner, use the owner authorization data */ + if (tpm_state->tpm_stclear_data.ownerReference == TPM_KH_OWNER) { + entityDigest = &(tpm_state->tpm_permanent_data.ownerAuth); + authData = &(tpm_state->tpm_permanent_data.ownerAuth); + } + /* Description 5. If the owner pointer is pointing to a delegate row, the TPM + internally MUST treat the OSAP session as a DSAP session */ + else { + returnCode = TPM_OSAPDelegate(&entityDigest, + &authData, + authSession, + tpm_state, + tpm_state->tpm_stclear_data.ownerReference); + } + } + break; + case TPM_ET_SRK: + /* 8. else if entityType = TPM_ET_SRK */ + /* a. The entity to authorize is the SRK. entityValue is ignored. */ + printf("TPM_Process_OSAP: entityType TPM_ET_SRK\n"); + entityDigest = &(tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest); + returnCode = TPM_Key_GetUsageAuth(&authData, &(tpm_state->tpm_permanent_data.srk)); + break; + case TPM_ET_COUNTER: + /* 9. else if entityType = TPM_ET_COUNTER */ + /* a. The entity is a monotonic counter, entityValue contains the counter handle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityType TPM_ET_COUNTER entityValue %08x\n", + entityValue); + returnCode = + TPM_Counters_GetCounterValue(&counterValue, + tpm_state->tpm_permanent_data.monotonicCounter, + entityValue); + } + if (returnCode == TPM_SUCCESS) { + /* get the entityDigest for the counter */ + entityDigest = &(counterValue->digest); + /* get the authData for the counter */ + authData = &(counterValue->authData); + } + break; + case TPM_ET_NV: + /* 10. else if entityType = TPM_ET_NV + a. The entity is a NV index, entityValue contains the NV index */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_OSAP: entityType TPM_ET_NV\n"); + returnCode = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive, + &(tpm_state->tpm_nv_index_entries), + entityValue); + } + if (returnCode == TPM_SUCCESS) { + /* get the entityDigest for the NV data */ + entityDigest = &(tpm_nv_data_sensitive->digest); + /* get the authData for the NV data */ + authData = &(tpm_nv_data_sensitive->authValue); + } + break; + default: + /* 11. else return TPM_INVALID_PARAMETER */ + printf("TPM_Process_OSAP: Error, unknown entityType %04x\n", entityType); + returnCode = TPM_BAD_PARAMETER; + break; + } + } + /* 2.c. shared secret */ + /* 4. The TPM calculates the shared secret using an HMAC calculation. The key for the HMAC + calculation is the secret AuthData assigned to the key handle identified by entityValue. + The input to the HMAC calculation is the concatenation of nonces nonceEvenOSAP and + nonceOddOSAP. The output of the HMAC calculation is the shared secret which is saved in + the authorization area associated with authHandle */ + if (returnCode == TPM_SUCCESS) { + TPM_Digest_Copy(authSession->entityDigest, *entityDigest); + TPM_PrintFour("TPM_Process_OSAP: entityDigest", *entityDigest); + TPM_PrintFour("TPM_Process_OSAP: authData", *authData); + TPM_PrintFour("TPM_Process_OSAP: nonceEvenOSAP", nonceEvenOSAP); + TPM_PrintFour("TPM_Process_OSAP: nonceOddOSAP", nonceOddOSAP); + returnCode = TPM_HMAC_Generate(authSession->sharedSecret, + *authData, /* HMAC key */ + TPM_NONCE_SIZE, nonceEvenOSAP, + TPM_NONCE_SIZE, nonceOddOSAP, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_OSAP: sharedSecret", authSession->sharedSecret); + } + /* 12. On each subsequent use of the OSAP session the TPM MUST generate a new nonce value. + NOTE: Done as the response is generated. */ + /* 13. The TPM MUST ensure that OSAP shared secret is only available while the OSAP session is + valid. + */ + /* 14. The session MUST terminate upon any of the following conditions: + a. The command that uses the session returns an error + NOTE Done by command + b. The resource is evicted from the TPM or otherwise invalidated + NOTE Done by evict or flush + c. The session is used in any command for which the shared secret is used to encrypt an + input parameter (TPM_ENCAUTH) + NOTE Done by the command + d. The TPM Owner is cleared + NOTE Done by owner clear + e. TPM_ChangeAuthOwner is executed and this session is attached to the owner authorization + NOTE Done by TPM_ChangeAuthOwner + f. The session explicitly terminated with continueAuth, TPM_Reset or TPM_FlushSpecific + NOTE Done by the ordinal processing + g. All OSAP sessions associated with the delegation table MUST be invalidated when any of the + following commands execute: + i. TPM_Delegate_Manage + ii. TPM_Delegate_CreateOwnerDelegation with Increment==TRUE + iii. TPM_Delegate_LoadOwnerDelegation + NOTE Done by the ordinal processing + */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_OSAP: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + /* append authHandle */ + returnCode = TPM_Sbuffer_Append32(response, authHandle); + } + /* append nonceEven */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, authSession->nonceEven); + } + /* append nonceEvenOSAP */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, nonceEvenOSAP); + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if the handle is not being returned, it should be terminated */ + if (((returnCode != 0) || (rcf != 0)) && got_handle) { + TPM_AuthSessionData_Delete(authSession); + } + /* + cleanup + */ + return rcf; +} + +/* 18.3 TPM_DSAP rev 106 + + The TPM_DSAP command creates the authorization session handle using a delegated AuthData value + passed into the command as an encrypted blob or from the internal delegation table. It can be + used to start an authorization session for a user key or the owner. + + As in TPM_OSAP, it generates a shared secret and generates nonceEven and nonceEvenOSAP. + + 1. The TPM_DSAP command allows the creation of an authorization session handle and the tracking + of the handle by the TPM. The TPM generates the handle, nonceEven and nonceEvenOSAP. + + 2. The TPM has an internal limit on the number of handles that may be open at one time, so the + request for a new handle may fail if there is insufficient space available. + + 3. The TPM_DSAP allows the binding of a delegated authorization to a specific entity. This allows + the caller to continue to send in AuthData for each command but not have to request the + information or cache the actual AuthData. + + 4. On each subsequent use of the DSAP session the TPM MUST generate a new nonce value and check if + the ordinal to be executed has delegation to execute. The TPM MUST ensure that the DSAP shared + secret is only available while the DSAP session is valid. + + 5. When TPM_DSAP is wrapped in an encrypted transport session + a. For input the only parameter encrypted or logged is entityValue + b. For output no parameters are encrypted or logged + + 6. The DSAP session MUST terminate under any of the following conditions + + a. The command that uses the session returns an error + b. If attached to a key, when the key is evicted from the TPM or otherwise invalidated + c. The session is used in any command for which the shared secret is used to encrypt an + input parameter (TPM_ENCAUTH) + d. The TPM Owner is cleared + e. TPM_ChangeAuthOwner is executed and this session is attached to the owner + authorization + f. The session explicitly terminated with continueAuth, TPM_Reset or TPM_FlushSpecific + g. All DSAP sessions MUST be invalidated when any of the following commands execute: + + i. TPM_Delegate_CreateOwnerDelegation + (1) When Increment is TRUE + ii. TPM_Delegate_LoadOwnerDelegation + iii. TPM_Delegate_Manage + + NOTE Done by the ordinal processing + + entityType = TPM_ET_DEL_OWNER_BLOB + The entityValue parameter contains a delegation blob structure. + entityType = TPM_ET_DEL_ROW + The entityValue parameter contains a row number in the nv Delegation table which should be + used for the AuthData value. +*/ + +TPM_RESULT TPM_Process_DSAP(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_ENTITY_TYPE entityType; /* The type of delegation information to use */ + TPM_KEY_HANDLE keyHandle = 0; /* Key for which delegated authority corresponds, or 0 if + delegated owner activity. Only relevant if entityValue + equals TPM_DELEGATE_USEKEY_BLOB */ + TPM_NONCE nonceOddDSAP; /* The nonce generated by the caller associated with the + shared secret. */ + TPM_SIZED_BUFFER entityValue; /* TPM_DELEGATE_KEY_BLOB or TPM_DELEGATE_OWNER_BLOB or + index. MUST not be empty. If entityType is TPM_ET_DEL_ROW + then entityValue is a TPM_DELEGATE_INDEX */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *authSession; /* the empty structure to be filled */ + unsigned char *stream; /* temp input stream */ + uint32_t stream_size; + TPM_DELEGATE_OWNER_BLOB b1DelegateOwnerBlob; + TPM_DELEGATE_KEY_BLOB k1DelegateKeyBlob; + TPM_KEY *delKey; /* key corresponding to keyHandle */ + TPM_BOOL parentPCRStatus; + TPM_DELEGATE_SENSITIVE s1DelegateSensitive; + uint32_t delegateRowIndex; + TPM_DELEGATE_TABLE_ROW *d1DelegateTableRow; + TPM_SECRET *a1AuthValue; + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + + TPM_BOOL got_handle = FALSE; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_AUTHHANDLE authHandle = 0; /* Handle that TPM creates that points to the authorization + state. */ + TPM_NONCE nonceEvenDSAP; /* Nonce generated by TPM and associated with shared + secret. */ + + printf("TPM_Process_DSAP: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&entityValue); /* freed @1 */ + TPM_DelegateOwnerBlob_Init(&b1DelegateOwnerBlob); /* freed @2 */ + TPM_DelegateKeyBlob_Init(&k1DelegateKeyBlob); /* freed @3 */ + TPM_DelegateSensitive_Init(&s1DelegateSensitive); /* freed @4 */ + /* + get inputs + */ + /* get entityType */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&entityType, &command, ¶mSize); + } + /* get keyHandle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DSAP: entityType %04hx\n", entityType); + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* get nonceOddDSAP */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DSAP: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(nonceOddDSAP, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command + sizeof(uint32_t); /* audit entityValue but not entityValueSize */ + /* get entityValue */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&entityValue, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_OWNER | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_DSAP: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* use a temporary copy so the original values are not moved */ + stream = entityValue.buffer; + stream_size = entityValue.size; + switch (entityType & 0x00ff) { /* entity type LSB is the actual entity type */ + case TPM_ET_DEL_OWNER_BLOB: + /* 1. If entityType == TPM_ET_DEL_OWNER_BLOB */ + /* a. Map entityValue to B1 a TPM_DELEGATE_OWNER_BLOB */ + /* b. Validate that B1 is a valid TPM_DELEGATE_OWNER_BLOB, return TPM_WRONG_ENTITYTYPE + on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateOwnerBlob_Load(&b1DelegateOwnerBlob, + &stream, &stream_size); + if (returnCode != TPM_SUCCESS) { + returnCode = TPM_WRONG_ENTITYTYPE; + } + } + /* c. Locate B1 -> pub -> familyID in the TPM_FAMILY_TABLE and set familyRow to + indicate row, return TPM_BADINDEX if not found */ + /* d. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */ + /* e. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + b1DelegateOwnerBlob.pub.familyID); + } + /* f. Verify that B1->verificationCount equals FR -> verificationCount. */ + if (returnCode == TPM_SUCCESS) { + if (b1DelegateOwnerBlob.pub.verificationCount != familyRow->verificationCount) { + printf("TPM_Process_DSAP: Error, verificationCount mismatch %u %u\n", + b1DelegateOwnerBlob.pub.verificationCount, familyRow->verificationCount); + returnCode = TPM_FAMILYCOUNT; + } + } + /* g. Validate the integrity of the blob */ + /* i. Copy B1 -> integrityDigest to H2 */ + /* ii. Set B1 -> integrityDigest to NULL */ + /* iii. Create H3 the HMAC of B1 using tpmProof as the secret */ + /* iv. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &b1DelegateOwnerBlob, /* structure */ + b1DelegateOwnerBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateOwnerBlob_Store,/* store function */ + TPM_AUTHFAIL); /* error code */ + } + /* h. Create S1 a TPM_DELEGATE_SENSITIVE by decrypting B1 -> sensitiveArea using + TPM_DELEGATE_KEY */ + /* i. Validate S1 values */ + /* i. S1 -> tag is TPM_TAG_DELEGATE_SENSITIVE */ + /* ii. Return TPM_BAD_DELEGATE on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateSensitive_DecryptEncData + (&s1DelegateSensitive, /* decrypted data */ + &(b1DelegateOwnerBlob.sensitiveArea), + tpm_state->tpm_permanent_data.delegateKey); + } + /* j. Set A1 to S1 -> authValue */ + if (returnCode == TPM_SUCCESS) { + a1AuthValue = &(s1DelegateSensitive.authValue); + } + break; + case TPM_ET_DEL_ROW: + /* 2. Else if entityType == TPM_ET_DEL_ROW */ + /* a. Verify that entityValue points to a valid row in the delegation table. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&delegateRowIndex, &stream, &stream_size); + } + /* b. Set D1 to the delegation information in the row. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_DelegateTable_GetValidRow(&d1DelegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + delegateRowIndex); + } + if (returnCode == TPM_SUCCESS) { + /* c. Set A1 to D1->authValue. */ + a1AuthValue = &d1DelegateTableRow->authValue; + /* d. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate + that row, return TPM_BADINDEX if not found */ + /* e. Set FR to TPM_FAMILY_TABLE.FamTableRow[familyRow] */ + /* f. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + returnCode = + TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + d1DelegateTableRow->pub.familyID); + } + /* g. Verify that D1->verificationCount equals FR -> verificationCount. */ + if (returnCode == TPM_SUCCESS) { + if (d1DelegateTableRow->pub.verificationCount != familyRow->verificationCount) { + printf("TPM_Process_DSAP: Error, verificationCount mismatch %u %u\n", + d1DelegateTableRow->pub.verificationCount, familyRow->verificationCount); + returnCode = TPM_FAMILYCOUNT; + } + } + break; + case TPM_ET_DEL_KEY_BLOB: + /* 3. Else if entityType == TPM_ET_DEL_KEY_BLOB */ + /* a. Map entityValue to K1 a TPM_DELEGATE_KEY_BLOB */ + /* b. Validate that K1 is a valid TPM_DELEGATE_KEY_BLOB, return TPM_WRONG_ENTITYTYPE on + error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateKeyBlob_Load(&k1DelegateKeyBlob, &stream, &stream_size); + if (returnCode != TPM_SUCCESS) { + returnCode = TPM_WRONG_ENTITYTYPE; + } + } + /* c. Locate K1 -> pub -> familyID in the TPM_FAMILY_TABLE and set familyRow to + indicate that row, return TPM_BADINDEX if not found */ + /* d. Set FR to TPM_FAMILY_TABLE.FamTableRow[familyRow] */ + /* e. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + k1DelegateKeyBlob.pub.familyID); + } + /* f. Verify that K1 -> pub -> verificationCount equals FR -> verificationCount. */ + if (returnCode == TPM_SUCCESS) { + if (k1DelegateKeyBlob.pub.verificationCount != familyRow->verificationCount) { + printf("TPM_Process_DSAP: Error, verificationCount mismatch %u %u\n", + k1DelegateKeyBlob.pub.verificationCount, familyRow->verificationCount); + returnCode = TPM_FAMILYCOUNT; + } + } + /* g. Validate the integrity of the blob */ + /* i. Copy K1 -> integrityDigest to H2 */ + /* ii. Set K1 -> integrityDigest to NULL */ + /* iii. Create H3 the HMAC of K1 using tpmProof as the secret */ + /* iv. Compare H2 to H3 return TPM_AUTHFAIL on mismatch */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &k1DelegateKeyBlob, /* structure */ + k1DelegateKeyBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_DelegateKeyBlob_Store, /* store function */ + TPM_AUTHFAIL); /* error code */ + } + /* h. Validate that K1 -> pubKeyDigest identifies keyHandle, return TPM_KEYNOTFOUND on + error */ + /* get the TPM_KEY corresponding to keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&delKey, + &parentPCRStatus, + tpm_state, + keyHandle, + TRUE, /* read only */ + TRUE, /* ignore PCRs at setup */ + FALSE); /* cannot use EK */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_CheckStructure(k1DelegateKeyBlob.pubKeyDigest, + &(delKey->pubKey), + (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store, + TPM_KEYNOTFOUND); + } + /* i. Create S1 a TPM_DELEGATE_SENSITIVE by decrypting K1 -> sensitiveArea using + TPM_DELEGATE_KEY */ + /* j. Validate S1 values */ + /* i. S1 -> tag is TPM_TAG_DELEGATE_SENSITIVE */ + /* ii. Return TPM_BAD_DELEGATE on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_DelegateSensitive_DecryptEncData + (&s1DelegateSensitive, /* decrypted data */ + &(k1DelegateKeyBlob.sensitiveArea), + tpm_state->tpm_permanent_data.delegateKey); + } + /* k. Set A1 to S1 -> authValue */ + if (returnCode == TPM_SUCCESS) { + a1AuthValue = &(s1DelegateSensitive.authValue); + } + break; + default: + /* 4. Else return TPM_BAD_PARAMETER */ + printf("TPM_Process_DSAP: Error, bad entityType %04hx\n", entityType); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 5. Generate a new authorization session handle and reserve space to save protocol + identification, shared secret, pcrInfo, both nonces, ADIP encryption scheme, delegated + permission bits and any other information the TPM needs to manage the session. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetNewHandle(&authSession, + &authHandle, + tpm_state->tpm_stclear_data.authSessions); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_DSAP: Using authHandle %08x\n", authHandle); + got_handle = TRUE; + /* save protocol identification */ + authSession->protocolID = TPM_PID_DSAP; + /* save the ADIP encryption scheme */ + authSession->adipEncScheme = (entityType >> 8) & 0x00ff; + /* NOTE: added: Check if the ADIP encryption scheme specified by entityType is supported, if + not return TPM_INAPPROPRIATE_ENC. */ + returnCode = TPM_AuthSessionData_CheckEncScheme(authSession->adipEncScheme, + tpm_state->tpm_permanent_flags.FIPS); + } + if (returnCode == TPM_SUCCESS) { + if (entityType == TPM_ET_DEL_KEY_BLOB) { + /* map the entity type to a key */ + authSession->entityTypeByte = TPM_ET_KEYHANDLE; + /* Save the entityDigest for comparison during use. */ + TPM_Digest_Copy(authSession->entityDigest, delKey->tpm_store_asymkey->pubDataDigest); + /* Save the TPM_DELEGATE_PUBLIC to check the permissions and pcrInfo at DSAP session + use. */ + returnCode =TPM_DelegatePublic_Copy(&(authSession->pub), &(k1DelegateKeyBlob.pub)); + } + else { + /* owner or blob or delegate row are both owner auth */ + authSession->entityTypeByte = TPM_ET_OWNER; + /* Save the entityDigest for comparison during use. */ + TPM_Digest_Copy(authSession->entityDigest, tpm_state->tpm_permanent_data.ownerAuth); + /* Save the TPM_DELEGATE_PUBLIC to check the permissions and pcrInfo at DSAP session + use. */ + if (entityType == TPM_ET_DEL_OWNER_BLOB) { + returnCode = TPM_DelegatePublic_Copy(&(authSession->pub), + &(b1DelegateOwnerBlob.pub)); + } + else { /* TPM_ET_DEL_ROW */ + returnCode = TPM_DelegatePublic_Copy(&(authSession->pub), + &(d1DelegateTableRow->pub)); + } + } + /* 6. Read two new values from the RNG to generate nonceEven and nonceEvenOSAP. */ + TPM_Nonce_Generate(authSession->nonceEven); + TPM_Nonce_Generate(nonceEvenDSAP); + } + /* 7. The TPM calculates the shared secret using an HMAC calculation. The key for the HMAC + calculation is A1. The input to the HMAC calculation is the concatenation of nonces + nonceEvenOSAP and nonceOddOSAP. The output of the HMAC calculation is the shared secret + which is saved in the authorization area associated with authHandle. */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_DSAP: authData", *a1AuthValue); + TPM_PrintFour("TPM_Process_DSAP: nonceEvenOSAP", nonceEvenDSAP); + TPM_PrintFour("TPM_Process_DSAP: nonceOddOSAP", nonceOddDSAP); + returnCode = TPM_HMAC_Generate(authSession->sharedSecret, + *a1AuthValue, /* HMAC key */ + TPM_NONCE_SIZE, nonceEvenDSAP, + TPM_NONCE_SIZE, nonceOddDSAP, + 0, NULL); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_DSAP: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + /* append authHandle */ + returnCode = TPM_Sbuffer_Append32(response, authHandle); + } + /* append nonceEven */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, authSession->nonceEven); + } + /* append nonceEvenDSAP */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Store(response, nonceEvenDSAP); + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if the handle is not being returned, it should be terminated */ + if (((returnCode != 0) || (rcf != 0)) && got_handle) { + TPM_AuthSessionData_Delete(authSession); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&entityValue); /* @1 */ + TPM_DelegateOwnerBlob_Delete(&b1DelegateOwnerBlob); /* @2 */ + TPM_DelegateKeyBlob_Delete(&k1DelegateKeyBlob); /* @3 */ + TPM_DelegateSensitive_Delete(&s1DelegateSensitive); /* @4 */ + return rcf; +} + +/* TPM_DSAPDelegate() implements the actions common to TPM_DSAP and TPM_OSAP with + ownerReference pointing to a delegate row. + + 'entityDigest' and 'authData' are returned, as they are used by common code. + authSession. + + protocolID is changed to DSAP. + the TPM_DELEGATE_PUBLIC blob is copied to the OSAP/DSAP session structure. +*/ + +static TPM_RESULT TPM_OSAPDelegate(TPM_DIGEST **entityDigest, + TPM_SECRET **authData, + TPM_AUTH_SESSION_DATA *authSession, + tpm_state_t *tpm_state, + uint32_t delegateRowIndex) +{ + TPM_RESULT rc = 0; + TPM_DELEGATE_TABLE_ROW *d1DelegateTableRow; + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + + printf("TPM_DSAPCommon: Index %u\n", delegateRowIndex); + /* 2. Else if entityType == TPM_ET_DEL_ROW */ + /* a. Verify that entityValue points to a valid row in the delegation table. */ + /* b. Set d1 to the delegation information in the row. */ + if (rc == TPM_SUCCESS) { + rc = TPM_DelegateTable_GetValidRow(&d1DelegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + delegateRowIndex); + } + if (rc == TPM_SUCCESS) { + /* d. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate that + row, return TPM_BADINDEX if not found */ + /* e. Set FR to TPM_FAMILY_TABLE.FamTableRow[familyRow] */ + /* f. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + rc = TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + d1DelegateTableRow->pub.familyID); + } + /* g. Verify that d1->verificationCount equals FR -> verificationCount. */ + if (rc == TPM_SUCCESS) { + if (d1DelegateTableRow->pub.verificationCount != familyRow->verificationCount) { + printf("TPM_DSAPCommon: Error, verificationCount mismatch %u %u\n", + d1DelegateTableRow->pub.verificationCount, familyRow->verificationCount); + rc = TPM_FAMILYCOUNT; + } + } + if (rc == TPM_SUCCESS) { + /* c. Set a1 to d1->authValue. */ + *authData = &d1DelegateTableRow->authValue; /* use owner delegate authorization value */ + /* indicate later that the entity is the 'owner'. Use the real owner auth because the + ordinal doesn't know about the delegation */ + *entityDigest = &(tpm_state->tpm_permanent_data.ownerAuth); + authSession->protocolID = TPM_PID_DSAP; /* change from OSAP to DSAP */ + /* Save the TPM_DELEGATE_PUBLIC to check the permissions and pcrInfo at DSAP session + use. */ + rc = TPM_DelegatePublic_Copy(&(authSession->pub), + &(d1DelegateTableRow->pub)); + } + return rc; +} + +/* 18.4 TPM_SetOwnerPointer rev 109 + + 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 to provide an owner delegation function for legacy code that + does not itself support delegation. Normally, TPM_STCLEAR_DATA->ownerReference points to + TPM_KH_OWNER, indicating that OIAP and OSAP sessions should use the owner authorization. This + command allows ownerReference to point to an index in the delegation table, indicating that + OIAP and OSAP sessions should use the delegation authorization. + + In use, a TSS supporting delegation would create and load the owner delegation and set the owner + pointer to that delegation. From then on, a legacy TSS application would use its OIAP and OSAP + sessions with the delegated owner authorization. + + Since this command is not authorized, the ownerReference is open to DoS attacks. Applications can + attempt to recover from a failing owner authorization by resetting ownerReference to an + appropriate value. + + This command intentionally does not clear OSAP sessions. A TPM 1.1 application gets the benefit + of owner delegation, while the original owner can use a pre-existing OSAP session with the actual + owner authorization. +*/ + +TPM_RESULT TPM_Process_SetOwnerPointer(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) + +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_ENTITY_TYPE entityType; /* The type of entity in use */ + uint32_t entityValue = 0; /* The selection value based on entityType */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_STCLEAR_DATA *v1StClearData; + TPM_DELEGATE_TABLE_ROW *b1DelegateTableRow; /* delegate row indicated by entityValue */ + TPM_FAMILY_TABLE_ENTRY *familyRow; /* family table row containing familyID */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SetOwnerPointer: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get entityType */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&entityType, &command, ¶mSize); + } + /* get entityValue */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerPointer: entityType %04hx\n", entityType); + returnCode = TPM_Load32(&entityValue, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerPointer: entityValue %08x\n", entityValue); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SetOwnerPointer: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Map TPM_STCLEAR_DATA to V1 */ + if (returnCode == TPM_SUCCESS) { + v1StClearData = &(tpm_state->tpm_stclear_data); + /* 2. If entityType = TPM_ET_DEL_ROW */ + if (entityType == TPM_ET_DEL_ROW) { + /* a. This value indicates that the entity is a delegate row. entityValue is a delegate + index in the delegation table. */ + /* b. Validate that entityValue points to a legal row within the delegate table stored + within the TPM. If not return TPM_BADINDEX */ + /* i. Set D1 to the delegation information in the row. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_DelegateTable_GetValidRow(&b1DelegateTableRow, + &(tpm_state->tpm_permanent_data.delegateTable), + entityValue); + + } + /* c. Locate D1 -> familyID in the TPM_FAMILY_TABLE and set familyRow to indicate that + row, return TPM_BADINDEX if not found. */ + /* d. Set FR to TPM_FAMILY_TABLE.famTableRow[familyRow] */ + /* e. If FR -> flags TPM_FAMFLAG_ENABLED is FALSE, return TPM_DISABLED_CMD */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_FamilyTable_GetEnabledEntry(&familyRow, + &(tpm_state->tpm_permanent_data.familyTable), + b1DelegateTableRow->pub.familyID); + } + /* f. Verify that B1->verificationCount equals FR -> verificationCount. */ + if (returnCode == TPM_SUCCESS) { + if (b1DelegateTableRow->pub.verificationCount != familyRow->verificationCount) { + printf("TPM_Process_SetOwnerPointer: Error, " + "verificationCount mismatch %u %u\n", + b1DelegateTableRow->pub.verificationCount, familyRow->verificationCount); + returnCode = TPM_FAMILYCOUNT; + } + } + /* g. The TPM sets V1-> ownerReference to entityValue */ + /* h. Return TPM_SUCCESS */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SetOwnerPointer: Setting ownerReference to %08x\n", + entityValue); + v1StClearData->ownerReference = entityValue; + } + } + /* 3. else if entityType = TPM_ET_OWNER */ + else if (entityType == TPM_ET_OWNER) { + /* a. This value indicates that the entity is the TPM owner. entityValue is ignored. */ + /* b. The TPM sets V1-> ownerReference to TPM_KH_OWNER */ + /* c. Return TPM_SUCCESS */ + printf("TPM_Process_SetOwnerPointer: Setting ownerReference to %08x\n", TPM_KH_OWNER); + v1StClearData->ownerReference = TPM_KH_OWNER; + } + /* 4. Return TPM_BAD_PARAMETER */ + else { + printf("TPM_Process_SetOwnerPointer: Error, bad entityType\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SetOwnerPointer: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 27.1.2 TPM_Terminate_Handle rev 87 + + This allows the TPM manager to clear out information in a session handle. + + The TPM may maintain the authorization session even though a key attached to it has been unloaded + or the authorization session itself has been unloaded in some way. When a command is executed + that requires this session, it is the responsibility of the external software to load both the + entity and the authorization session information prior to command execution. + + The TPM SHALL terminate the session and destroy all data associated with the session indicated. +*/ + +TPM_RESULT TPM_Process_TerminateHandle(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_TerminateHandle: Ordinal Entry\n"); + /* + get inputs + */ + /* get handle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&authHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_TerminateHandle: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* terminate the handle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TerminateHandle: Using authHandle %08x\n", authHandle); + returnCode = TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, + authHandle); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_TerminateHandle: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 22.1 TPM_FlushSpecific rev 104 + + TPM_FlushSpecific flushes from the TPM a specific handle. + + TPM_FlushSpecific releases the resources associated with the given handle. +*/ + +TPM_RESULT TPM_Process_FlushSpecific(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_HANDLE handle; /* The handle of the item to flush */ + TPM_RESOURCE_TYPE resourceType = 0; /* The type of resource that is being flushed */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + uint32_t r1Resource; /* the context resource being flushed */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* key table entry for the handle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_FlushSpecific: Ordinal Entry\n"); + /* + get inputs + */ + /* get handle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&handle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get resourceType parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_FlushSpecific: Handle %08x\n", handle); + returnCode = TPM_Load32(&resourceType, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_FlushSpecific: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + switch (resourceType) { + case TPM_RT_CONTEXT: + /* 1. If resourceType is TPM_RT_CONTEXT */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_FlushSpecific: Flushing context count %08x\n", handle); + /* a. The handle for a context is not a handle but the "context count" value. The + TPM uses the "context count" value to locate the proper contextList entry and + sets R1 to the contextList entry */ + returnCode = TPM_ContextList_GetEntry(&r1Resource, /* index into + contextList[] */ + tpm_state->tpm_stclear_data.contextList, + handle); + /* 7. Validate that R1 determined by resourceType and handle points to a valid + allocated resource. Return TPM_BAD_PARAMETER on error. */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_FlushSpecific: Error, context count %08x not found\n", + handle); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 8. Invalidate R1 and all internal resources allocated to R1 */ + /* a. Resources include authorization sessions */ + if (returnCode == TPM_SUCCESS) { + /* setting the entry to 0 prevents the session from being reloaded. */ + tpm_state->tpm_stclear_data.contextList[r1Resource] = 0; + } + break; + case TPM_RT_KEY: + /* 2. Else if resourceType is TPM_RT_KEY */ + /* a. Set R1 to the key pointed to by handle */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_FlushSpecific: Flushing key handle %08x\n", handle); + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + handle); + /* 7. Validate that R1 determined by resourceType and handle points to a valid + allocated resource. Return TPM_BAD_PARAMETER on error. */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_FlushSpecific: Error, key handle %08x not found\n", + handle); + returnCode = TPM_BAD_PARAMETER; + } + } + /* b. If R1 -> ownerEvict is TRUE return TPM_KEY_OWNER_CONTROL */ + if (returnCode == TPM_SUCCESS) { + if (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) { + printf("TPM_Process_FlushSpecific: Error, keyHandle specifies owner evict\n"); + returnCode = TPM_KEY_OWNER_CONTROL; + } + } + /* 8. Invalidate R1 and all internal resources allocated to R1 */ + /* a. Resources include authorization sessions */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntry_FlushSpecific(tpm_state, tpm_key_handle_entry); + } + break; + case TPM_RT_AUTH: + /* NOTE replaces deprecated TPM_Terminate_Handle */ + /* 3. Else if resourceType is TPM_RT_AUTH */ + /* a. Set R1 to the authorization session pointed to by handle */ + /* 7. Validate that R1 determined by resourceType and handle points to a valid allocated + resource. Return TPM_BAD_PARAMETER on error. */ + /* 8. Invalidate R1 and all internal resources allocated to R1 */ + /* a. Resources include authorization sessions */ + printf("TPM_Process_FlushSpecific: Flushing authorization session handle %08x\n", + handle); + returnCode = TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, + handle); + break; + case TPM_RT_TRANS: + /* 4. Else if resourceType is TPM_RT_TRANS */ + /* a. Set R1 to the transport session pointed to by handle */ + /* 7. Validate that R1 determined by resourceType and handle points to a valid allocated + resource. Return TPM_BAD_PARAMETER on error. */ + /* 8. Invalidate R1 and all internal resources allocated to R1 */ + /* a. Resources include authorization sessions */ + printf("TPM_Process_FlushSpecific: Flushing transport session handle %08x\n", handle); + returnCode = TPM_TransportSessions_TerminateHandle + (tpm_state->tpm_stclear_data.transSessions, + handle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + break; + case TPM_RT_DAA_TPM: + /* 5. Else if resourceType is TPM_RT_DAA_TPM */ + /* a. Set R1 to the DAA session pointed to by handle */ + /* 7. Validate that R1 determined by resourceType and handle points to a valid allocated + resource. Return TPM_BAD_PARAMETER on error. */ + /* 8. Invalidate R1 and all internal resources allocated to R1 */ + /* a. Resources include authorization sessions */ + printf("TPM_Process_FlushSpecific: Flushing DAA session handle %08x\n", handle); + returnCode = TPM_DaaSessions_TerminateHandle(tpm_state->tpm_stclear_data.daaSessions, + handle); + break; + default: + /* 6. Else return TPM_INVALID_RESOURCE */ + printf("TPM_Process_FlushSpecific: Error, invalid resourceType %08x\n", resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_FlushSpecific: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 21.2 TPM_SaveContext rev 107 + + 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. + + The caller of the function uses the label field to add additional sequencing, anti-replay or other + items to the blob. The information does not need to be confidential but needs to be part of the + blob integrity. +*/ + +TPM_RESULT TPM_Process_SaveContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_HANDLE handle; /* Handle of the resource being saved. */ + TPM_RESOURCE_TYPE resourceType = 0; /* The type of resource that is being saved */ + BYTE label[TPM_CONTEXT_LABEL_SIZE]; /* Label for identification purposes */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_STORE_BUFFER b1_sbuffer; /* serialization of b1 */ + TPM_STCLEAR_DATA *v1StClearData; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* key table entry for the handle */ + TPM_AUTH_SESSION_DATA *tpm_auth_session_data; /* session table entry for the handle */ + TPM_TRANSPORT_INTERNAL *tpm_transport_internal; /* transport table entry for the handle */ + TPM_DAA_SESSION_DATA *tpm_daa_session_data; /* daa session table entry for the handle */ + TPM_NONCE *n1ContextNonce; + TPM_SYMMETRIC_KEY_TOKEN k1ContextKey = NULL; + TPM_STORE_BUFFER r1ContextSensitive; /* serialization of sensitive data clear text */ + TPM_CONTEXT_SENSITIVE c1ContextSensitive; + TPM_CONTEXT_BLOB b1ContextBlob; + TPM_STORE_BUFFER c1_sbuffer; /* serialization of c1ContextSensitive */ + uint32_t contextIndex; /* free index in context list */ + uint32_t space; /* free space in context list */ + TPM_BOOL isZero; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SaveContext: Ordinal Entry\n"); + TPM_Sbuffer_Init(&b1_sbuffer); /* freed @1 */ + TPM_Sbuffer_Init(&r1ContextSensitive); /* freed @2 */ + TPM_ContextBlob_Init(&b1ContextBlob); /* freed @3 */ + TPM_ContextSensitive_Init(&c1ContextSensitive); /* freed @4 */ + TPM_Sbuffer_Init(&c1_sbuffer); /* freed @6 */ + /* + get inputs + */ + /* get handle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&handle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get resourceType */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: handle %08x\n", handle); + returnCode = TPM_Load32(&resourceType, &command, ¶mSize); + } + /* get label */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: resourceType %08x\n", resourceType); + returnCode = TPM_Loadn(label, TPM_CONTEXT_LABEL_SIZE, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_SaveContext: label", label); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SaveContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */ + if (returnCode == TPM_SUCCESS) { + v1StClearData = &(tpm_state->tpm_stclear_data); + } + /* 2. Validate that handle points to resource that matches resourceType, return + TPM_INVALID_RESOURCE on error */ + /* 3. Validate that resourceType is a resource from the following list if not return + TPM_INVALID_RESOURCE */ + if (returnCode == TPM_SUCCESS) { + switch (resourceType) { + case TPM_RT_KEY: + /* a. TPM_RT_KEY */ + printf("TPM_Process_SaveContext: Resource is key handle %08x\n", handle); + /* check if the key handle is valid */ + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + handle); + break; + case TPM_RT_AUTH: + /* b. TPM_RT_AUTH */ + printf("TPM_Process_SaveContext: Resource is session handle %08x\n", handle); + returnCode = TPM_AuthSessions_GetEntry(&tpm_auth_session_data, + v1StClearData->authSessions, + handle); + break; + case TPM_RT_TRANS: + /* c. TPM_RT_TRANS */ + printf("TPM_Process_SaveContext: Resource is transport handle %08x\n", handle); + returnCode = TPM_TransportSessions_GetEntry(&tpm_transport_internal, + v1StClearData->transSessions, + handle); + break; + case TPM_RT_DAA_TPM: + /* d. TPM_RT_DAA_TPM */ + printf("TPM_Process_SaveContext: Resource is DAA handle %08x\n", handle); + returnCode = TPM_DaaSessions_GetEntry(&tpm_daa_session_data, + v1StClearData->daaSessions, + handle); + break; + default: + printf("TPM_Process_SaveContext: Error, invalid resourceType %08x\n", resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + if (returnCode != 0) { + printf("TPM_Process_SaveContext: Error, handle %08x not found\n", handle); + returnCode = TPM_INVALID_RESOURCE; + } + } + /* 4. Locate the correct nonce */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: Locating nonce\n"); + /* a. If resourceType is TPM_RT_KEY */ + if (resourceType == TPM_RT_KEY) { + if (returnCode == TPM_SUCCESS) { + /* i. If TPM_STCLEAR_DATA -> contextNonceKey is NULLS */ + TPM_Nonce_IsZero(&isZero, tpm_state->tpm_stclear_data.contextNonceKey); + if (isZero) { + /* (1) Set TPM_STCLEAR_DATA -> contextNonceKey to the next value from the TPM + RNG */ + returnCode = TPM_Nonce_Generate(tpm_state->tpm_stclear_data.contextNonceKey); + } + } + if (returnCode == TPM_SUCCESS) { + /* ii. Map N1 to TPM_STCLEAR_DATA -> contextNonceKey */ + n1ContextNonce = &(tpm_state->tpm_stclear_data.contextNonceKey); + /* iii. If the key has TPM_KEY_CONTROL_OWNER_EVICT set then return TPM_OWNER_CONTROL + */ + if (tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT) { + printf("TPM_Process_SaveContext: Error, key under owner control\n"); + returnCode = TPM_OWNER_CONTROL; + } + } + } + /* b. Else (resource not TPM_RT_KEY) */ + else { + if (returnCode == TPM_SUCCESS) { + /* i. If V1 -> contextNonceSession is NULLS */ + TPM_Nonce_IsZero(&isZero, v1StClearData->contextNonceSession); + if (isZero) { + /* (1) Set V1 -> contextNonceSession to the next value from the TPM RNG */ + returnCode = TPM_Nonce_Generate(v1StClearData->contextNonceSession); + } + } + /* ii. Map N1 to V1 -> contextNonceSession */ + if (returnCode == TPM_SUCCESS) { + n1ContextNonce = &(v1StClearData->contextNonceSession); + } + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: Building sensitive data\n"); + /* 5. Set K1 to TPM_PERMANENT_DATA -> contextKey */ + k1ContextKey = tpm_state->tpm_permanent_data.contextKey; + /* 6. Create R1 by putting the sensitive part of the resource pointed to by handle into a + structure. The structure is a TPM manufacturer option. The TPM MUST ensure that ALL + sensitive information of the resource is included in R1. */ + /* NOTE Since the contextKey is a symmetric key, the entire resource is put into the + sensitiveData */ + switch (resourceType) { + case TPM_RT_KEY: + returnCode = TPM_KeyHandleEntry_Store(&r1ContextSensitive, tpm_key_handle_entry); + break; + case TPM_RT_AUTH: + returnCode = TPM_AuthSessionData_Store(&r1ContextSensitive, tpm_auth_session_data); + break; + case TPM_RT_TRANS: + returnCode = TPM_TransportInternal_Store(&r1ContextSensitive, tpm_transport_internal); + break; + case TPM_RT_DAA_TPM: + returnCode = TPM_DaaSessionData_Store(&r1ContextSensitive, tpm_daa_session_data); + break; + default: + printf("TPM_Process_SaveContext: Error, invalid resourceType %08x", resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + } + /* 7. Create C1 a TPM_CONTEXT_SENSITIVE structure */ + /* NOTE Done at TPM_ContextSensitive_Init() */ + /* a. C1 forms the inner encrypted wrapper for the blob. All saved context blobs MUST include a + TPM_CONTEXT_SENSITIVE structure and the TPM_CONTEXT_SENSITIVE structure MUST be encrypted. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: Building TPM_CONTEXT_SENSITIVE\n"); + /* b. Set C1 -> contextNonce to N1 */ + TPM_Nonce_Copy(c1ContextSensitive.contextNonce, *n1ContextNonce); + /* c. Set C1 -> internalData to R1 */ + returnCode = TPM_SizedBuffer_SetFromStore(&(c1ContextSensitive.internalData), + &r1ContextSensitive); + } + /* 8. Create B1 a TPM_CONTEXT_BLOB */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveContext: Building TPM_CONTEXT_BLOB\n"); + /* a. Set B1 -> tag to TPM_TAG_CONTEXTBLOB */ + /* NOTE Done at TPM_ContextBlob_Init() */ + /* b. Set B1 -> resourceType to resourceType */ + b1ContextBlob.resourceType = resourceType; + /* c. Set B1 -> handle to handle */ + b1ContextBlob.handle = handle; + /* d. Set B1 -> integrityDigest to NULL */ + /* NOTE Done at TPM_ContextBlob_Init() */ + /* e. Set B1 -> label to label */ + memcpy(b1ContextBlob.label, label, TPM_CONTEXT_LABEL_SIZE); + + } + /* f. Set B1 -> additionalData to information determined by the TPM manufacturer. This data will + help the TPM to reload and reset context. This area MUST NOT hold any data that is sensitive + (symmetric IV are fine, prime factors of an RSA key are not). */ + /* i. For OSAP sessions, and for DSAP sessions attached to keys, the hash of the entity MUST be + included in additionalData */ + /* NOTE Included in TPM_AUTH_SESSION_DATA. This is implementation defined, and the manufacturer + can put everything in sensitive data. */ + /* g. Set B1 -> additionalSize to the size of additionalData */ + /* NOTE Initialized by TPM_ContextBlob_Init() */ + /* h. Set B1 -> sensitiveSize to the size of C1 */ + /* i. Set B1 -> sensitiveData to C1 */ + /* serialize C1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextSensitive_Store(&c1_sbuffer, &c1ContextSensitive); + } + /* Here the clear text goes into TPM_CONTEXT_BLOB->sensitiveData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(b1ContextBlob.sensitiveData), &c1_sbuffer); + } + if (returnCode == TPM_SUCCESS) { + /* 9. If resourceType is TPM_RT_KEY */ + if (resourceType == TPM_RT_KEY) { + /* a. Set B1 -> contextCount to 0 */ + b1ContextBlob.contextCount = 0; + } + /* 10. Else */ + else { + printf("TPM_Process_SaveContext: Processing session context count\n"); + if (returnCode == TPM_SUCCESS) { + /* a. If V1 -> contextCount > 2^32-2 then */ + if (v1StClearData->contextCount > 0xfffffffe) { + /* i. Return with TPM_TOOMANYCONTEXTS */ + printf("TPM_Process_SaveContext: Error, too many contexts\n"); + returnCode = TPM_TOOMANYCONTEXTS; + } + } + /* b. Else */ + if (returnCode == TPM_SUCCESS) { + /* i. Validate that the TPM can still manage the new count value */ + /* (1) If the distance between the oldest saved context and the contextCount is + too large return TPM_CONTEXT_GAP */ + /* Since contextCount is uint32_t, this is not applicable here. From email: Does + the TPM have the ability to keep track of the context delta. It is possible to + keep track of things with just a byte or so internally, if this is done a gap of + greater than 2^16 or so might be too large, hence the context gap message */ + } + /* ii. Find contextIndex such that V1 -> contextList[contextIndex] equals 0. If not + found exit with TPM_NOCONTEXTSPACE */ + if (returnCode == TPM_SUCCESS) { + TPM_ContextList_GetSpace(&space, &contextIndex, v1StClearData->contextList); + if (space == 0) { + printf("TPM_Process_SaveContext: Error, no space in context list\n"); + returnCode = TPM_NOCONTEXTSPACE; + } + } + if (returnCode == TPM_SUCCESS) { + /* iii. Increment V1 -> contextCount by 1 */ + v1StClearData->contextCount++; + /* iv. Set V1-> contextList[contextIndex] to V1 -> contextCount */ + v1StClearData->contextList[contextIndex] = v1StClearData->contextCount; + /* v. Set B1 -> contextCount to V1 -> contextCount */ + b1ContextBlob.contextCount = v1StClearData->contextCount; + } + /* c. The TPM MUST invalidate all information regarding the resource except for + information needed for reloading */ + if (returnCode == TPM_SUCCESS) { + switch (resourceType) { + case TPM_RT_AUTH: + returnCode = TPM_AuthSessions_TerminateHandle(v1StClearData->authSessions, + handle); + break; + case TPM_RT_TRANS: + returnCode = TPM_TransportSessions_TerminateHandle + (v1StClearData->transSessions, + handle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + break; + case TPM_RT_DAA_TPM: + returnCode = TPM_DaaSessions_TerminateHandle(v1StClearData->daaSessions, + handle); + break; + default: + printf("TPM_Process_SaveContext: Error, invalid resourceType %08x", + resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + } + } + } + /* 11. Calculate B1 -> integrityDigest the HMAC of B1 using TPM_PERMANENT_DATA -> tpmProof as + the secret. NOTE It is calculated on the cleartext data */ + if (returnCode == TPM_SUCCESS) { + /* This is a bit circular. It's safe since the TPM_CONTEXT_BLOB is serialized before the + HMAC is generated. The result is put back into the structure. */ + printf("TPM_Process_SaveContext: Digesting TPM_CONTEXT_BLOB\n"); + returnCode = TPM_HMAC_GenerateStructure + (b1ContextBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &b1ContextBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store); /* store function */ + } + /* 12. Create E1 by encrypting C1 using K1 as the key */ + /* a. Set B1 -> sensitiveSize to the size of E1 */ + /* b. Set B1 -> sensitiveData to E1 */ + if (returnCode == TPM_SUCCESS) { + /* The cleartext went into sensitiveData for the integrityDigest calculation. Free it now, + before the encrypted data is stored there. */ + TPM_SizedBuffer_Delete(&(b1ContextBlob.sensitiveData)); + returnCode = TPM_SymmetricKeyData_EncryptSbuffer(&(b1ContextBlob.sensitiveData), + &c1_sbuffer, + k1ContextKey); + } + /* 13. Set contextSize to the size of B1 */ + /* 14. Return B1 in contextBlob */ + /* Since the redundant size parameter must be returned, the TPM_CONTEXT_BLOB is serialized + first. Later, rather than the usual _Store to the response, the already serialized buffer is + stored. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Store(&b1_sbuffer, &b1ContextBlob); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SaveContext: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return contextSize and contextBlob */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &b1_sbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&b1_sbuffer); /* @1 */ + TPM_Sbuffer_Delete(&r1ContextSensitive); /* @2 */ + TPM_ContextBlob_Delete(&b1ContextBlob); /* @3 */ + TPM_ContextSensitive_Delete(&c1ContextSensitive); /* @4 */ + TPM_Sbuffer_Delete(&c1_sbuffer); /* @6 */ + return rcf; +} + +/* 21.3 TPM_LoadContext rev 107 + + TPM_LoadContext loads into the TPM a previously saved context. The command returns the handle. +*/ + +TPM_RESULT TPM_Process_LoadContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_HANDLE entityHandle; /* The handle the TPM MUST use to locate the entity ties + to the OSAP/DSAP session */ + TPM_BOOL keepHandle; /* Indication if the handle MUST be preserved */ + uint32_t contextSize; /* The size of the following context blob */ + TPM_CONTEXT_BLOB b1ContextBlob; /* The context blob */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL key_added = FALSE; /* key has been added to handle list */ + TPM_BOOL auth_session_added = FALSE; + TPM_BOOL trans_session_added = FALSE; + TPM_BOOL daa_session_added = FALSE; + TPM_STCLEAR_DATA *v1StClearData = NULL; + unsigned char *m1Decrypt; /* decrypted sensitive data */ + uint32_t m1_length; /* actual data in m1 */ + unsigned char *stream; + uint32_t stream_size; + TPM_CONTEXT_SENSITIVE c1ContextSensitive; + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; + TPM_AUTH_SESSION_DATA tpm_auth_session_data; /* loaded authorization session */ + TPM_TRANSPORT_INTERNAL tpm_transport_internal; /* loaded transport session */ + TPM_DAA_SESSION_DATA tpm_daa_session_data; /* loaded daa session */ + TPM_DIGEST entityDigest; /* digest of the entity corresponding to + entityHandle */ + uint32_t contextIndex; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_LoadContext: Ordinal Entry\n"); + TPM_ContextBlob_Init(&b1ContextBlob); /* freed @1 */ + TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* no free */ + m1Decrypt = NULL; /* freed @2 */ + TPM_ContextSensitive_Init(&c1ContextSensitive); /* freed @3 */ + TPM_AuthSessionData_Init(&tpm_auth_session_data); /* freed @4 */ + TPM_TransportInternal_Init(&tpm_transport_internal); /* freed @5 */ + TPM_DaaSessionData_Init(&tpm_daa_session_data); /* freed @6 */ + /* + get inputs + */ + /* get parameter entityHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&entityHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get keepHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: entityHandle %08x\n", entityHandle); + returnCode = TPM_LoadBool(&keepHandle, &command, ¶mSize); + } + /* get contextSize parameter (redundant, not used) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: keepHandle %02x\n", keepHandle); + returnCode = TPM_Load32(&contextSize, &command, ¶mSize); + } + /* get contextBlob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Load(&b1ContextBlob, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Map contextBlob to B1, a TPM_CONTEXT_BLOB structure */ + /* NOTE Done by TPM_ContextBlob_Load() */ + if (returnCode == TPM_SUCCESS) { + /* 2. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */ + v1StClearData = &(tpm_state->tpm_stclear_data); + /* 3. Create M1 by decrypting B1 -> sensitiveData using TPM_PERMANENT_DATA -> contextKey */ + printf("TPM_Process_LoadContext: Decrypting sensitiveData\n"); + returnCode = TPM_SymmetricKeyData_Decrypt(&m1Decrypt, /* decrypted data */ + &m1_length, /* length decrypted data */ + b1ContextBlob.sensitiveData.buffer, /* encrypt */ + b1ContextBlob.sensitiveData.size, + tpm_state->tpm_permanent_data.contextKey); + } + /* 4. Create C1 and R1 by splitting M1 into a TPM_CONTEXT_SENSITIVE structure and internal + resource data */ + /* NOTE R1 is manufacturer specific data that might be part of the blob. This implementation + does not use R1 */ + if (returnCode == TPM_SUCCESS) { + stream = m1Decrypt; + stream_size = m1_length; + returnCode = TPM_ContextSensitive_Load(&c1ContextSensitive, &stream, &stream_size); + } + /* Parse the TPM_CONTEXT_SENSITIVE -> internalData depending on the resource type */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Parsing TPM_CONTEXT_SENSITIVE -> internalData\n"); + stream = c1ContextSensitive.internalData.buffer; + stream_size = c1ContextSensitive.internalData.size; + switch (b1ContextBlob.resourceType) { + case TPM_RT_KEY: + printf("TPM_Process_LoadContext: Loading TPM_KEY_HANDLE_ENTRY\n"); + returnCode = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, &stream, &stream_size); + break; + case TPM_RT_AUTH: + printf("TPM_Process_LoadContext: Loading TPM_AUTH_SESSION_DATA\n"); + returnCode = TPM_AuthSessionData_Load(&tpm_auth_session_data, &stream, &stream_size); + printf("TPM_Process_LoadContext: protocolID %02x entityTypeByte %02x\n", + tpm_auth_session_data.protocolID, tpm_auth_session_data.entityTypeByte); + break; + case TPM_RT_TRANS: + printf("TPM_Process_LoadContext: Loading TPM_TRANSPORT_INTERNAL\n"); + returnCode = TPM_TransportInternal_Load(&tpm_transport_internal, + &stream, &stream_size); + break; + case TPM_RT_DAA_TPM: + printf("TPM_Process_LoadContext: Loading TPM_DAA_SESSION_DATA\n"); + returnCode = TPM_DaaSessionData_Load(&tpm_daa_session_data, &stream, &stream_size); + printf("TPM_Process_LoadContext: stage %u\n", + tpm_daa_session_data.DAA_session.DAA_stage); + break; + default: + printf("TPM_Process_LoadContext: Error, invalid resourceType %08x", + b1ContextBlob.resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + } + /* 5. Check contextNonce */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Checking contextNonce\n"); + /* a. If B1 -> resourceType is NOT TPM_RT_KEY */ + if (b1ContextBlob.resourceType != TPM_RT_KEY) { + /* i. If C1 -> contextNonce does not equal V1 -> contextNonceSession return + TPM_BADCONTEXT */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Compare(v1StClearData->contextNonceSession, + c1ContextSensitive.contextNonce); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Error comparing non-key contextNonce\n"); + returnCode = TPM_BADCONTEXT; + } + } + /* ii. Validate that the resource pointed to by the context is loaded (i.e. for OSAP the + key referenced is loaded and DSAP connected to the key) return TPM_RESOURCEMISSING */ + /* (1) For OSAP sessions and for DSAP sessions attached to keys, the TPM MUST validate + that the hash of the entity matches the entity held by the TPM */ + /* (2) For OSAP and DSAP sessions referring to a key, verify that entityHandle + identifies the key linked to this OSAP/DSAP session, if not return TPM_BAD_HANDLE. */ + if ((returnCode == TPM_SUCCESS) && (b1ContextBlob.resourceType == TPM_RT_AUTH)) { + if ((tpm_auth_session_data.protocolID == TPM_PID_OSAP) || + (tpm_auth_session_data.protocolID == TPM_PID_DSAP)) { + /* check that the entity is loaded, and get the entity's digest */ + switch (tpm_auth_session_data.entityTypeByte) { + case TPM_ET_KEYHANDLE: + returnCode = TPM_LoadContext_CheckKeyLoaded(tpm_state, + entityHandle, + entityDigest); + break; + case TPM_ET_OWNER: + returnCode = TPM_LoadContext_CheckOwnerLoaded(tpm_state, + entityDigest); + break; + case TPM_ET_SRK: + returnCode = TPM_LoadContext_CheckSrkLoaded(tpm_state, + entityDigest); + break; + case TPM_ET_COUNTER: + returnCode = TPM_LoadContext_CheckCounterLoaded(tpm_state, + entityHandle, + entityDigest); + break; + case TPM_ET_NV: + returnCode = TPM_LoadContext_CheckNvLoaded(tpm_state, + entityHandle, + entityDigest); + break; + default: + printf("TPM_Process_LoadContext: Error, invalid session entityType %02x\n", + tpm_auth_session_data.entityTypeByte); + returnCode = TPM_WRONG_ENTITYTYPE; + break; + } + if (returnCode == TPM_SUCCESS) { + returnCode= TPM_Digest_Compare(entityDigest, + tpm_auth_session_data.entityDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Error, " + "OSAP or DSAP entityDigest mismatch\n"); + returnCode = TPM_RESOURCEMISSING; + } + } + } + } + } + /* b. Else (TPM_RT_KEY) */ + else { + /* i. If C1 -> internalData -> parentPCRStatus is FALSE and C1 -> internalData -> + isVolatile is FALSE */ + /* NOTE parentPCRStatus and keyFlags are not security sensitive data, could be in + additionalData */ + /* (1) Ignore C1 -> contextNonce */ + if (returnCode == TPM_SUCCESS) { + if (tpm_key_handle_entry.parentPCRStatus || + (tpm_key_handle_entry.key->keyFlags & TPM_ISVOLATILE)) { + /* ii. else */ + /* (1) If C1 -> contextNonce does not equal TPM_STCLEAR_DATA -> contextNonceKey + return TPM_BADCONTEXT */ + returnCode = TPM_Nonce_Compare(v1StClearData->contextNonceKey, + c1ContextSensitive.contextNonce); + if (returnCode != 0) { + printf("TPM_Process_LoadContext: Error comparing contextNonceKey\n"); + returnCode = TPM_BADCONTEXT; + } + } + } + } + } + /* 6. Validate the structure */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Checking integrityDigest\n"); + /* a. Set H1 to B1 -> integrityDigest */ + /* NOTE Done by TPM_HMAC_CheckStructure() */ + /* b. Set B1 -> integrityDigest to all zeros */ + /* NOTE Done by TPM_HMAC_CheckStructure() */ + /* c. Copy M1 to B1 -> sensitiveData (integrityDigest HMAC uses cleartext) */ + returnCode = TPM_SizedBuffer_Set(&(b1ContextBlob.sensitiveData), m1_length, m1Decrypt); + } + /* d. Create H2 the HMAC of B1 using TPM_PERMANENT_DATA -> tpmProof as the HMAC key */ + /* e. If H2 does not equal H1 return TPM_BADCONTEXT */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &b1ContextBlob, /* structure */ + b1ContextBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store, /* store function */ + TPM_BADCONTEXT); /* error code */ + } + /* 9. If B1 -> resourceType is NOT TPM_RT_KEY */ + if ((returnCode == TPM_SUCCESS) && (b1ContextBlob.resourceType != TPM_RT_KEY)) { + printf("TPM_Process_LoadContext: Checking contextCount\n"); + /* a. Find contextIndex such that V1 -> contextList[contextIndex] equals B1 -> + TPM_CONTEXT_BLOB -> contextCount */ + /* b. If not found then return TPM_BADCONTEXT */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextList_GetEntry(&contextIndex, + v1StClearData->contextList, + b1ContextBlob.contextCount); + } + /* c. Set V1 -> contextList[contextIndex] to 0 */ + if (returnCode == TPM_SUCCESS) { + v1StClearData->contextList[contextIndex] = 0; + } + } + /* 10. Process B1 to return the resource back into TPM use */ + /* restore the entity, try to keep the handle as 'handle' */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadContext: Adding entry to table\n"); + switch (b1ContextBlob.resourceType) { + case TPM_RT_KEY: + returnCode = TPM_KeyHandleEntries_AddEntry(&(b1ContextBlob.handle), + keepHandle, + tpm_state->tpm_key_handle_entries, + &tpm_key_handle_entry); + key_added = TRUE; + break; + case TPM_RT_AUTH: + returnCode = TPM_AuthSessions_AddEntry(&(b1ContextBlob.handle), /* input/output */ + keepHandle, + v1StClearData->authSessions, + &tpm_auth_session_data); + auth_session_added = TRUE; + break; + case TPM_RT_TRANS: + returnCode = TPM_TransportSessions_AddEntry(&(b1ContextBlob.handle), /* input/output */ + keepHandle, + v1StClearData->transSessions, + &tpm_transport_internal); + trans_session_added = TRUE; + break; + case TPM_RT_DAA_TPM: + returnCode = TPM_DaaSessions_AddEntry(&(b1ContextBlob.handle), /* input/output */ + keepHandle, + v1StClearData->daaSessions, + &tpm_daa_session_data); + daa_session_added = TRUE; + break; + default: + printf("TPM_Process_LoadContext: Error, invalid resourceType %08x\n", + b1ContextBlob.resourceType); + returnCode = TPM_INVALID_RESOURCE; + break; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadContext: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* return handle */ + returnCode = TPM_Sbuffer_Append32(response, b1ContextBlob.handle); + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + /* if there was a failure, roll back */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(tpm_key_handle_entry.key); /* free on error */ + free(tpm_key_handle_entry.key); /* free on error */ + if (key_added) { + /* if there was a failure and inKey was stored in the handle list, free the handle. + Ignore errors, since only one error code can be returned. */ + TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, + b1ContextBlob.handle); + } + if (auth_session_added) { + TPM_AuthSessions_TerminateHandle(v1StClearData->authSessions, b1ContextBlob.handle); + } + if (trans_session_added) { + TPM_TransportSessions_TerminateHandle(v1StClearData->transSessions, + b1ContextBlob.handle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + if (daa_session_added) { + TPM_DaaSessions_TerminateHandle(v1StClearData->daaSessions, b1ContextBlob.handle); + } + } + TPM_ContextBlob_Delete(&b1ContextBlob); /* @1 */ + free(m1Decrypt); /* @2 */ + TPM_ContextSensitive_Delete(&c1ContextSensitive); /* @3 */ + TPM_AuthSessionData_Delete(&tpm_auth_session_data); /* @4 */ + TPM_TransportInternal_Delete(&tpm_transport_internal); /* @5 */ + TPM_DaaSessionData_Delete(&tpm_daa_session_data); /* @6 */ + return rcf; +} + +/* TPM_LoadContext_CheckKeyLoaded() validates that the key associated with a loading authorization + context is loaded. + + It returns the key pubDataDigest for comparison with the digest of the loading context. +*/ + +static TPM_RESULT TPM_LoadContext_CheckKeyLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest) +{ + TPM_RESULT rc = 0; + TPM_KEY_HANDLE_ENTRY *key_handle_entry; + + printf("TPM_LoadContext_CheckKeyLoaded: handle %08x\n", entityHandle); + /* get the key associated with entityHandle */ + /* special case, SRK is not in the key handle list */ + if (entityHandle == TPM_KH_SRK) { + if (tpm_state->tpm_permanent_data.ownerInstalled) { + TPM_Digest_Copy(entityDigest, + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest); + } + else { + printf("TPM_LoadContext_CheckKeyLoaded: Error, ownerInstalled is FALSE\n"); + rc = TPM_NOSRK; + } + } + /* normal case, key is in the key handle list */ + else { + rc = TPM_KeyHandleEntries_GetEntry(&key_handle_entry, + tpm_state->tpm_key_handle_entries, + entityHandle); + if (rc == 0) { + TPM_Digest_Copy(entityDigest, key_handle_entry->key->tpm_store_asymkey->pubDataDigest); + } + else { + printf("TPM_LoadContext_CheckKeyLoaded: Error, key handle %08x not found\n", + entityHandle); + rc = TPM_BAD_HANDLE; + } + } + return rc; +} + +/* TPM_LoadContext_CheckKeyLoadedByDigest() validates that the key associated with a loading + authorization context is loaded. + + It compares the key the pubDataDigest to the digest of the loading context. +*/ + +static TPM_RESULT TPM_LoadContext_CheckKeyLoadedByDigest(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest) +{ + TPM_RESULT rc = TPM_RETRY; /* any non-zero value will do */ + size_t start; + size_t current; + TPM_KEY_HANDLE_ENTRY *key_handle_entry; + + printf("TPM_LoadContext_CheckKeyLoadedByDigest:\n"); + /* get the key associated with entityDigest */ + start = 0; + /* iterate through all keys in the key handle table */ + while ((rc != 0) && /* a match sets rc to 0, terminates loop */ + /* returns TPM_RETRY when at the end of the table, terminates loop */ + (TPM_KeyHandleEntries_GetNextEntry(&key_handle_entry, + ¤t, + tpm_state->tpm_key_handle_entries, + start)) == 0) { + + + start = current + 1; + rc = TPM_Digest_Compare(entityDigest, + key_handle_entry->key->tpm_store_asymkey->pubDataDigest); + } + /* if that failed, check the SRK */ + if (rc != 0) { + if (tpm_state->tpm_permanent_data.ownerInstalled) { + rc = TPM_Digest_Compare + (entityDigest, + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest); + } + } + if (rc != 0) { + printf("TPM_LoadContext_CheckKeyLoadedByDigest: " + "Error, OSAP or DSAP entityDigest mismatch\n"); + rc = TPM_RESOURCEMISSING; + } + return rc; +} + +/* TPM_LoadContext_CheckOwnerLoaded() validates that the owner is loaded. + + It returns the owner authorization for comparison with the digest of the loading context. +*/ + +static TPM_RESULT TPM_LoadContext_CheckOwnerLoaded(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest) +{ + TPM_RESULT rc = 0; + + printf("TPM_LoadContext_CheckOwnerLoaded:\n"); + /* verify that an owner is installed */ + if (rc == 0) { + if (!tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_LoadContext_CheckOwnerLoaded: Error, no owner\n"); + rc = TPM_RESOURCEMISSING; + } + } + if (rc == 0) { + TPM_Digest_Copy(entityDigest, tpm_state->tpm_permanent_data.ownerAuth); + } + return rc; +} + +/* TPM_LoadContext_CheckSrkLoaded() validates that the SRK is loaded. + + It returns the SRK pubDataDigest for comparison with the digest of the loading context. +*/ + +static TPM_RESULT TPM_LoadContext_CheckSrkLoaded(tpm_state_t *tpm_state, + TPM_DIGEST entityDigest) +{ + TPM_RESULT rc = 0; + + printf("TPM_LoadContext_CheckSrkLoaded:\n"); + /* verify that an owner is installed */ + if (rc == 0) { + if (!tpm_state->tpm_permanent_data.ownerInstalled) { + printf("TPM_LoadContext_CheckSrkLoaded: Error, no SRK\n"); + rc = TPM_RESOURCEMISSING; + } + } + if (rc == 0) { + TPM_Digest_Copy(entityDigest, + tpm_state->tpm_permanent_data.srk.tpm_store_asymkey->pubDataDigest); + } + return rc; +} + +/* TPM_LoadContext_CheckCounterLoaded() validates that the counter associated with a loading + authorization context is loaded. + + It returns the counter authorization for comparison with the digest of the loading context. +*/ + +static TPM_RESULT TPM_LoadContext_CheckCounterLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest) +{ + TPM_RESULT rc = 0; + TPM_COUNTER_VALUE *counterValue; /* associated with entityHandle */ + + printf("TPM_LoadContext_CheckCounterLoaded: handle %08x\n", entityHandle); + if (rc == 0) { + rc = TPM_Counters_GetCounterValue(&counterValue, + tpm_state->tpm_permanent_data.monotonicCounter, + entityHandle); + if (rc != 0) { + printf("TPM_LoadContext_CheckCounterLoaded: Error, no counter\n"); + rc = TPM_RESOURCEMISSING; + } + } + if (rc == 0) { + TPM_Digest_Copy(entityDigest, counterValue->digest); + } + return rc; +} + +/* TPM_LoadContext_CheckNvLoaded() validates that the NV space associated with a loading + authorization context exists. +*/ + +static TPM_RESULT TPM_LoadContext_CheckNvLoaded(tpm_state_t *tpm_state, + TPM_HANDLE entityHandle, + TPM_DIGEST entityDigest) +{ + + TPM_RESULT rc = 0; + TPM_NV_DATA_SENSITIVE *tpm_nv_data_sensitive; /* associated with entityValue */ + + printf(" TPM_LoadContext_CheckNvLoaded: handle %08x\n", entityHandle); + if (rc == 0) { + rc = TPM_NVIndexEntries_GetEntry(&tpm_nv_data_sensitive, + &(tpm_state->tpm_nv_index_entries), + entityHandle); + if (rc != 0) { + printf("TPM_LoadContext_CheckNvLoaded: Error, no NV at index %08x\n", entityHandle); + rc = TPM_RESOURCEMISSING; + } + } + if (rc == 0) { + TPM_Digest_Copy(entityDigest, tpm_nv_data_sensitive->digest); + } + return rc; +} + +/* 21.1 TPM_KeyControlOwner rev 116 + + This command controls some attributes of keys that are stored within the TPM key cache. + + 1. Set an internal bit within the key cache that controls some attribute of a loaded key. + + 2.When a key is set to ownerEvict, the key handle value remains the same as long as the key + remains ownerEvict. The key handle value persists through TPM_Startup. + + OwnerEvict: If this bit is set to true, this key remains in the TPM non-volatile storage + through all TPM_Startup events. The only way to evict this key is for the TPM Owner to + execute this command again, setting the owner control bit to false and then executing + TPM_FlushSpecific. + + The key handle does not reference an authorized entity and is not validated. + + The check for two remaining key slots ensures that users can load the two keys required to + execute many commands. Since only the owner can flush owner evict keys, non-owner commands + could be blocked if this test was not performed. +*/ + +TPM_RESULT TPM_Process_KeyControlOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The handle of a loaded key. */ + TPM_PUBKEY pubKey; /* The public key associated with the loaded key */ + TPM_KEY_CONTROL bitName = 0; /* The name of the bit to be modified */ + TPM_BOOL bitValue = FALSE; /* The value to set the bit to */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for owner + authentication. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA ownerAuth; /* HMAC authorization: key ownerAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* entry for keyHandle */ + TPM_BOOL isSpace; + TPM_BOOL oldOwnerEvict; /* original owner evict state */ + uint16_t ownerEvictCount; /* current number of owner evict keys */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_KeyControlOwner: Ordinal Entry\n"); + TPM_Pubkey_Init(&pubKey); /* freed @1 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get pubKey parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_KeyControlOwner: keyHandle %08x\n", keyHandle); + returnCode = TPM_Pubkey_Load(&pubKey, &command, ¶mSize); + } + /* get bitName parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&bitName, &command, ¶mSize); + } + /* get bitValue parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load8(&bitValue, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_KeyControlOwner: bitName %08x bitValue %02x\n", bitName, bitValue); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + ownerAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_KeyControlOwner: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. Validate the AuthData using the owner authentication value, on error return TPM_AUTHFAIL + */ + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_OWNER, + ordinal, + NULL, + &(tpm_state->tpm_permanent_data.ownerAuth), /* OIAP */ + tpm_state->tpm_permanent_data.ownerAuth); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* owner HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + ownerAuth); /* Authorization digest for input */ + } + /* 2. Validate that keyHandle refers to a loaded key, return TPM_INVALID_KEYHANDLE on error. */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + keyHandle); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_KeyControlOwner: Error, key handle not loaded\n"); + returnCode = TPM_INVALID_KEYHANDLE; + } + } + /* If the keyUsage field of the key indicated by keyHandle does not have the value + TPM_KEY_SIGNING, TPM_KEY_STORAGE, TPM_KEY_IDENTITY, TPM_KEY_BIND, or TPM_KEY_LEGACY, the TPM + must return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if ((tpm_key_handle_entry->key->keyUsage != TPM_KEY_SIGNING) && + (tpm_key_handle_entry->key->keyUsage != TPM_KEY_STORAGE) && + (tpm_key_handle_entry->key->keyUsage != TPM_KEY_IDENTITY) && + (tpm_key_handle_entry->key->keyUsage != TPM_KEY_BIND) && + (tpm_key_handle_entry->key->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_KeyControlOwner: Error, invalid key keyUsage %04hx\n", + tpm_key_handle_entry->key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Validate that pubKey matches the key held by the TPM pointed to by keyHandle, return + TPM_BAD_PARAMETER on mismatch */ + /* a. This check is added so that virtualization of the keyHandle does not result in attacks, as + the keyHandle is not associated with an authorization value */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_ComparePubkey(tpm_key_handle_entry->key, &pubKey); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_KeyControlOwner: Error comparing pubKey\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 4. Validate that bitName is valid, return TPM_BAD_MODE on error. NOTE Valid means a legal + TPM_KEY_CONTROL value */ + if (returnCode == TPM_SUCCESS) { + switch(bitName) { + /* 5. If bitName == TPM_KEY_CONTROL_OWNER_EVICT */ + case TPM_KEY_CONTROL_OWNER_EVICT: + /* save the old value to determine if NVRAM update is necessary */ + oldOwnerEvict = tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT; + /* a. If bitValue == TRUE */ + if (bitValue) { + printf("TPM_Process_KeyControlOwner: setting key owner evict\n"); + if (!oldOwnerEvict) { /* if the key is not owner evict */ + /* i. Verify that after this operation at least two key slots will be present + within the TPM that can store any type of key both of which do NOT have the + OwnerEvict bit set, on error return TPM_NOSPACE */ + if (returnCode == TPM_SUCCESS) { + TPM_KeyHandleEntries_IsEvictSpace(&isSpace, + tpm_state->tpm_key_handle_entries, + 2); /* minSpace */ + if (!isSpace) { + printf("TPM_Process_KeyControlOwner: Error, " + "Need 2 non-evict slots\n"); + returnCode = TPM_NOSPACE; + } + } + /* ii. Verify that for this key handle, parentPCRStatus is FALSE and isVolatile + is FALSE. Return TPM_BAD_PARAMETER on error. */ + if (returnCode == TPM_SUCCESS) { + if (tpm_key_handle_entry->parentPCRStatus || + tpm_key_handle_entry->key->keyFlags & TPM_ISVOLATILE) { + printf("TPM_Process_KeyControlOwner: Error, " + "parentPCRStatus or Volatile\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* check the current number of occupied owner evict key slots */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_OwnerEvictGetCount + (&ownerEvictCount, + tpm_state->tpm_key_handle_entries); + } + /* check that the number of owner evict key slots will not be exceeded */ + if (returnCode == TPM_SUCCESS) { + if (ownerEvictCount == TPM_OWNER_EVICT_KEY_HANDLES) { + printf("TPM_Process_KeyControlOwner: Error, " + "no evict space, only %u evict slots\n", + TPM_OWNER_EVICT_KEY_HANDLES); + returnCode = TPM_NOSPACE; + } + } + /* iii. Set ownerEvict within the internal key storage structure to TRUE. */ + if (returnCode == TPM_SUCCESS) { + tpm_key_handle_entry->keyControl |= TPM_KEY_CONTROL_OWNER_EVICT; + } + /* if the old value was FALSE, write the entry to NVRAM */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } + } + else { /* if the key is already owner evict, nothing to do */ + printf("TPM_Process_KeyControlOwner: key is already owner evict\n"); + } + } + /* b. Else if bitValue == FALSE */ + else { + if (oldOwnerEvict) { /* if the key is currently owner evict */ + printf("TPM_Process_KeyControlOwner: setting key not owner evict\n"); + /* i. Set ownerEvict within the internal key storage structure to FALSE. */ + if (returnCode == TPM_SUCCESS) { + tpm_key_handle_entry->keyControl &= ~TPM_KEY_CONTROL_OWNER_EVICT; + } + /* if the old value was TRUE, delete the entry from NVRAM */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PermanentAll_NVStore(tpm_state, + TRUE, /* write NV */ + 0); /* no roll back */ + } + } + else { /* if the key is already not owner evict, nothing to do */ + printf("TPM_Process_KeyControlOwner: key is already not owner evict\n"); + } + } + break; + default: + printf("TPM_Process_KeyControlOwner: Invalid bitName %08x\n", bitName); + returnCode = TPM_BAD_MODE; + break; + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_KeyControlOwner: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_Pubkey_Delete(&pubKey); /* @1 */ + return rcf; +} + +/* 27.2 Context management + + The 1.1 context commands were written for specific resource types. The 1.2 commands are generic + for all resource types. So the Savexxx commands are replaced by TPM_SaveContext and the LoadXXX + commands by TPM_LoadContext. +*/ + +/* 27.2.1 TPM_SaveKeyContext rev 87 + + 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_Process_SaveKeyContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The key which will be kept outside the TPM */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry; /* key table entry for the key handle */ + TPM_BOOL isZero; /* contextNonceKey not set yet */ + TPM_CONTEXT_SENSITIVE contextSensitive; + TPM_STORE_BUFFER contextSensitive_sbuffer; /* serialization of contextSensitive */ + TPM_CONTEXT_BLOB contextBlob; + TPM_STORE_BUFFER contextBlob_sbuffer; /* serialization of contextBlob */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SaveKeyContext: Ordinal Entry\n"); + TPM_ContextSensitive_Init(&contextSensitive); /* freed @1 */ + TPM_Sbuffer_Init(&contextSensitive_sbuffer); /* freed @2 */ + TPM_ContextBlob_Init(&contextBlob); /* freed @3 */ + TPM_Sbuffer_Init(&contextBlob_sbuffer); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SaveKeyContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. This command allows saving a loaded key outside the TPM. After creation of the + KeyContextBlob, the TPM automatically releases the internal memory used by that key. The + format of the key context blob is specific to a TPM. + + 2. A TPM protected capability belonging to the TPM that created a key context blob MUST be + the only entity that can interpret the contents of that blob. If a cryptographic technique is + used for this purpose, the level of security provided by that technique SHALL be at least as + secure as a 2048 bit RSA algorithm. Any secrets (such as keys) used in such a cryptographic + technique MUST be generated using the TPM's random number generator. Any symmetric key MUST + be used within the power-on session during which it was created, only. + + 3. A key context blob SHALL enable verification of the integrity of the contents of the blob + by a TPM protected capability. + + 4. A key context blob SHALL enable verification of the session validity of the contents of + the blob by a TPM protected capability. The method SHALL ensure that all key context blobs + are rendered invalid if power to the TPM is interrupted. + */ + /* check if the key handle is valid */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveKeyContext: Handle %08x\n", keyHandle); + returnCode = TPM_KeyHandleEntries_GetEntry(&tpm_key_handle_entry, + tpm_state->tpm_key_handle_entries, + keyHandle); + } + /* use the contextNonceKey to invalidate a blob at power up */ + if (returnCode == TPM_SUCCESS) { + /* If TPM_STCLEAR_DATA -> contextNonceKey is NULLS */ + TPM_Nonce_IsZero(&isZero, tpm_state->tpm_stclear_data.contextNonceKey); + if (isZero) { + /* Set TPM_STCLEAR_DATA -> contextNonceKey to the next value from the TPM RNG */ + returnCode = TPM_Nonce_Generate(tpm_state->tpm_stclear_data.contextNonceKey); + } + } + /* Create internalData by putting the sensitive part of the resource pointed to by handle into a + structure. The structure is a TPM manufacturer option. The TPM MUST ensure that ALL sensitive + information of the resource is included in internalData. For a key, the sensitive part is + the TPM_STORE_ASYMKEY */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveKeyContext: Building TPM_CONTEXT_SENSITIVE\n"); + returnCode = TPM_SizedBuffer_SetStructure(&(contextSensitive.internalData), + tpm_key_handle_entry, + (TPM_STORE_FUNCTION_T)TPM_KeyHandleEntry_Store); + } + if (returnCode == TPM_SUCCESS) { + /* TPM_CONTEXT_SENSITIVE -> contextNonce */ + TPM_Nonce_Copy(contextSensitive.contextNonce, tpm_state->tpm_stclear_data.contextNonceKey); + /* TPM_CONTEXT_BLOB -> resourceType, handle, integrityDigest */ + printf("TPM_Process_SaveKeyContext: Building TPM_CONTEXT_BLOB\n"); + contextBlob.resourceType = TPM_RT_KEY; + contextBlob.handle = keyHandle; + contextBlob.contextCount = 0; + } + /* TPM_CONTEXT_BLOB -> sensitiveData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextSensitive_Store(&contextSensitive_sbuffer, &contextSensitive); + } + /* Here the clear text goes into TPM_CONTEXT_BLOB->sensitiveData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(contextBlob.sensitiveData), + &contextSensitive_sbuffer); + } + /* Calculate TPM_CONTEXT_BLOB -> integrityDigest, the HMAC of TPM_CONTEXT_BLOB using + TPM_PERMANENT_DATA -> tpmProof as the secret */ + if (returnCode == TPM_SUCCESS) { + /* This is a bit circular. It's safe since the TPM_CONTEXT_BLOB is serialized before the + HMAC is generated. The result is put back into the structure. */ + printf("TPM_Process_SaveKeyContext: Digesting TPM_CONTEXT_BLOB\n"); + returnCode = TPM_HMAC_GenerateStructure + (contextBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &contextBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store); /* store function */ + } + /* encrypt TPM_CONTEXT_SENSITIVE using as TPM_PERMANENT_DATA -> contextKey the key. Store the + result in TPM_CONTEXT_BLOB -> sensitiveData */ + if (returnCode == TPM_SUCCESS) { + /* The cleartext went into sensitiveData for the integrityDigest calculation. Free it now, + before the encrypted data is stored there. */ + TPM_SizedBuffer_Delete(&(contextBlob.sensitiveData)); + printf("TPM_Process_SaveKeyContext: Encrypting TPM_CONTEXT_SENSITIVE\n"); + returnCode = + TPM_SymmetricKeyData_EncryptSbuffer(&(contextBlob.sensitiveData), + &contextSensitive_sbuffer, + tpm_state->tpm_permanent_data.contextKey); + } + /* serialize TPM_CONTEXT_BLOB */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Store(&contextBlob_sbuffer, &contextBlob); + } + /* invalidate the key handle and delete the key */ + if (returnCode == TPM_SUCCESS) { + /* free the key resources, free the key itself, and remove entry from the key handle entries + list */ + TPM_KeyHandleEntry_Delete(tpm_key_handle_entry); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SaveKeyContext: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return keyContextSize and keyContextBlob */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &contextBlob_sbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_ContextSensitive_Delete(&contextSensitive); /* @1 */ + TPM_Sbuffer_Delete(&contextSensitive_sbuffer); /* @2 */ + TPM_ContextBlob_Delete(&contextBlob); /* @3 */ + TPM_Sbuffer_Delete(&contextBlob_sbuffer); /* @4 */ + return rcf; +} + +/* 27.2.2 TPM_LoadKeyContext rev 87 + + 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_Process_LoadKeyContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + uint32_t keyContextSize; /* The size of the following key context blob */ + TPM_CONTEXT_BLOB keyContextBlob; /* The key context blob */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + unsigned char *stream; + uint32_t stream_size; + unsigned char *contextSensitiveBuffer; /* decrypted sensitive data */ + uint32_t contextSensitiveBuffer_length; /* actual data in contextSensitiveBuffer */ + TPM_CONTEXT_SENSITIVE contextSensitive; + TPM_KEY_HANDLE_ENTRY *used_key_handle_entry; + TPM_KEY_HANDLE_ENTRY tpm_key_handle_entry; + TPM_RESULT getRc; /* is the handle value free */ + TPM_BOOL isSpace; + uint32_t index; /* free space index */ + TPM_BOOL key_added = FALSE; /* key has been added to handle list */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY_HANDLE keyHandle; /* The handle assigned to the key after it has been + successfully loaded. */ + + printf("TPM_Process_LoadKeyContext: Ordinal Entry\n"); + TPM_ContextBlob_Init(&keyContextBlob); /* freed @1 */ + contextSensitiveBuffer = NULL; /* freed @2 */ + TPM_ContextSensitive_Init(&contextSensitive); /* freed @3 */ + TPM_KeyHandleEntry_Init(&tpm_key_handle_entry); /* no free */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get keyContextSize parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyContextSize, &command, ¶mSize); + } + /* get keyContextBlob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Load(&keyContextBlob, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadKeyContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. This command allows loading a key context blob into the TPM previously retrieved by a + TPM_SaveKeyContext call. After successful completion the handle returned by this command can + be used to access the key. + + 2. The contents of a key context blob SHALL be discarded unless the contents have passed an + integrity test. This test SHALL (statistically) prove that the contents of the blob are the + same as when the blob was created. + + 3. The contents of a key context blob SHALL be discarded unless the contents have passed a + session validity test. This test SHALL (statistically) prove that the blob was created by + this TPM during this power-on session. + */ + if (returnCode == TPM_SUCCESS) { + if (keyContextBlob.resourceType != TPM_RT_KEY) { + printf("TPM_Process_LoadKeyContext: Error, resourceType %08x should be TPM_RT_KEY\n", + keyContextBlob.resourceType); + returnCode =TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Decrypting TPM_CONTEXT_SENSITIVE stream\n"); + returnCode = + TPM_SymmetricKeyData_Decrypt(&contextSensitiveBuffer, /* decrypted data */ + &contextSensitiveBuffer_length, /* length decrypted data */ + keyContextBlob.sensitiveData.buffer, /* encrypted */ + keyContextBlob.sensitiveData.size, + tpm_state->tpm_permanent_data.contextKey); + } + /* deserialize TPM_CONTEXT_SENSITIVE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Creating TPM_CONTEXT_SENSITIVE\n"); + stream = contextSensitiveBuffer; + stream_size = contextSensitiveBuffer_length; + returnCode = TPM_ContextSensitive_Load(&contextSensitive, &stream, &stream_size); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Loading TPM_KEY_HANDLE_ENTRY from internalData\n"); + stream = contextSensitive.internalData.buffer; + stream_size = contextSensitive.internalData.size; + returnCode = TPM_KeyHandleEntry_Load(&tpm_key_handle_entry, &stream, &stream_size); + } + /* check contextNonce */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Checking TPM_CONTEXT_SENSITIVE -> contextNonce\n"); + returnCode = TPM_Nonce_Compare(tpm_state->tpm_stclear_data.contextNonceKey, + contextSensitive.contextNonce); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Error comparing contextNonceKey\n"); + returnCode = TPM_BADCONTEXT; + } + } + /* Move decrypted data back to keyContextBlob for integrityDigest check. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Set(&(keyContextBlob.sensitiveData), + contextSensitiveBuffer_length, contextSensitiveBuffer); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Checking integrityDigest\n"); + /* make a copy of integrityDigest, because it needs to be 0 for the HMAC calculation */ + /* NOTE Done by TPM_HMAC_CheckStructure() */ + /* b. Set B1 -> integrityDigest to NULL */ + /* NOTE Done by TPM_HMAC_CheckStructure() */ + /* verify the integrityDigest HMAC of TPM_CONTEXT_BLOB using TPM_PERMANENT_DATA -> tpmProof + as the HMAC key */ + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &keyContextBlob, /* structure */ + keyContextBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store, /* store function */ + TPM_BADCONTEXT); /* error code */ + } + /* try to use the saved handle value when possible */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Checking if suggested handle %08x is free\n", + keyContextBlob.handle); + /* check if the key handle is free */ + getRc = TPM_KeyHandleEntries_GetEntry(&used_key_handle_entry, + tpm_state->tpm_key_handle_entries, + keyContextBlob.handle); + /* GetEntry TPM_SUCCESS means the handle is already used */ + if (getRc == TPM_SUCCESS) { + keyHandle = 0; /* no suggested handle */ + } + /* not success means that the handle value is not currently used */ + else { + keyHandle = keyContextBlob.handle; + } + } + /* check that there is space in the key handle entries */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Checking for table space\n"); + TPM_KeyHandleEntries_IsSpace(&isSpace, &index, + tpm_state->tpm_key_handle_entries); + /* if there is no space, return error */ + if (!isSpace) { + printf("TPM_Process_LoadKeyContext: Error, no room in table\n"); + returnCode = TPM_RESOURCES; + } + } + /* restore the entity, try to keep the handle as 'handle' */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKeyContext: Adding entry to table\n"); + returnCode = TPM_KeyHandleEntries_AddEntry(&keyHandle, + FALSE, /* keep handle */ + tpm_state->tpm_key_handle_entries, + &tpm_key_handle_entry); + key_added = TRUE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadKeyContext: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* return keyHandle */ + returnCode = TPM_Sbuffer_Append32(response, keyHandle); + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_ContextBlob_Delete(&keyContextBlob); /* @1 */ + free(contextSensitiveBuffer); /* @2 */ + TPM_ContextSensitive_Delete(&contextSensitive); /* @3 */ + /* if there was a failure, roll back */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(tpm_key_handle_entry.key); /* @5 */ + free(tpm_key_handle_entry.key); /* @5 */ + if (key_added) { + /* if there was a failure and a key was stored in the handle list, free the handle. + Ignore errors, since only one error code can be returned. */ + TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, keyHandle); + } + } + return rcf; +} + +/* 27.2.3 TPM_SaveAuthContext rev 87 + + SaveAuthContext saves a loaded authorization session outside the TPM. After creation of the + authorization context blob, the TPM automatically releases the internal memory used by that + session. The format of the authorization context blob is specific to a TPM. +*/ + +TPM_RESULT TPM_Process_SaveAuthContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_AUTHHANDLE authHandle; /* Authorization session which will be kept outside the TPM + */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *tpm_auth_session_data; /* session table entry for the handle */ + TPM_BOOL isZero; /* contextNonceSession not set yet */ + TPM_STCLEAR_DATA *v1StClearData; + uint32_t contextIndex; /* free index in context list */ + uint32_t space; /* free space in context list */ + TPM_CONTEXT_SENSITIVE contextSensitive; + TPM_STORE_BUFFER contextSensitive_sbuffer; /* serialization of contextSensitive */ + TPM_CONTEXT_BLOB contextBlob; + TPM_STORE_BUFFER contextBlob_sbuffer; /* serialization of contextBlob */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SaveAuthContext: Ordinal Entry\n"); + TPM_ContextSensitive_Init(&contextSensitive); /* freed @1 */ + TPM_Sbuffer_Init(&contextSensitive_sbuffer); /* freed @2 */ + TPM_ContextBlob_Init(&contextBlob); /* freed @3 */ + TPM_Sbuffer_Init(&contextBlob_sbuffer); /* freed @4 */ + /* + get inputs + */ + /* get authHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&authHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveAuthContext: authHandle %08x\n", authHandle); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SaveAuthContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This command allows saving a loaded authorization session outside the TPM. After creation of + the authContextBlob, the TPM automatically releases the internal memory used by that + session. The format of the authorization context blob is specific to a TPM. + + A TPM protected capability belonging to the TPM that created an authorization context blob + MUST be the only entity that can interpret the contents of that blob. If a cryptographic + technique is used for this purpose, the level of security provided by that technique SHALL be + at least as secure as a 2048 bit RSA algorithm. Any secrets (such as keys) used in such a + cryptographic technique MUST be generated using the TPM's random number generator. Any + symmetric key MUST be used within the power-on session during which it was created, only. + + An authorization context blob SHALL enable verification of the integrity of the contents of + the blob by a TPM protected capability. + + An authorization context blob SHALL enable verification of the session validity of the + contents of the blob by a TPM protected capability. The method SHALL ensure that all + authorization context blobs are rendered invalid if power to the TPM is interrupted. + */ + /* 1. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */ + if (returnCode == TPM_SUCCESS) { + v1StClearData = &(tpm_state->tpm_stclear_data); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveAuthContext: Handle %08x\n", authHandle); + returnCode = TPM_AuthSessions_GetEntry(&tpm_auth_session_data, + v1StClearData->authSessions, + authHandle); + } + if (returnCode == TPM_SUCCESS) { + /* If TPM_STANY_DATA -> contextNonceSession is NULLS */ + TPM_Nonce_IsZero(&isZero, v1StClearData->contextNonceSession); + if (isZero) { + /* Set TPM_STANY_DATA -> contextNonceSession to the next value from the TPM RNG */ + returnCode = TPM_Nonce_Generate(v1StClearData->contextNonceSession); + } + } + /* Create internalData by putting the sensitive part of the resource pointed to by handle into a + structure. The structure is a TPM manufacturer option. The TPM MUST ensure that ALL sensitive + information of the resource is included in internalData. For a session, the entire structure + can fit in the sensitive part. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveAuthContext: Building TPM_CONTEXT_SENSITIVE\n"); + returnCode = TPM_SizedBuffer_SetStructure(&(contextSensitive.internalData), + tpm_auth_session_data, + (TPM_STORE_FUNCTION_T)TPM_AuthSessionData_Store); + } + if (returnCode == TPM_SUCCESS) { + } + if (returnCode == TPM_SUCCESS) { + /* TPM_CONTEXT_SENSITIVE -> contextNonce */ + TPM_Nonce_Copy(contextSensitive.contextNonce, v1StClearData->contextNonceSession); + /* TPM_CONTEXT_BLOB -> resourceType, handle, integrityDigest */ + printf("TPM_Process_SaveAuthContext: Building TPM_CONTEXT_BLOB\n"); + contextBlob.resourceType = TPM_RT_AUTH; + contextBlob.handle = authHandle; + TPM_Digest_Init(contextBlob.integrityDigest); + } + /* TPM_CONTEXT_BLOB -> sensitiveData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextSensitive_Store(&contextSensitive_sbuffer, &contextSensitive); + } + /* Here the clear text goes into TPM_CONTEXT_BLOB->sensitiveData */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(contextBlob.sensitiveData), + &contextSensitive_sbuffer); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_SaveAuthContext: Processing session context count\n"); + /* a. If V1 -> contextCount > 2^32-2 then */ + if (v1StClearData->contextCount > 0xfffffffe) { + /* i. Return with TPM_TOOMANYCONTEXTS */ + printf("TPM_Process_SaveAuthContext: Error, too many contexts\n"); + returnCode = TPM_TOOMANYCONTEXTS; + } + } + /* b. Else */ + if (returnCode == TPM_SUCCESS) { + /* i. Increment V1 -> contextCount by 1 */ + v1StClearData->contextCount++; + /* ii. Validate that the TPM can still manage the new count value */ + /* (1) If the distance between the oldest saved context and the contextCount is + too large return TPM_CONTEXT_GAP */ + /* Since contextCount is uint32_t, this is not applicable here. From email: Does the + TPM have the ability to keep track of the context delta. It is possible to keep + track of things with just a byte or so internally, if this is done a gap of + greater than 2^16 or so might be too large, hence the context gap message */ + } + /* iii. Find contextIndex such that V1 -> contextList[contextIndex] equals 0. If not + found exit with TPM_NOCONTEXTSPACE */ + if (returnCode == TPM_SUCCESS) { + TPM_ContextList_GetSpace(&space, &contextIndex, v1StClearData->contextList); + if (space == 0) { + printf("TPM_Process_SaveAuthContext: Error, no space in context list\n"); + returnCode = TPM_NOCONTEXTSPACE; + } + } + if (returnCode == TPM_SUCCESS) { + /* iv. Set V1-> contextList[contextIndex] to V1 -> contextCount */ + v1StClearData->contextList[contextIndex] = v1StClearData->contextCount; + /* v. Set B1 -> contextCount to V1 -> contextCount */ + contextBlob.contextCount = v1StClearData->contextCount; + } + /* c. The TPM MUST invalidate all information regarding the resource except for information + needed for reloading */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_TerminateHandle(v1StClearData->authSessions, authHandle); + } + /* Calculate TPM_CONTEXT_BLOB -> integrityDigest, the HMAC of TPM_CONTEXT_BLOB using + TPM_PERMANENT_DATA -> tpmProof as the secret */ + if (returnCode == TPM_SUCCESS) { + /* This is a bit circular. It's safe since the TPM_CONTEXT_BLOB is serialized before the + HMAC is generated. The result is put back into the structure. */ + printf("TPM_Process_SaveAuthContext: Digesting TPM_CONTEXT_BLOB\n"); + returnCode = TPM_HMAC_GenerateStructure + (contextBlob.integrityDigest, /* HMAC */ + tpm_state->tpm_permanent_data.tpmProof, /* HMAC key */ + &contextBlob, /* structure */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store); /* store function */ + } + /* encrypt TPM_CONTEXT_SENSITIVE using as TPM_PERMANENT_DATA -> contextKey the key. Store the + result in TPM_CONTEXT_BLOB -> sensitiveData */ + if (returnCode == TPM_SUCCESS) { + /* The cleartext went into sensitiveData for the integrityDigest calculation. Free it now, + before the encrypted data is stored there. */ + TPM_SizedBuffer_Delete(&(contextBlob.sensitiveData)); + printf("TPM_Process_SaveAuthContext: Encrypting TPM_CONTEXT_SENSITIVE\n"); + returnCode = + TPM_SymmetricKeyData_EncryptSbuffer(&(contextBlob.sensitiveData), + &contextSensitive_sbuffer, + tpm_state->tpm_permanent_data.contextKey); + } + /* serialize TPM_CONTEXT_BLOB */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Store(&contextBlob_sbuffer, &contextBlob); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SaveAuthContext: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return authContextSize and authContextBlob */ + returnCode = TPM_Sbuffer_AppendAsSizedBuffer(response, &contextBlob_sbuffer); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_ContextSensitive_Delete(&contextSensitive); /* @1 */ + TPM_Sbuffer_Delete(&contextSensitive_sbuffer); /* @2 */ + TPM_ContextBlob_Delete(&contextBlob); /* @3 */ + TPM_Sbuffer_Delete(&contextBlob_sbuffer); /* @4 */ + return rcf; +} + +/* 27.2.4 TPM_LoadAuthContext rev 106 + + 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_Process_LoadAuthContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + uint32_t authContextSize; /* The size of the following auth context blob */ + TPM_CONTEXT_BLOB authContextBlob; /* The auth context blob */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + unsigned char *stream; + uint32_t stream_size; + unsigned char *contextSensitiveBuffer; /* decrypted sensitive data */ + uint32_t contextSensitiveBuffer_length; /* actual data in contextSensitiveBuffer */ + TPM_CONTEXT_SENSITIVE contextSensitive; + TPM_AUTH_SESSION_DATA tpm_auth_session_data; + TPM_AUTH_SESSION_DATA *used_auth_session_data; + TPM_RESULT getRc; /* is the handle value free */ + TPM_BOOL isSpace; + uint32_t index; /* free space index */ + TPM_BOOL auth_session_added = FALSE; /* session key has been added to handle list */ + TPM_STCLEAR_DATA *v1StClearData = NULL; + uint32_t contextIndex; + TPM_DIGEST entityDigest; /* digest of the entity used to set up the + OSAP or DSAP session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY_HANDLE authHandle; /* The handle assigned to the authorization session after it + has been successfully loaded. */ + + printf("TPM_Process_LoadAuthContext: Ordinal Entry\n"); + TPM_ContextBlob_Init(&authContextBlob); /* freed @1 */ + contextSensitiveBuffer = NULL; /* freed @2 */ + TPM_ContextSensitive_Init(&contextSensitive); /* freed @3 */ + TPM_AuthSessionData_Init(&tpm_auth_session_data); /* freed @4 */ + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get authContextSize parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&authContextSize, &command, ¶mSize); + } + /* get authContextBlob parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_ContextBlob_Load(&authContextBlob, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: handle %08x\n", authContextBlob.handle); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadAuthContext: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* This command allows loading an authorization context blob into the TPM previously retrieved + by a TPM_SaveAuthContext call. After successful completion, the handle returned by this + command can be used to access the authorization session. + + The contents of an authorization context blob SHALL be discarded unless the contents have + passed an integrity test. This test SHALL (statistically) prove that the contents of the blob + are the same as when the blob was created. + + The contents of an authorization context blob SHALL be discarded unless the contents have + passed a session validity test. This test SHALL (statistically) prove that the blob was + created by this TPM during this power-on session. + + For an OSAP authorization context blob referring to a key, verify that the key linked to this + session is resident in the TPM. + */ + if (returnCode == TPM_SUCCESS) { + /* 2. Map V1 to TPM_STANY_DATA NOTE MAY be TPM_STCLEAR_DATA */ + v1StClearData = &(tpm_state->tpm_stclear_data); + if (authContextBlob.resourceType != TPM_RT_AUTH) { + printf("TPM_Process_LoadAuthContext: Error, resourceType %08x should be TPM_RT_AUTH\n", + authContextBlob.resourceType); + returnCode = TPM_BAD_PARAMETER; + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Decrypting TPM_CONTEXT_SENSITIVE stream\n"); + returnCode = + TPM_SymmetricKeyData_Decrypt(&contextSensitiveBuffer, /* decrypted data */ + &contextSensitiveBuffer_length, /* length decrypted data */ + authContextBlob.sensitiveData.buffer, /* encrypted */ + authContextBlob.sensitiveData.size, + tpm_state->tpm_permanent_data.contextKey); + } + /* deserialize TPM_CONTEXT_SENSITIVE */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Creating TPM_CONTEXT_SENSITIVE\n"); + stream = contextSensitiveBuffer; + stream_size = contextSensitiveBuffer_length; + returnCode = TPM_ContextSensitive_Load(&contextSensitive, + &stream, + &stream_size); + } + /* Parse the TPM_CONTEXT_SENSITIVE -> internalData to TPM_AUTH_SESSION_DATA */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Loading TPM_AUTH_SESSION_DATA from internalData\n"); + stream = contextSensitive.internalData.buffer; + stream_size = contextSensitive.internalData.size; + returnCode = TPM_AuthSessionData_Load(&tpm_auth_session_data, &stream, &stream_size); + } + /* check contextNonce */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: protocolID %04x entityTypeByte %02x\n", + tpm_auth_session_data.protocolID, tpm_auth_session_data.entityTypeByte); + printf("TPM_Process_LoadAuthContext: Checking TPM_CONTEXT_SENSITIVE -> contextNonce\n"); + returnCode = TPM_Nonce_Compare(v1StClearData->contextNonceSession, + contextSensitive.contextNonce); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Error comparing contextNonceSession\n"); + returnCode = TPM_BADCONTEXT; + } + } + if (returnCode == TPM_SUCCESS) { + if ((tpm_auth_session_data.protocolID == TPM_PID_OSAP) || + (tpm_auth_session_data.protocolID == TPM_PID_DSAP)) { + /* check that the entity is loaded, and that the entity's digest equals that of the OSAP + or DSAP session */ + switch (tpm_auth_session_data.entityTypeByte) { + case TPM_ET_OWNER: + printf("TPM_Process_LoadAuthContext: Owner OSAP/DSAP session\n"); + /* check for owner */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadContext_CheckOwnerLoaded(tpm_state, entityDigest); + } + /* compare entity digest */ + if (returnCode == TPM_SUCCESS) { + returnCode= TPM_Digest_Compare(entityDigest, + tpm_auth_session_data.entityDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: " + "Error, OSAP or DSAP entityDigest mismatch\n"); + returnCode = TPM_RESOURCEMISSING; + } + } + break; + case TPM_ET_SRK: + printf("TPM_Process_LoadAuthContext: SRK OSAP/DSAP session\n"); + /* check for SRK */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadContext_CheckSrkLoaded(tpm_state, entityDigest); + } + /* compare entity digest */ + if (returnCode == TPM_SUCCESS) { + returnCode= TPM_Digest_Compare(entityDigest, + tpm_auth_session_data.entityDigest); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: " + "Error, OSAP or DSAP entityDigest mismatch\n"); + returnCode = TPM_RESOURCEMISSING; + } + } + break; + case TPM_ET_KEYHANDLE: + printf("TPM_Process_LoadAuthContext: Key OSAP/DSAP session\n"); + /* for keys */ + returnCode = + TPM_LoadContext_CheckKeyLoadedByDigest(tpm_state, + tpm_auth_session_data.entityDigest); + break; + case TPM_ET_COUNTER: + printf("TPM_Process_LoadAuthContext: Counter OSAP/DSAP session\n"); +#if 0 /* TPM_LoadAuthContext is a deprecated 1.1 command, where there was no counter */ + returnCode = + TPM_LoadContext_CheckCounterLoaded(tpm_state, + entityHandle, + entityDigest); +#endif + break; + case TPM_ET_NV: + printf("TPM_Process_LoadAuthContext: NV OSAP/DSAP session\n"); +#if 0 /* TPM_LoadAuthContext is a deprecated 1.1 command, where there was no NV space */ + returnCode = + TPM_LoadContext_CheckNvLoaded(tpm_state, + entityHandle, + entityDigest); +#endif + break; + default: + printf("TPM_Process_LoadAuthContext: Error, invalid session entityType %02x\n", + tpm_auth_session_data.entityTypeByte); + returnCode = TPM_WRONG_ENTITYTYPE; + break; + } + } + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Checking integrityDigest\n"); + /* b. Set B1 -> integrityDigest to NULL */ + /* NOTE Done by TPM_HMAC_CheckStructure() */ + /* c. Copy M1 to B1 -> sensitiveData (integrityDigest HMAC uses cleartext) */ + returnCode = TPM_SizedBuffer_Set(&(authContextBlob.sensitiveData), + contextSensitiveBuffer_length, contextSensitiveBuffer); + /* verify the integrityDigest HMAC of TPM_CONTEXT_BLOB using TPM_PERMANENT_DATA -> tpmProof + as the HMAC key */ + returnCode = TPM_HMAC_CheckStructure + (tpm_state->tpm_permanent_data.tpmProof, /* key */ + &authContextBlob, /* structure */ + authContextBlob.integrityDigest, /* expected */ + (TPM_STORE_FUNCTION_T)TPM_ContextBlob_Store, /* store function */ + TPM_BADCONTEXT); /* error code */ + } + /* try to use the saved handle value when possible */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Checking if suggested handle %08x is free\n", + authContextBlob.handle); + /* check if the auth handle is free */ + getRc = TPM_AuthSessions_GetEntry(&used_auth_session_data, + tpm_state->tpm_stclear_data.authSessions, + authContextBlob.handle); + /* GetEntry TPM_SUCCESS means the handle is already used */ + if (getRc == TPM_SUCCESS) { + authHandle = 0; /* no suggested handle */ + } + /* not success means that the handle value is not currently used */ + else { + authHandle = authContextBlob.handle; + } + } + /* check that there is space in the authorization handle entries */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Checking for table space\n"); + TPM_AuthSessions_IsSpace(&isSpace, &index, + tpm_state->tpm_stclear_data.authSessions); + /* if there is no space, return error */ + if (!isSpace) { + printf("TPM_Process_LoadAuthContext: Error, no room in table\n"); + TPM_AuthSessions_Trace(tpm_state->tpm_stclear_data.authSessions); + returnCode = TPM_RESOURCES; + } + } + /* a. Find contextIndex such that V1 -> contextList[contextIndex] equals B1 -> + TPM_CONTEXT_BLOB -> contextCount */ + /* b. If not found then return TPM_BADCONTEXT */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadAuthContext: Checking contextCount\n"); + returnCode = TPM_ContextList_GetEntry(&contextIndex, + v1StClearData->contextList, + authContextBlob.contextCount); + } + /* c. Set V1 -> contextList[contextIndex] to 0 */ + if (returnCode == TPM_SUCCESS) { + v1StClearData->contextList[contextIndex] = 0; + } + /* restore the entity, try to keep the handle as 'handle' */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_AddEntry(&authHandle, /* input/output */ + FALSE, /* keepHandle */ + v1StClearData->authSessions, + &tpm_auth_session_data); + auth_session_added = TRUE; + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadAuthContext: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* return authHandle */ + returnCode = TPM_Sbuffer_Append32(response, authHandle); + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + TPM_ContextBlob_Delete(&authContextBlob); /* @1 */ + free(contextSensitiveBuffer); /* @2 */ + TPM_ContextSensitive_Delete(&contextSensitive); /* @3 */ + TPM_AuthSessionData_Delete(&tpm_auth_session_data); /* @4 */ + /* if there was a failure, roll back */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + if (auth_session_added) { + TPM_AuthSessionData_Delete(&tpm_auth_session_data); + } + } + return rcf; +} diff --git a/src/tpm_session.h b/src/tpm_session.h new file mode 100644 index 00000000..a7c9c6de --- /dev/null +++ b/src/tpm_session.h @@ -0,0 +1,276 @@ +/********************************************************************************/ +/* */ +/* TPM Sessions Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_session.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_SESSION_H +#define TPM_SESSION_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_types.h" + +/* + TPM_AUTH_SESSION_DATA (the entire array) +*/ + +void TPM_AuthSessions_Init(TPM_AUTH_SESSION_DATA *authSessions); +TPM_RESULT TPM_AuthSessions_Load(TPM_AUTH_SESSION_DATA *authSessions, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_AuthSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_AUTH_SESSION_DATA *authSessions); +void TPM_AuthSessions_Delete(TPM_AUTH_SESSION_DATA *authSessions); + + +void TPM_AuthSessions_IsSpace(TPM_BOOL *isSpace, uint32_t *index, + TPM_AUTH_SESSION_DATA *authSessions); +void TPM_AuthSessions_Trace(TPM_AUTH_SESSION_DATA *authSessions); +void TPM_AuthSessions_GetSpace(uint32_t *space, + TPM_AUTH_SESSION_DATA *authSessions); +TPM_RESULT TPM_AuthSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_AUTH_SESSION_DATA *authSessions); +TPM_RESULT TPM_AuthSessions_GetNewHandle(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, + TPM_AUTHHANDLE *authHandle, + TPM_AUTH_SESSION_DATA *authSessions); +TPM_RESULT TPM_AuthSessions_GetEntry(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, + TPM_AUTH_SESSION_DATA *authSessions, + TPM_AUTHHANDLE authHandle); +TPM_RESULT TPM_AuthSessions_AddEntry(TPM_HANDLE *tpm_handle, + TPM_BOOL keepHandle, + TPM_AUTH_SESSION_DATA *authSessions, + TPM_AUTH_SESSION_DATA *tpm_auth_session_data); +TPM_RESULT TPM_AuthSessions_GetData(TPM_AUTH_SESSION_DATA **tpm_auth_session_data, + TPM_SECRET **hmacKey, + tpm_state_t *tpm_state, + TPM_AUTHHANDLE authHandle, + TPM_PROTOCOL_ID protocolID, + TPM_ENT_TYPE entityType, + TPM_COMMAND_CODE ordinal, + TPM_KEY *tpmKey, + TPM_SECRET *entityAuth, + TPM_DIGEST entityDigest); + +TPM_RESULT TPM_AuthSessions_TerminateHandle(TPM_AUTH_SESSION_DATA *authSessions, + TPM_AUTHHANDLE authHandle); +void TPM_AuthSessions_TerminateEntity(TPM_BOOL *continueAuthSession, + TPM_AUTHHANDLE authHandle, + TPM_AUTH_SESSION_DATA *authSessions, + TPM_ENT_TYPE entityType, + TPM_DIGEST *entityDigest); +void TPM_AuthSessions_TerminatexSAP(TPM_BOOL *continueAuthSession, + TPM_AUTHHANDLE authHandle, + TPM_AUTH_SESSION_DATA *authSessions); + +/* + TPM_AUTH_SESSION_DATA (one element of the array) +*/ + + +void TPM_AuthSessionData_Init(TPM_AUTH_SESSION_DATA *tpm_auth_session_data); +TPM_RESULT TPM_AuthSessionData_Load(TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_AuthSessionData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_AUTH_SESSION_DATA *tpm_auth_session_data); +void TPM_AuthSessionData_Delete(TPM_AUTH_SESSION_DATA *tpm_auth_session_data); + + +void TPM_AuthSessionData_Copy(TPM_AUTH_SESSION_DATA *dest_auth_session_data, + TPM_HANDLE tpm_handle, + TPM_AUTH_SESSION_DATA *src_auth_session_data); +TPM_RESULT TPM_AuthSessionData_GetDelegatePublic(TPM_DELEGATE_PUBLIC **delegatePublic, + TPM_AUTH_SESSION_DATA *auth_session_data); +TPM_RESULT TPM_AuthSessionData_CheckEncScheme(TPM_ADIP_ENC_SCHEME adipEncScheme, + TPM_BOOL FIPS); +TPM_RESULT TPM_AuthSessionData_Decrypt(TPM_DIGEST a1Even, + TPM_DIGEST a1Odd, + TPM_ENCAUTH encAuthEven, + TPM_AUTH_SESSION_DATA *tpm_auth_session_data, + TPM_NONCE nonceOdd, + TPM_ENCAUTH encAuthOdd, + TPM_BOOL odd); + +/* + Context List +*/ + +void TPM_ContextList_Init(uint32_t *contextList); +TPM_RESULT TPM_ContextList_Load(uint32_t *contextList, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_ContextList_Store(TPM_STORE_BUFFER *sbuffer, + const uint32_t *contextList); + +TPM_RESULT TPM_ContextList_StoreHandles(TPM_STORE_BUFFER *sbuffer, + const uint32_t *contextList); +void TPM_ContextList_GetSpace(uint32_t *space, + uint32_t *entry, + const uint32_t *contextList); +TPM_RESULT TPM_ContextList_GetEntry(uint32_t *entry, + const uint32_t *contextList, + uint32_t value); + +/* + TPM_CONTEXT_BLOB +*/ + +void TPM_ContextBlob_Init(TPM_CONTEXT_BLOB *tpm_context_blob); +TPM_RESULT TPM_ContextBlob_Load(TPM_CONTEXT_BLOB *tpm_context_blob, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_ContextBlob_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CONTEXT_BLOB *tpm_context_blob); +void TPM_ContextBlob_Delete(TPM_CONTEXT_BLOB *tpm_context_blob); + +/* + TPM_CONTEXT_SENSITIVE +*/ + +void TPM_ContextSensitive_Init(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive); +TPM_RESULT TPM_ContextSensitive_Load(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_ContextSensitive_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CONTEXT_SENSITIVE *tpm_context_sensitive); +void TPM_ContextSensitive_Delete(TPM_CONTEXT_SENSITIVE *tpm_context_sensitive); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_OIAP(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_OSAP(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_DSAP(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_SetOwnerPointer(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_TerminateHandle(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + +TPM_RESULT TPM_Process_FlushSpecific(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_SaveContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_LoadContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_KeyControlOwner(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_SaveKeyContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_LoadKeyContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_SaveAuthContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_LoadAuthContext(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + + + + + +#endif diff --git a/src/tpm_sizedbuffer.c b/src/tpm_sizedbuffer.c new file mode 100644 index 00000000..046ad432 --- /dev/null +++ b/src/tpm_sizedbuffer.c @@ -0,0 +1,374 @@ +/********************************************************************************/ +/* */ +/* TPM Sized Buffer Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_sizedbuffer.c 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_memory.h" +#include "tpm_process.h" +#include "tpm_types.h" + +#include "tpm_sizedbuffer.h" + +void TPM_SizedBuffer_Init(TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + tpm_sized_buffer->size = 0; + tpm_sized_buffer->buffer = NULL; + return; +} + +/* TPM_SizedBuffer_Load() allocates and sets a sized buffer from a stream. A sized buffer structure + has two members: + + - 4 bytes size + - pointer to array of 'size' + + This structure is typically a cast from a subset of a larger TPM structure. Two members - a 4 + bytes size followed by a 4 bytes pointer to the data is a common TPM structure idiom. + + This function correctly handles a 'size' of 0. + + Call TPM_SizedBuffer_Init() before first use + Call TPM_SizedBuffer_Delete() after use +*/ + +TPM_RESULT TPM_SizedBuffer_Load(TPM_SIZED_BUFFER *tpm_sized_buffer, /* result */ + unsigned char **stream, /* pointer to next parameter */ + uint32_t *stream_size) /* stream size left */ +{ + TPM_RESULT rc = 0; + + printf(" TPM_SizedBuffer_Load:\n"); + if (rc == 0) { + rc = TPM_Load32(&(tpm_sized_buffer->size), stream, stream_size); + } + /* if the size is not 0 */ + if ((rc == 0) && (tpm_sized_buffer->size > 0)) { + /* allocate memory for the buffer */ + if (rc == 0) { + rc = TPM_Malloc(&(tpm_sized_buffer->buffer), tpm_sized_buffer->size); + } + /* copy the buffer */ + if (rc == 0) { + rc = TPM_Loadn(tpm_sized_buffer->buffer, tpm_sized_buffer->size, stream, stream_size); + } + } + return rc; +} + +/* TPM_SizedBuffer_Set() reallocs a sized buffer and copies 'size' bytes of 'data' into it. + + If the sized buffer already has data, the buffer is realloc'ed. + + This function correctly handles a 'size' of 0. + + Call TPM_SizedBuffer_Delete() to free the buffer +*/ + +TPM_RESULT TPM_SizedBuffer_Set(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size, + const unsigned char *data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SizedBuffer_Set:\n"); + /* allocate memory for the buffer, and copy the buffer */ + if (rc == 0) { + if (size > 0) { + rc = TPM_Realloc(&(tpm_sized_buffer->buffer), + size); + if (rc == 0) { + tpm_sized_buffer->size = size; + memcpy(tpm_sized_buffer->buffer, data, size); + } + } + /* if size is zero */ + else { + TPM_SizedBuffer_Delete(tpm_sized_buffer); + } + } + return rc; +} + +/* TPM_SizedBuffer_SetFromStore() reallocs a sized buffer and copies 'sbuffer" data into it. + + This function correctly handles an 'sbuffer' of 0 length. + */ + +TPM_RESULT TPM_SizedBuffer_SetFromStore(TPM_SIZED_BUFFER *tpm_sized_buffer, + TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *data; + uint32_t size; + + if (rc == 0) { + /* get the stream and its size from the TPM_STORE_BUFFER */ + TPM_Sbuffer_Get(sbuffer, &data, &size); + rc = TPM_SizedBuffer_Set(tpm_sized_buffer, size, data); + } + return rc; +} + +/* TPM_SizedBuffer_SetStructure() serializes the structure 'tpmStructure' using the function + 'storeFunction', storing the result in a TPM_SIZED_BUFFER. +*/ + +TPM_RESULT TPM_SizedBuffer_SetStructure(TPM_SIZED_BUFFER *tpm_sized_buffer, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* serialized tpmStructure */ + + printf(" TPM_SizedBuffer_SetStructure:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the structure */ + if (rc == 0) { + if (tpmStructure != NULL) { + rc = storeFunction(&sbuffer, tpmStructure); + } + } + /* copy to TPM_SIZED_BUFFER */ + if (rc == 0) { + rc = TPM_SizedBuffer_SetFromStore(tpm_sized_buffer, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +TPM_RESULT TPM_SizedBuffer_Copy(TPM_SIZED_BUFFER *tpm_sized_buffer_dest, + TPM_SIZED_BUFFER *tpm_sized_buffer_src) +{ + TPM_RESULT rc = 0; + rc = TPM_SizedBuffer_Set(tpm_sized_buffer_dest, + tpm_sized_buffer_src->size, + tpm_sized_buffer_src->buffer); + return rc; +} + + +/* TPM_SizedBuffer_Store() serializes a TPM_SIZED_BUFFER into a TPM_STORE_BUFFER + */ + +TPM_RESULT TPM_SizedBuffer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SizedBuffer_Store:\n"); + /* append the size */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_sized_buffer->size); + } + /* append the data */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_sized_buffer->buffer, tpm_sized_buffer->size); + } + return rc; +} + +void TPM_SizedBuffer_Delete(TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + printf(" TPM_SizedBuffer_Delete:\n"); + if (tpm_sized_buffer != NULL) { + free(tpm_sized_buffer->buffer); + TPM_SizedBuffer_Init(tpm_sized_buffer); + } + return; +} + +/* TPM_SizedBuffer_Allocate() allocates 'size' bytes of memory and sets the TPM_SIZED_BUFFER + members. + + The buffer data is not initialized. +*/ + +TPM_RESULT TPM_SizedBuffer_Allocate(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SizedBuffer_Allocate: Size %u\n", size); + tpm_sized_buffer->size = size; + rc = TPM_Malloc(&(tpm_sized_buffer->buffer), size); + return rc; +} + +/* TPM_SizedBuffer_GetBool() converts from a TPM_SIZED_BUFFER to a TPM_BOOL. + + If the size does not indicate a TPM_BOOL, an error is returned. +*/ + +TPM_RESULT TPM_SizedBuffer_GetBool(TPM_BOOL *tpm_bool, + TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + + if (tpm_sized_buffer->size == sizeof(TPM_BOOL)) { + *tpm_bool = *(TPM_BOOL *)tpm_sized_buffer->buffer; + printf(" TPM_SizedBuffer_GetBool: bool %02x\n", *tpm_bool); + } + else { + printf("TPM_SizedBuffer_GetBool: Error, buffer size %08x is not a BOOL\n", + tpm_sized_buffer->size); + rc = TPM_BAD_PARAMETER; + } + return rc; +} + +/* TPM_SizedBuffer_GetUint32() converts from a TPM_SIZED_BUFFER to a uint32_t. + + If the size does not indicate a uint32_t, an error is returned. +*/ + +TPM_RESULT TPM_SizedBuffer_GetUint32(uint32_t *uint32, + TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + + if (rc == 0) { + if (tpm_sized_buffer->size != sizeof(uint32_t)) { + printf("TPM_GetUint32: Error, buffer size %08x is not a uint32_t\n", + tpm_sized_buffer->size); + rc = TPM_BAD_PARAMETER; + } + } + if (rc == 0) { + stream = tpm_sized_buffer->buffer; + stream_size = tpm_sized_buffer->size; + rc = TPM_Load32(uint32, &stream, &stream_size); + } + return rc; +} + +/* TPM_SizedBuffer_Append32() appends a uint32_t to a TPM_SIZED_BUFFER + +*/ + +TPM_RESULT TPM_SizedBuffer_Append32(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t uint32) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SizedBuffer_Append32: Current size %u uint32 %08x\n", + tpm_sized_buffer->size, uint32); + /* allocate space for another uint32_t */ + if (rc == 0) { + rc = TPM_Realloc(&(tpm_sized_buffer->buffer), + tpm_sized_buffer->size + sizeof(uint32_t)); + } + if (rc == 0) { + uint32_t ndata = htonl(uint32); /* convert to network byte order */ + memcpy(tpm_sized_buffer->buffer + tpm_sized_buffer->size, /* append at end */ + (char *)&ndata, /* cast safe after conversion */ + sizeof(uint32_t)); + tpm_sized_buffer->size += sizeof(uint32_t); + } + return rc; +} + +/* TPM_SizedBuffer_Remove32() removes the uint32_t with value from a TPM_SIZED_BUFFER + +*/ + +TPM_RESULT TPM_SizedBuffer_Remove32(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t uint32) +{ + TPM_RESULT rc = 0; + unsigned char *stream; + uint32_t stream_size; + uint32_t bufferValue; + TPM_BOOL found = FALSE; + unsigned char *from; + unsigned char *to; + + printf(" TPM_SizedBuffer_Remove32: Current size %u uint32 %08x\n", + tpm_sized_buffer->size, uint32); + + stream = tpm_sized_buffer->buffer; + stream_size = tpm_sized_buffer->size; + + /* search for the uint32 */ + while ((rc == 0) && (stream_size != 0) && !found) { + /* get the next value */ + if (rc == 0) { + rc = TPM_Load32(&bufferValue, &stream, &stream_size); + } + /* if the value is the one to be removed */ + if (rc == 0) { + if (bufferValue == uint32) { + found = TRUE; + /* shift the reset of the buffer down by a uint32_t */ + for (from = stream, to = (stream - sizeof(uint32_t)) ; + /* go to the end of the buffer */ + from < (tpm_sized_buffer->buffer + tpm_sized_buffer->size) ; + from++, to++) { + *to = *from; + } + /* adjust the size */ + tpm_sized_buffer->size -= sizeof(uint32_t); + } + } + } + if (!found) { + printf("TPM_SizedBuffer_Remove32: Error, value not found\n"); + rc = TPM_BAD_HANDLE; + } + return rc; +} + +/* TPM_SizedBuffer_Zero() overwrites all data in the buffer with zeros + + */ + +void TPM_SizedBuffer_Zero(TPM_SIZED_BUFFER *tpm_sized_buffer) +{ + printf(" TPM_SizedBuffer_Zero:\n"); + if (tpm_sized_buffer->buffer != NULL) { + memset(tpm_sized_buffer->buffer, 0, tpm_sized_buffer->size); + } + return; +} diff --git a/src/tpm_sizedbuffer.h b/src/tpm_sizedbuffer.h new file mode 100644 index 00000000..a92c3e90 --- /dev/null +++ b/src/tpm_sizedbuffer.h @@ -0,0 +1,75 @@ +/********************************************************************************/ +/* */ +/* TPM Sized Buffer Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_sizedbuffer.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_SIZEDBUFFER_H +#define TPM_SIZEDBUFFER_H + +#include "tpm_digest.h" +#include "tpm_store.h" + +void TPM_SizedBuffer_Init(TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_SizedBuffer_Load(TPM_SIZED_BUFFER *tpm_sized_buffer, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_SizedBuffer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_SizedBuffer_Set(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size, + const unsigned char *data); +TPM_RESULT TPM_SizedBuffer_SetFromStore(TPM_SIZED_BUFFER *tpm_sized_buffer, + TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_SizedBuffer_SetStructure(TPM_SIZED_BUFFER *tpm_sized_buffer, + void *tpmStructure, + TPM_STORE_FUNCTION_T storeFunction); +TPM_RESULT TPM_SizedBuffer_Copy(TPM_SIZED_BUFFER *tpm_sized_buffer_dest, + TPM_SIZED_BUFFER *tpm_sized_buffer_src); +void TPM_SizedBuffer_Delete(TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_SizedBuffer_Allocate(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t size); +TPM_RESULT TPM_SizedBuffer_GetBool(TPM_BOOL *tpm_bool, + TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_SizedBuffer_GetUint32(uint32_t *uint32, + TPM_SIZED_BUFFER *tpm_sized_buffer); +TPM_RESULT TPM_SizedBuffer_Append32(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t uint32); +TPM_RESULT TPM_SizedBuffer_Remove32(TPM_SIZED_BUFFER *tpm_sized_buffer, + uint32_t uint32); +void TPM_SizedBuffer_Zero(TPM_SIZED_BUFFER *tpm_sized_buffer); + +#endif diff --git a/src/tpm_startup.c b/src/tpm_startup.c new file mode 100644 index 00000000..25ee0175 --- /dev/null +++ b/src/tpm_startup.c @@ -0,0 +1,1444 @@ +/********************************************************************************/ +/* */ +/* TPM Admin Startup and State */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_startup.c 4533 2011-03-30 19:50:41Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_constants.h" +#include "tpm_commands.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_digest.h" +#include "tpm_init.h" +#include "tpm_key.h" +#include "tpm_nonce.h" +#include "tpm_nvfile.h" +#include "tpm_nvfilename.h" +#include "tpm_nvram.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_session.h" + +#include "tpm_startup.h" + +/* + Save State +*/ + +/* TPM_SaveState_Load() restores the TPM state from a stream created by TPM_SaveState_Store() + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_SaveState_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + unsigned char *stream_start = *stream; /* copy for integrity check */ + uint32_t stream_size_start = *stream_size; + + printf(" TPM_SaveState_Load:\n"); + if (rc == 0) { + printf(" TPM_SaveState_Load: Loading PCR's\n"); + } + /* 1. Store PCR contents except for */ + /* a. If the PCR attribute pcrReset is TRUE */ + /* b. Any platform identified debug PCR */ + /* NOTE Done by TPM_StclearData_Load() */ + /* 2. The auditDigest MUST be handled according to the audit requirements as reported by + TPM_GetCapability */ + /* NOTE Moved to TPM_STCLEAR_DATA */ + /* 3. All values in TPM_STCLEAR_DATA MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearData_Load(&(tpm_state->tpm_stclear_data), stream, stream_size, + tpm_state->tpm_permanent_data.pcrAttrib); + } + /* 4. All values in TPM_STCLEAR_FLAGS MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearFlags_Load(&(tpm_state->tpm_stclear_flags), stream, stream_size); + } + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved as reported by + TPM_GetCapability */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Load(tpm_state, stream, stream_size); + } + /* 8. The contents of sessions (authorization, transport etc.) MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE Done at TPM_StclearData_Load() */ + /* load the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_LoadVolatile(&(tpm_state->tpm_nv_index_entries), + stream, stream_size); + } + /* sanity check the stream size */ + if (rc == 0) { + if (*stream_size != TPM_DIGEST_SIZE) { + printf("TPM_SaveState_Load: Error (fatal) stream size %u not %u\n", + *stream_size, TPM_DIGEST_SIZE); + rc = TPM_FAIL; + } + } + /* check the integrity digest */ + if (rc == 0) { + printf(" TPM_SaveState_Load: Checking integrity digest\n"); + rc = TPM_SHA1_Check(*stream, /* currently points to integrity digest */ + stream_size_start - TPM_DIGEST_SIZE, stream_start, + 0, NULL); + } + /* remove the integrity digest from the stream */ + if (rc == 0) { + *stream_size -= TPM_DIGEST_SIZE; + } + return rc; +} + +/* TPM_SaveState_Store() stores the TPM state to a stream that can be restored through + TPM_SaveState_Load(). + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_SaveState_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; /* elements of sbuffer */ + uint32_t length; + TPM_DIGEST tpm_digest; + + printf(" TPM_SaveState_Store:\n"); + if (rc == 0) { + printf(" TPM_SaveState_Store: Storing PCR's\n"); + } + /* NOTE: Actions from TPM_SaveState */ + /* 1. Store TPM_STCLEAR_DATA -> PCR contents except for */ + /* a. If the PCR attribute pcrReset is TRUE */ + /* b. Any platform identified debug PCR */ + /* NOTE Done by TPM_StclearData_Store() */ + /* 2. The auditDigest MUST be handled according to the audit requirements as reported by + TPM_GetCapability */ + /* NOTE Moved to TPM_STCLEAR_DATA */ + /* a. If the ordinalAuditStatus is TRUE for the TPM_SaveState ordinal and the auditDigest is + being stored in the saved state, the saved auditDigest MUST include the TPM_SaveState input + parameters and MUST NOT include the output parameters. */ + /* NOTE Done naturally because this function is called between input and output audit. */ + /* 3. All values in TPM_STCLEAR_DATA MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearData_Store(sbuffer, &(tpm_state->tpm_stclear_data), + tpm_state->tpm_permanent_data.pcrAttrib); + } + /* 4. All values in TPM_STCLEAR_FLAGS MUST be preserved */ + if (rc == 0) { + rc = TPM_StclearFlags_Store(sbuffer, &(tpm_state->tpm_stclear_flags)); + } + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE This implementation saves all keys. Owner evict keys are not saved in the state blob, + as they are already saved in the file system */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Store(sbuffer, tpm_state); + } + /* 8. The contents of sessions (authorization, transport etc.) MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE Done by TPM_StclearData_Store() */ + /* store the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_StoreVolatile(sbuffer, + &(tpm_state->tpm_nv_index_entries)); + } + if (rc == 0) { + /* get the current serialized buffer and its length */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* generate the integrity digest */ + rc = TPM_SHA1(tpm_digest, + length, buffer, + 0, NULL); + } + /* append the integrity digest to the stream */ + if (rc == 0) { + printf(" TPM_SaveState_Store: Appending integrity digest\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_digest, TPM_DIGEST_SIZE); + } + return rc; +} + +/* TPM_SaveState_IsSaveKey() determines which keys are saved as part of the saved state. + + According to Ryan, all keys must be saved for this to be of use. +*/ + +void TPM_SaveState_IsSaveKey(TPM_BOOL *save, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry) +{ + *save = FALSE; + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved as reported by + TPM_GetCapability */ + /* NOTE Owner evict keys are not saved in the state blob, as they are already saved in the file + system */ + if (!(tpm_key_handle_entry->keyControl & TPM_KEY_CONTROL_OWNER_EVICT)) { + *save = TRUE; + } + else { + *save = FALSE; + } + if (*save) { + printf(" TPM_SaveState_IsSaveKey: Save key handle %08x\n", tpm_key_handle_entry->handle); + } + return; +} + +/* TPM_SaveState_NVLoad() deserializes the saved state data from the NV file TPM_SAVESTATE_NAME + + 0 on success. + Returns TPM_RETRY on non-existent file + TPM_FAIL on failure to load (fatal), since it should never occur +*/ + +TPM_RESULT TPM_SaveState_NVLoad(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + unsigned char *stream = NULL; + unsigned char *stream_start = NULL; + uint32_t stream_size; + + printf(" TPM_SaveState_NVLoad:\n"); + if (rc == 0) { + /* load from NVRAM. Returns TPM_RETRY on non-existent file. */ + rc = TPM_NVRAM_LoadData(&stream, /* freed @1 */ + &stream_size, + tpm_state->tpm_number, + TPM_SAVESTATE_NAME); + } + /* deserialize from stream */ + if (rc == 0) { + stream_start = stream; /* save starting point for free() */ + rc = TPM_SaveState_Load(tpm_state, &stream, &stream_size); + if (rc != 0) { + printf("TPM_SaveState_NVLoad: Error (fatal) loading deserializing saved state\n"); + rc = TPM_FAIL; + } + } + free(stream_start); /* @1 */ + return rc; +} + +/* TPM_SaveState_NVStore() serializes saved state data and stores it in the NV file + TPM_SAVESTATE_NAME +*/ + +TPM_RESULT TPM_SaveState_NVStore(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_SaveState_NVStore:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize relevant data from tpm_state to be written to NV */ + if (rc == 0) { + rc = TPM_SaveState_Store(&sbuffer, tpm_state); + /* get the serialized buffer and its length */ + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + } + /* validate the length of the stream */ + if (rc == 0) { + printf(" TPM_SaveState_NVStore: Require %u bytes\n", length); + if (length > TPM_MAX_SAVESTATE_SPACE) { + printf("TPM_SaveState_NVStore: Error, No space, need %u max %u\n", + length, TPM_MAX_SAVESTATE_SPACE); + rc = TPM_NOSPACE; + } + } + if (rc == 0) { + /* store the buffer in NVRAM */ + rc = TPM_NVRAM_StoreData(buffer, + length, + tpm_state->tpm_number, + TPM_SAVESTATE_NAME); + tpm_state->tpm_stany_flags.stateSaved = TRUE; /* mark the state as stored */ + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_SaveState_NVDelete() deletes the NV file + + If mustExist is TRUE, returns an error if the file does not exist. + If mustExist is FALSE, returns success if the file does not exist. +*/ + +TPM_RESULT TPM_SaveState_NVDelete(tpm_state_t *tpm_state, + TPM_BOOL mustExist) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SaveState_NVDelete:\n"); + if (rc == 0) { + /* remove the saved state */ + rc = TPM_NVRAM_DeleteName(tpm_state->tpm_number, + TPM_SAVESTATE_NAME, + mustExist); + tpm_state->tpm_stany_flags.stateSaved = FALSE; /* mark the state as deleted */ + } + return rc; +} + +/* Volatile state includes all the tpm_state structure volatile members. It is a superset of Saved + state, used when the entire TPM state must be saved and restored +*/ + +/* TPM_VolatileAll_Load() restores the TPM state from a stream created by TPM_VolatileAll_Store() + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_VolatileAll_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + TPM_PCR_ATTRIBUTES pcrAttrib[TPM_NUM_PCR]; + size_t i; + unsigned char *stream_start = *stream; /* copy for integrity check */ + uint32_t stream_size_start = *stream_size; + + printf(" TPM_VolatileAll_Load:\n"); + /* check format tag */ + /* In the future, if multiple formats are supported, this check will be replaced by a 'switch' + on the tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_VSTATE_V1, stream, stream_size); + } + /* compiled in TPM parameters */ + if (rc == 0) { + rc = TPM_Parameters_Load(stream, stream_size); + } + /* V1 is the TCG standard returned by the getcap. It's unlikely that this will change */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_STCLEAR_FLAGS_V1, stream, stream_size); + } + /* TPM_STCLEAR_FLAGS */ + if (rc == 0) { + rc = TPM_StclearFlags_Load(&(tpm_state->tpm_stclear_flags), stream, stream_size); + } + /* TPM_STANY_FLAGS */ + if (rc == 0) { + rc = TPM_StanyFlags_Load(&(tpm_state->tpm_stany_flags), stream, stream_size); + } + /* TPM_STCLEAR_DATA */ + /* normally, resettable PCRs are not restored. "All" means to restore everything */ + for (i = 0 ; (rc == 0) && (i < TPM_NUM_PCR) ; i++) { + pcrAttrib[i].pcrReset = FALSE; + } + /* TPM_STCLEAR_DATA */ + if (rc == 0) { + rc = TPM_StclearData_Load(&(tpm_state->tpm_stclear_data), stream, stream_size, + (TPM_PCR_ATTRIBUTES *)&pcrAttrib); + } + /* TPM_STANY_DATA */ + if (rc == 0) { + rc = TPM_StanyData_Load(&(tpm_state->tpm_stany_data), stream, stream_size); + } + /* TPM_KEY_HANDLE_ENTRY */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Load(tpm_state, stream, stream_size); + } + /* Context for SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Load: Loading SHA ordinal context\n"); + rc = TPM_Sha1Context_Load(&(tpm_state->sha1_context), stream, stream_size); + } + /* Context for TIS SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Load: Loading TIS context\n"); + rc = TPM_Sha1Context_Load(&(tpm_state->sha1_context_tis), stream, stream_size); + } + /* TPM_TRANSHANDLE */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_state->transportHandle), stream, stream_size); + } + /* testState */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_state->testState), stream, stream_size); + } + /* load the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_LoadVolatile(&(tpm_state->tpm_nv_index_entries), + stream, stream_size); + } + /* sanity check the stream size */ + if (rc == 0) { + if (*stream_size != TPM_DIGEST_SIZE) { + printf("TPM_VolatileAll_Load: Error (fatal) stream size %u not %u\n", + *stream_size, TPM_DIGEST_SIZE); + rc = TPM_FAIL; + } + } + /* check the integrity digest */ + if (rc == 0) { + printf(" TPM_VolatileAll_Load: Checking integrity digest\n"); + rc = TPM_SHA1_Check(*stream, /* currently points to integrity digest */ + stream_size_start - TPM_DIGEST_SIZE, stream_start, + 0, NULL); + } + /* remove the integrity digest from the stream */ + if (rc == 0) { + *stream_size -= TPM_DIGEST_SIZE; + } + return rc; +} + +/* TPM_VolatileAll_Store() stores the TPM state to a stream that can be restored through + TPM_VolatileAll_Load(). + + The two functions must be kept in sync. +*/ + +TPM_RESULT TPM_VolatileAll_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_PCR_ATTRIBUTES pcrAttrib[TPM_NUM_PCR]; + size_t i; + const unsigned char *buffer; /* elements of sbuffer */ + uint32_t length; + TPM_DIGEST tpm_digest; + + printf(" TPM_VolatileAll_Store:\n"); + /* overall format tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_VSTATE_V1); + } + /* compiled in TPM parameters */ + if (rc == 0) { + rc = TPM_Parameters_Store(sbuffer); + } + /* V1 is the TCG standard returned by the getcap. It's unlikely that this will change */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_STCLEAR_FLAGS_V1); + } + /* TPM_STCLEAR_FLAGS */ + if (rc == 0) { + rc = TPM_StclearFlags_Store(sbuffer, &(tpm_state->tpm_stclear_flags)); + } + /* TPM_STANY_FLAGS */ + if (rc == 0) { + rc = TPM_StanyFlags_Store(sbuffer, &(tpm_state->tpm_stany_flags)); + } + /* TPM_STCLEAR_DATA */ + /* normally, resettable PCRs are not restored. "All" means to restore everything */ + for (i = 0 ; (rc == 0) && (i < TPM_NUM_PCR) ; i++) { + pcrAttrib[i].pcrReset = FALSE; + } + /* TPM_STCLEAR_DATA */ + if (rc == 0) { + rc = TPM_StclearData_Store(sbuffer, &(tpm_state->tpm_stclear_data), + (TPM_PCR_ATTRIBUTES *)&pcrAttrib); + } + /* TPM_STANY_DATA */ + if (rc == 0) { + rc = TPM_StanyData_Store(sbuffer, &(tpm_state->tpm_stany_data)); + } + /* TPM_KEY_HANDLE_ENTRY */ + if (rc == 0) { + rc = TPM_KeyHandleEntries_Store(sbuffer, tpm_state); + } + /* Context for SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Store: Storing SHA ordinal context\n"); + rc = TPM_Sha1Context_Store(sbuffer, tpm_state->sha1_context); + } + /* Context for TIS SHA1 functions */ + if (rc == 0) { + printf(" TPM_VolatileAll_Store: Storing TIS context\n"); + rc = TPM_Sha1Context_Store(sbuffer, tpm_state->sha1_context_tis); + } + /* TPM_TRANSHANDLE */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_state->transportHandle); + } + /* testState */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_state->testState); + } + /* store the NV volatile flags */ + if (rc == 0) { + rc = TPM_NVIndexEntries_StoreVolatile(sbuffer, + &(tpm_state->tpm_nv_index_entries)); + } + if (rc == 0) { + /* get the current serialized buffer and its length */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + /* generate the integrity digest */ + rc = TPM_SHA1(tpm_digest, + length, buffer, + 0, NULL); + } + /* append the integrity digest to the stream */ + if (rc == 0) { + printf(" TPM_VolatileAll_Store: Appending integrity digest\n"); + rc = TPM_Sbuffer_Append(sbuffer, tpm_digest, TPM_DIGEST_SIZE); + } + return rc; +} + +/* TPM_VolatileAll_NVLoad() deserializes the entire volatile state data from the NV file + TPM_VOLATILESTATE_NAME. + + If the file does not exist (a normal startup), returns success. + + 0 on success or non-existant file + TPM_FAIL on failure to load (fatal), since it should never occur +*/ + +TPM_RESULT TPM_VolatileAll_NVLoad(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_BOOL done = FALSE; + unsigned char *stream = NULL; + unsigned char *stream_start = NULL; + uint32_t stream_size; + + printf(" TPM_VolatileAll_NVLoad:\n"); + if (rc == 0) { + /* load from NVRAM. Returns TPM_RETRY on non-existent file. */ + rc = TPM_NVRAM_LoadData(&stream, /* freed @1 */ + &stream_size, + tpm_state->tpm_number, + TPM_VOLATILESTATE_NAME); + /* if the file does not exist, leave the volatile state initial values */ + if (rc == TPM_RETRY) { + done = TRUE; + rc = 0; + } + else if (rc != 0) { + printf("TPM_VolatileAll_NVLoad: Error (fatal) loading %s\n", TPM_VOLATILESTATE_NAME); + rc = TPM_FAIL; + } + } + /* deserialize from stream */ + if ((rc == 0) && !done) { + stream_start = stream; /* save starting point for free() */ + rc = TPM_VolatileAll_Load(tpm_state, &stream, &stream_size); + if (rc != 0) { + printf("TPM_VolatileAll_NVLoad: Error (fatal) loading deserializing state\n"); + rc = TPM_FAIL; + } + } + if (rc != 0) { + printf(" TPM_VolatileAll_NVLoad: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + + } + free(stream_start); /* @1 */ + return rc; +} + +/* TPM_VolatileAll_NVStore() serializes the entire volatile state data and stores it in the NV file + TPM_VOLATILESTATE_NAME +*/ + +TPM_RESULT TPM_VolatileAll_NVStore(tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* safe buffer for storing binary data */ + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_VolatileAll_NVStore:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize relevant data from tpm_state to be written to NV */ + if (rc == 0) { + rc = TPM_VolatileAll_Store(&sbuffer, tpm_state); + /* get the serialized buffer and its length */ + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + } + /* validate the length of the stream */ + if (rc == 0) { + printf(" TPM_VolatileAll_NVStore: Require %u bytes\n", length); + if (length > TPM_MAX_VOLATILESTATE_SPACE) { + printf("TPM_VolatileAll_NVStore: Error, No space, need %u max %u\n", + length, TPM_MAX_VOLATILESTATE_SPACE); + rc = TPM_NOSPACE; + } + } + if (rc == 0) { + /* store the buffer in NVRAM */ + rc = TPM_NVRAM_StoreData(buffer, + length, + tpm_state->tpm_number, + TPM_VOLATILESTATE_NAME); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + Compiled in TPM Parameters +*/ + +TPM_RESULT TPM_Parameters_Load(unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Parameters_Load:\n"); + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_TPM_PARAMETERS_V1, + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check8(TPM_MAJOR, "TPM_MAJOR", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check8(TPM_MINOR, "TPM_MINOR", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_PCCLIENT, "TPM_PCCLIENT", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_NUM_PCR, "TPM_NUM_PCR", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_RSA_KEY_LENGTH_MAX, "TPM_RSA_KEY_LENGTH_MAX", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_KEY_HANDLES, "TPM_KEY_HANDLES", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_OWNER_EVICT_KEY_HANDLES, "TPM_OWNER_EVICT_KEY_HANDLES", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_NUM_FAMILY_TABLE_ENTRY_MIN, + "TPM_NUM_FAMILY_TABLE_ENTRY_MIN", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_NUM_DELEGATE_TABLE_ENTRY_MIN, + "TPM_NUM_DELEGATE_TABLE_ENTRY_MIN", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_AUTH_SESSIONS, "TPM_MIN_AUTH_SESSIONS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_TRANS_SESSIONS, "TPM_MIN_TRANS_SESSIONS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_DAA_SESSIONS, "TPM_MIN_DAA_SESSIONS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_COUNTERS, "TPM_MIN_COUNTERS", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check16(TPM_MIN_SESSION_LIST, "TPM_MIN_SESSION_LIST", + stream, stream_size); + } + if (rc == 0) { + rc = TPM_Parameters_Check32(TPM_MAX_NV_SPACE, "TPM_MAX_NV_SPACE", + stream, stream_size); + } + return rc; +} + +TPM_RESULT TPM_Parameters_Check8(uint8_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint8_t tmp8; + + if (rc == 0) { + rc = TPM_Load8(&tmp8, stream, stream_size); + if (tmp8 != expected) { + printf("TPM_Parameters_Check8: Error (fatal) %s received %u expect %u\n", + parameter, tmp8, expected); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_Parameters_Check16(uint16_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint16_t tmp16; + + if (rc == 0) { + rc = TPM_Load16(&tmp16, stream, stream_size); + if (tmp16 != expected) { + printf("TPM_Parameters_Check16: Error (fatal) %s received %u expect %u\n", + parameter, tmp16, expected); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_Parameters_Check32(uint32_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t tmp32; + + if (rc == 0) { + rc = TPM_Load32(&tmp32, stream, stream_size); + if (tmp32 != expected) { + printf("TPM_Parameters_Check32: Error (fatal) %s received %u expect %u\n", + parameter, tmp32, expected); + rc = TPM_FAIL; + } + } + return rc; +} + +TPM_RESULT TPM_Parameters_Store(TPM_STORE_BUFFER *sbuffer) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Parameters_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TPM_PARAMETERS_V1); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append8(sbuffer, TPM_MAJOR); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append8(sbuffer, TPM_MINOR); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_PCCLIENT); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_NUM_PCR); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_RSA_KEY_LENGTH_MAX); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_KEY_HANDLES); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_OWNER_EVICT_KEY_HANDLES); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_NUM_FAMILY_TABLE_ENTRY_MIN); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_NUM_DELEGATE_TABLE_ENTRY_MIN); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_AUTH_SESSIONS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_TRANS_SESSIONS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_DAA_SESSIONS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_COUNTERS); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_MIN_SESSION_LIST); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, TPM_MAX_NV_SPACE); + } + return rc; +} + + +/* 27.5 TPM_Reset rev 105 + + Releases all resources associated with existing authorization sessions. This is useful if a TSS + driver has lost track of the state in the TPM. + + This is a deprecated command in V1.2. This command in 1.1 only referenced authorization sessions + and is not upgraded to affect any other TPM entity in 1.2 +*/ + +TPM_RESULT TPM_Process_Reset(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_Reset: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Reset: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. The TPM invalidates all resources allocated to authorization sessions as per version 1.1 + extant in the TPM */ + /* a. This includes structures created by TPM_SaveAuthContext and TPM_SaveKeyContext */ + /* b.The TPM MUST invalidate OSAP sessions */ + /* c.The TPM MAY invalidate DSAP sessions */ + /* d. The TPM MUST NOT invalidate structures created by TPM_SaveContext */ + if (returnCode == TPM_SUCCESS) { + TPM_StclearData_AuthSessionDelete(&(tpm_state->tpm_stclear_data)); + } + /* 2. The TPM does not reset any PCR or DIR values. */ + /* 3. The TPM does not reset any flags in the TPM_STCLEAR_FLAGS structure. */ + /* 4. The TPM does not reset or invalidate any keys */ + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_Reset: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 3.2 TPM_Startup rev 101 + + TPM_Startup is always preceded by TPM_Init, which is the physical indication (a system-wide + reset) that TPM initialization is necessary. + + There are many events on a platform that can cause a reset and the response to these events can + require different operations to occur on the TPM. The mere reset indication does not contain + sufficient information to inform the TPM as to what type of reset is occurring. Additional + information known by the platform initialization code needs transmitting to the TPM. The + TPM_Startup command provides the mechanism to transmit the information. + + The TPM can startup in three different modes: + + A "clear" start where all variables go back to their default or non-volatile set state + + A "save" start where the TPM recovers appropriate information and restores various values based + on a prior TPM_SaveState. This recovery requires an invocation of TPM_Init to be successful. + + A failing "save" start must shut down the TPM. The CRTM cannot leave the TPM in a state where an + untrusted upper software layer could issue a "clear" and then extend PCR's and thus mimic the + CRTM. + + A "deactivated" start where the TPM turns itself off and requires another TPM_Init before the TPM + will execute in a fully operational state. The TPM can startup in three different modes: +*/ + +TPM_RESULT TPM_Process_Startup(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + TPM_RESULT returnCode1 = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_STARTUP_TYPE startupType; + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_Startup: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get startupType parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load16(&startupType, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Startup: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* TPM_CheckState() can check for the normal case where postInitialise TRUE is an error. This + is the only command where FALSE is the error. */ + if (returnCode == TPM_SUCCESS) { + /* 1. If TPM_STANY_FLAGS -> postInitialise is FALSE, */ + if (!(tpm_state->tpm_stany_flags.postInitialise)) { + /* a. Then the TPM MUST return TPM_INVALID_POSTINIT, and exit this capability */ + printf("TPM_Process_Startup: Error, postInitialise is FALSE\n"); + returnCode = TPM_INVALID_POSTINIT; + } + } + if (returnCode == TPM_SUCCESS) { + /* 1. If the TPM is in failure mode */ + if (tpm_state->testState == TPM_TEST_STATE_FAILURE) { + /* a. TPM_STANY_FLAGS -> postInitialize is still set to FALSE */ + tpm_state->tpm_stany_flags.postInitialise = FALSE; + printf("TPM_Process_Startup: Error, shutdown is TRUE\n"); + /* b. The TPM returns TPM_FAILEDSELFTEST */ + returnCode = TPM_FAILEDSELFTEST; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + switch (startupType) { + case TPM_ST_CLEAR: /* The TPM is starting up from a clean state */ + returnCode = TPM_Startup_Clear(tpm_state); + break; + case TPM_ST_STATE: /* The TPM is starting up from a saved state */ + returnCode = TPM_Startup_State(tpm_state); + break; + case TPM_ST_DEACTIVATED: /* The TPM is to startup and set the deactivated flag to + TRUE */ + returnCode = TPM_Startup_Deactivated(tpm_state); + break; + default: + returnCode = TPM_BAD_PARAMETER; + break; + } + } + /* TPM_STANY_FLAGS MUST reset on TPM_Startup(any) */ + if (returnCode == TPM_SUCCESS) { + TPM_StanyFlags_Init(&(tpm_state->tpm_stany_flags)); + } + /* 5. The TPM MUST ensure that state associated with TPM_SaveState is invalidated */ + returnCode1 = TPM_SaveState_NVDelete(tpm_state, + FALSE); /* Ignore errors if the state does not + exist. */ + if (returnCode == TPM_SUCCESS) { /* previous error takes precedence */ + returnCode = returnCode1; + } + /* 6. The TPM MUST set TPM_STANY_FLAGS -> postInitialise to FALSE */ + tpm_state->tpm_stany_flags.postInitialise = FALSE; + /* + response + */ + if (rcf == 0) { + printf("TPM_Process_Startup: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + return rcf; +} + +/* 3.2 TPM_Startup(TPM_ST_CLEAR) rev 99 +*/ + +TPM_RESULT TPM_Startup_Clear(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_Clear:\n"); + /* 2. If stType = TPM_ST_CLEAR */ + if (returnCode == TPM_SUCCESS) { + /* a. Ensure that sessions associated with resources TPM_RT_CONTEXT, TPM_RT_AUTH, + TPM_RT_DAA_TPM, and TPM_RT_TRANS are invalidated */ + /* NOTE TPM_RT_CONTEXT - + contextNonceKey cleared by TPM_Global_Init() -> TPM_StanyData_Init() + contextNonceSession cleared by TPM_Global_Init() -> TPM_StanyData_Init() + */ + /* NOTE TPM_RT_AUTH - TPM_AuthSessions_Init() called by TPM_Global_Init() -> + TPM_StanyData_Init() */ + /* TPM_RT_TRANS - TPM_TransportSessions_Init() called by TPM_Global_Init() -> + TPM_StanyData_Init()*/ + /* TPM_RT_DAA_TPM - TPM_DaaSessions_Init() called by TPM_Global_Init() -> + TPM_StanyData_Init()*/ + /* b. Reset PCR values to each correct default value */ + /* i. pcrReset is FALSE, set to 0x00..00 */ + /* ii. pcrReset is TRUE, set to 0xFF..FF */ + /* NOTE done by TPM_MainInit() -> TPM_Global_Init() */ + /* c. Set the following TPM_STCLEAR_FLAGS to their default state + i. PhysicalPresence + ii. PhysicalPresenceLock + iii. disableForceClear + */ + /* NOTE Done by TPM_Global_Init() -> TPM_StclearFlags_Init() */ + /* d. The TPM MAY initialize auditDigest to all zeros + i. If not initialized to all zeros the TPM SHALL ensure that auditDigest contains a valid + value + ii. If initialization fails the TPM SHALL set auditDigest to all zeros and SHALL set the + internal TPM state so that the TPM returns TPM_FAILEDSELFTEST to all subsequent + commands. + */ + /* NOTE Done by TPM_Global_Init() ->TPM_StanyData_Init() */ + /* e. The TPM SHALL set TPM_STCLEAR_FLAGS -> deactivated to the same state as + TPM_PERMANENT_FLAGS -> deactivated + */ + tpm_state->tpm_stclear_flags.deactivated = tpm_state->tpm_permanent_flags.deactivated; + /* f. The TPM MUST set the TPM_STANY_DATA fields to: */ + /* i. TPM_STANY_DATA->contextNonceSession is set to all zeros */ + /* ii. TPM_STANY_DATA->contextCount is set to 0 */ + /* iii. TPM_STANY_DATA->contextList is set to 0 */ + /* NOTE Done by TPM_Global_Init() ->TPM_StanyData_Init() */ + /* g. The TPM MUST set TPM_STCLEAR_DATA fields to: */ + /* i. Invalidate contextNonceKey */ + /* ii. countID to zero */ + /* iii. OwnerReference to TPM_KH_OWNER */ + /* NOTE Done by TPM_Global_Init() -> TPM_StclearData_Init() */ + /* h. The TPM MUST set the following TPM_STCLEAR_FLAGS to */ + /* i. bGlobalLock to FALSE */ + /* NOTE Done by TPM_Global_Init() -> TPM_StclearFlags_Init() */ + /* i. Determine which keys should remain in the TPM */ + /* i. For each key that has a valid preserved value in the TPM */ + /* (1) if parentPCRStatus is TRUE then call TPM_FlushSpecific(keyHandle) */ + /* (2) if isVolatile is TRUE then call TPM_FlushSpecific(keyHandle) */ + /* NOTE Since TPM_Global_Init() calls TPM_KeyHandleEntries_Init(), there are no keys + remaining. Since this TPM implementation loads keys into volatile memory, not NVRAM, no + keys are preserved at ST_CLEAR. */ + /* ii. Keys under control of the OwnerEvict flag MUST stay resident in the TPM */ + /* NOTE Done by TPM_PermanentAll_NVLoad() */ + /* bReadSTClear and bWriteSTClear are volatile, in that they are set FALSE at + TPM_Startup(ST_Clear) */ + TPM_NVIndexEntries_StClear(&(tpm_state->tpm_nv_index_entries)); + } + return returnCode; +} + +/* 3.2 TPM_Startup(TPM_ST_STATE) rev 100 + */ + +TPM_RESULT TPM_Startup_State(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_State:\n"); + if (returnCode == TPM_SUCCESS) { + /* a. If the TPM has no state to restore the TPM MUST set the internal state such that it + returns TPM_FAILEDSELFTEST to all subsequent commands */ + /* b. The TPM MAY determine for each session type (authorization, transport, DAA, ...) to + release or maintain the session information. The TPM reports how it manages sessions in + the TPM_GetCapability command. */ + /* c. The TPM SHALL take all necessary actions to ensure that all PCRs contain valid + preserved values. If the TPM is unable to successfully complete these actions, it SHALL + enter the TPM failure mode. */ + /* i. For resettable PCR the TPM MUST set the value of TPM_STCLEAR_DATA -> PCR[] to the + resettable PCR default value. The TPM MUST NOT restore a resettable PCR to a preserved + value */ + /* d. The TPM MAY initialize auditDigest to all zeros */ + /* i. Otherwise, the TPM SHALL take all actions necessary to ensure that auditDigest + contains a valid value. If the TPM is unable to successfully complete these actions, the + TPM SHALL initialize auditDigest to all zeros and SHALL set the internal state such that + the TPM returns TPM_FAILEDSELFTEST to all subsequent commands. */ + /* e. The TPM MUST restore the following flags to their preserved states: */ + /* i. All values in TPM_STCLEAR_FLAGS */ + /* ii. All values in TPM_STCLEAR_DATA */ + /* f. The TPM MUST restore all keys that have a valid preserved value */ + /* NOTE Owner evict keys are loaded at TPM_PermanentAll_NVLoad() */ + returnCode = TPM_SaveState_NVLoad(tpm_state); /* returns TPM_RETRY on non-existent file */ + } + /* g. The TPM resumes normal operation. If the TPM is unable to resume normal operation, it + SHALL enter the TPM failure mode. */ + if (returnCode != TPM_SUCCESS) { + printf("TPM_Startup_State: Error restoring state\n"); + returnCode = TPM_FAILEDSELFTEST; + printf(" TPM_Startup_State: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return returnCode; +} + +/* 3.2 TPM_Startup(TPM_ST_DEACTIVATED) rev 97 + */ + +TPM_RESULT TPM_Startup_Deactivated(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_Deactivated:\n"); + if (returnCode == TPM_SUCCESS) { + /* a. Invalidate sessions */ + /* i. Ensure that all resources associated with saved and active sessions are invalidated */ + /* NOTE Done at TPM_MainInit() */ + /* b. The TPM MUST set TPM_STCLEAR_FLAGS -> deactivated to TRUE */ + tpm_state->tpm_stclear_flags.deactivated = TRUE; + } + return returnCode; +} + +/* TPM_Startup_Any() rev 96 + + Handles Actions common to all TPM_Startup options. +*/ + +TPM_RESULT TPM_Startup_Any(tpm_state_t *tpm_state) +{ + TPM_RESULT returnCode = TPM_SUCCESS; + + printf("TPM_Startup_Any:\n"); + /* TPM_STANY_FLAGS MUST reset on TPM_Startup(any) */ + TPM_StanyFlags_Init(&(tpm_state->tpm_stany_flags)); + /* 5. The TPM MUST ensure that state associated with TPM_SaveState is invalidated */ + returnCode = TPM_SaveState_NVDelete(tpm_state, + FALSE); /* Ignore errors if the state does not exist. */ + /* 6. The TPM MUST set TPM_STANY_FLAGS -> postInitialise to FALSE */ + tpm_state->tpm_stany_flags.postInitialise = FALSE; + return returnCode; +} + +/* 3.3 TPM_SaveState rev 111 + + 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 TPM enters a low or no power state. + + Resettable PCRs are tied to platform state that does not survive a sleep state. If the PCRs did + not reset, they would falsely indicate that the platform state was already present when it came + out of sleep. Since some setup is required first, there would be a gap where PCRs indicated the + wrong state. Therefore, the PCRs must be recreated. +*/ + +TPM_RESULT TPM_Process_SaveState(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_SaveState: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, (TPM_CHECK_NOT_SHUTDOWN | + TPM_CHECK_NO_LOCKOUT)); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_SaveState: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + /* 1. Preserved values MUST be non-volatile. */ + /* 2. If data is never stored in a volatile medium, that data MAY be used as preserved data. In + such cases, no explicit action may be required to preserve that data. */ + /* 3. If an explicit action is required to preserve data, it MUST be possible for the TPM to + determine whether preserved data is valid. */ + /* 4. If the parameter mirrored by a preserved value is altered, all preserved values MUST be + declared invalid. */ + if (returnCode == TPM_SUCCESS) { + /* Determine if TPM_SaveState was called from within a transport session. The TPM MAY save + transport sessions as part of the saved state. Since this TPM implements that option, + there's no point in saving the state, because it would be immediately invalidated during + the transport response. Return an error to indicate that the state was not saved. */ + if (transportInternal != NULL) { + printf("TPM_Process_SaveState: Error, called from transport session\n"); + returnCode = TPM_NO_WRAP_TRANSPORT; + } + } + /* Audit Generation Corner cases 3.a. TPM_SaveState: Only the input parameters are audited, and + the audit occurs before the state is saved. If an error occurs while or after the state is + saved, the audit still occurs. + */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* 5. The TPM MAY declare all preserved value is invalid in response to any command other that + TPM_Init. */ + /* NOTE Done by TPM_GetInParamDigest(), which is called by all ordinals */ + /* 1. Store TPM_STCLEAR_DATA -> PCR contents except for */ + /* a. If the PCR attribute pcrReset is TRUE */ + /* b. Any platform identified debug PCR */ + /* 2. The auditDigest MUST be handled according to the audit requirements as reported by + TPM_GetCapability */ + /* a. If the ordinalAuditStatus is TRUE for the TPM_SaveState ordinal and the auditDigest is + being stored in the saved state, the saved auditDigest MUST include the TPM_SaveState input + parameters and MUST NOT include the output parameters. */ + /* 3. All values in TPM_STCLEAR_DATA MUST be preserved */ + /* 4. All values in TPM_STCLEAR_FLAGS MUST be preserved */ + /* 5. The contents of any key that is currently loaded SHOULD be preserved if the key's + parentPCRStatus indicator is TRUE. */ + /* 6. The contents of any key that has TPM_KEY_CONTROL_OWNER_EVICT set MUST be preserved */ + /* 7. The contents of any key that is currently loaded MAY be preserved */ + /* 8. The contents of sessions (authorization, transport, DAA etc.) MAY be preserved as reported + by TPM_GetCapability */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SaveState_NVStore(tpm_state); + } + /* store the state in NVRAM */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_SaveState: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* Special case, no output parameter audit */ + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} diff --git a/src/tpm_startup.h b/src/tpm_startup.h new file mode 100644 index 00000000..61044cf6 --- /dev/null +++ b/src/tpm_startup.h @@ -0,0 +1,134 @@ +/********************************************************************************/ +/* */ +/* TPM Admin Startup and State */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_startup.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_STARTUP_H +#define TPM_STARTUP_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_types.h" + +/* + Startup +*/ + +TPM_RESULT TPM_Startup_Clear(tpm_state_t *tpm_state); +TPM_RESULT TPM_Startup_State(tpm_state_t *tpm_state); +TPM_RESULT TPM_Startup_Deactivated(tpm_state_t *tpm_state); +TPM_RESULT TPM_Startup_Any(tpm_state_t *tpm_state); + +/* + Save State +*/ + +TPM_RESULT TPM_SaveState_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_SaveState_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state); + +TPM_RESULT TPM_SaveState_NVLoad(tpm_state_t *tpm_state); +TPM_RESULT TPM_SaveState_NVStore(tpm_state_t *tpm_state); +TPM_RESULT TPM_SaveState_NVDelete(tpm_state_t *tpm_state, + TPM_BOOL mustExist); + +void TPM_SaveState_IsSaveKey(TPM_BOOL *save, + TPM_KEY_HANDLE_ENTRY *tpm_key_handle_entry); + +/* + Volatile State +*/ + +TPM_RESULT TPM_VolatileAll_Load(tpm_state_t *tpm_state, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_VolatileAll_Store(TPM_STORE_BUFFER *sbuffer, + tpm_state_t *tpm_state); +TPM_RESULT TPM_VolatileAll_NVLoad(tpm_state_t *tpm_state); +TPM_RESULT TPM_VolatileAll_NVStore(tpm_state_t *tpm_state); + +/* + Compiled in TPM Parameters +*/ + +TPM_RESULT TPM_Parameters_Load(unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Parameters_Store(TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_Parameters_Check8(uint8_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Parameters_Check16(uint16_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Parameters_Check32(uint32_t expected, + const char *parameter, + unsigned char **stream, + uint32_t *stream_size); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_Reset(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_Startup(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +TPM_RESULT TPM_Process_SaveState(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +#endif diff --git a/src/tpm_storage.c b/src/tpm_storage.c new file mode 100644 index 00000000..64743e6a --- /dev/null +++ b/src/tpm_storage.c @@ -0,0 +1,3591 @@ +/********************************************************************************/ +/* */ +/* Storage Functions */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_storage.c 4442 2011-02-14 20:20:01Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_cryptoh.h" +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_io.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_pcr.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_structures.h" +#include "tpm_ver.h" + +#include "tpm_storage.h" + +/* local function prototypes */ + +static TPM_RESULT TPM_SealCryptCommon(BYTE **o1, + TPM_ADIP_ENC_SCHEME adipEncScheme, + TPM_SIZED_BUFFER *inData, + TPM_AUTH_SESSION_DATA *auth_session_data, + TPM_NONCE nonceOdd); + +static TPM_RESULT TPM_LoadKeyCommon(TPM_KEY_HANDLE *inKeyHandle, + TPM_BOOL *key_added, + TPM_SECRET **hmacKey, + TPM_AUTH_SESSION_DATA **auth_session_data, + tpm_state_t *tpm_state, + TPM_TAG tag, + TPM_COMMAND_CODE ordinal, + TPM_KEY_HANDLE parentHandle, + TPM_KEY *inKey, + TPM_DIGEST inParamDigest, + TPM_AUTHHANDLE authHandle, + TPM_NONCE nonceOdd, + TPM_BOOL continueAuthSession, + TPM_AUTHDATA parentAuth); + +/* + TPM_BOUND_DATA +*/ + +/* TPM_BoundData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_BoundData_Init(TPM_BOUND_DATA *tpm_bound_data) +{ + printf(" TPM_BoundData_Init:\n"); + TPM_StructVer_Init(&(tpm_bound_data->ver)); + tpm_bound_data->payload = TPM_PT_BIND; + tpm_bound_data->payloadDataSize = 0; + tpm_bound_data->payloadData = NULL; + return; +} + +/* TPM_BoundData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_BoundData_Init() + After use, call TPM_BoundData_Delete() to free memory +*/ + +TPM_RESULT TPM_BoundData_Load(TPM_BOUND_DATA *tpm_bound_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_BoundData_Load:\n"); + if (rc == 0) { + rc = TPM_StructVer_Load(&(tpm_bound_data->ver), stream, stream_size); + } + /* check ver immediately to ease debugging */ + if (rc == 0) { + rc = TPM_StructVer_CheckVer(&(tpm_bound_data->ver)); + } + if (rc == 0) { + rc = TPM_Load8(&(tpm_bound_data->payload), stream, stream_size); + } + if ((rc == 0) && (*stream_size > 0)){ + /* There is no payloadData size in the serialized data. Assume it consumes the rest of the + stream */ + tpm_bound_data->payloadDataSize = *stream_size; + rc = TPM_Malloc(&(tpm_bound_data->payloadData), tpm_bound_data->payloadDataSize); + } + if ((rc == 0) && (*stream_size > 0)){ + memcpy(tpm_bound_data->payloadData, *stream, tpm_bound_data->payloadDataSize); + *stream += tpm_bound_data->payloadDataSize; + *stream_size -= tpm_bound_data->payloadDataSize; + } + return rc; +} + +/* TPM_BoundData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + This structure serialization assumes that the payloadDataSize member indicates the size of + payloadData. +*/ + +TPM_RESULT TPM_BoundData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_BOUND_DATA *tpm_bound_data) +{ + TPM_RESULT rc = 0; + + printf(" TPM_BoundData_Store:\n"); + if (rc == 0) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_bound_data->ver)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_bound_data->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, tpm_bound_data->payloadData, + tpm_bound_data->payloadDataSize); + } + return rc; +} + +/* TPM_BoundData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the bound_data + sets pointers to NULL + calls TPM_BoundData_Init to set members back to default values + The bound_data itself is not freed +*/ + +void TPM_BoundData_Delete(TPM_BOUND_DATA *tpm_bound_data) +{ + printf(" TPM_BoundData_Delete:\n"); + if (tpm_bound_data != NULL) { + free(tpm_bound_data->payloadData); + TPM_BoundData_Init(tpm_bound_data); + } + return; +} + +/* + TPM_SEALED_DATA +*/ + +/* TPM_SealedData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_SealedData_Init(TPM_SEALED_DATA *tpm_sealed_data) +{ + printf(" TPM_SealedData_Init:\n"); + tpm_sealed_data->payload = TPM_PT_SEAL; + TPM_Secret_Init(tpm_sealed_data->authData); + TPM_Secret_Init(tpm_sealed_data->tpmProof); + TPM_Digest_Init(tpm_sealed_data->storedDigest); + TPM_SizedBuffer_Init(&(tpm_sealed_data->data)); + return; +} + +/* TPM_SealedData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_SealedData_Init() + After use, call TPM_SealedData_Delete() to free memory +*/ + +TPM_RESULT TPM_SealedData_Load(TPM_SEALED_DATA *tpm_sealed_data, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_SealedData_Load:\n"); + /* load payload */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_sealed_data->payload), stream, stream_size); + } + /* load authData */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_sealed_data->authData, stream, stream_size); + } + /* load tpmProof */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_sealed_data->tpmProof, stream, stream_size); + } + /* load storedDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_sealed_data->storedDigest, stream, stream_size); + } + /* load dataSize and data */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_sealed_data->data), stream, stream_size); + } + return rc; +} + +/* TPM_SealedData_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_SealedData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SEALED_DATA *tpm_sealed_data) +{ + TPM_RESULT rc = 0; + printf(" TPM_SealedData_Store:\n"); + /* store payload */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_sealed_data->payload), sizeof(TPM_PAYLOAD_TYPE)); + } + /* store authData */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_sealed_data->authData); + } + /* store tpmProof */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_sealed_data->tpmProof); + } + /* store storedDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_sealed_data->storedDigest); + } + /* store dataSize and data */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_sealed_data->data)); + } + return rc; +} + +/* TPM_SealedData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_SealedData_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_SealedData_Delete(TPM_SEALED_DATA *tpm_sealed_data) +{ + printf(" TPM_SealedData_Delete:\n"); + if (tpm_sealed_data != NULL) { + TPM_SizedBuffer_Delete(&(tpm_sealed_data->data)); + TPM_SealedData_Init(tpm_sealed_data); + } + return; +} + +/* TPM_SealedData_GenerateEncData() generates an enc_data structure by serializing the + TPM_SEALED_DATA structure and encrypting the result using the public key. +*/ + +TPM_RESULT TPM_SealedData_GenerateEncData(TPM_SIZED_BUFFER *enc_data, + const TPM_SEALED_DATA *tpm_sealed_data, + TPM_KEY *tpm_key) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_SEALED_DATA serialization */ + + printf(" TPM_SealedData_GenerateEncData\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_SEALED_DATA */ + if (rc == 0) { + rc = TPM_SealedData_Store(&sbuffer, tpm_sealed_data); + } + /* encrypt the TPM_SEALED_DATA serialization buffer with the public key, and place + the result in the encData members */ + if (rc == 0) { + rc = TPM_RSAPublicEncryptSbuffer_Key(enc_data, &sbuffer, tpm_key); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* TPM_SealedData_DecryptEncData() decrypts the enc_data using the private key. The + result is deserialized and stored in the TPM_SEALED_DATA structure. + +*/ + +TPM_RESULT TPM_SealedData_DecryptEncData(TPM_SEALED_DATA *tpm_sealed_data, /* result */ + TPM_SIZED_BUFFER *enc_data, /* encrypted input */ + TPM_KEY *tpm_key) /* key for decrypting */ +{ + TPM_RESULT rc = 0; + unsigned char *decryptData = NULL; /* freed @1 */ + uint32_t decryptDataLength = 0; /* actual valid data */ + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_SealedData_DecryptEncData:\n"); + /* allocate space for the decrypted data */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptMalloc(&decryptData, /* decrypted data */ + &decryptDataLength, /* actual size of decrypted data */ + enc_data->buffer, /* encrypted data */ + enc_data->size, /* encrypted data size */ + tpm_key); + } + /* load the TPM_SEALED_DATA structure from the decrypted data stream */ + if (rc == 0) { + /* use temporary variables, because TPM_SealedData_Load() moves the stream */ + stream = decryptData; + stream_size = decryptDataLength; + rc = TPM_SealedData_Load(tpm_sealed_data, &stream, &stream_size); + } + free(decryptData); /* @1 */ + return rc; +} + + +/* + TPM_STORED_DATA +*/ + +/* TPM_StoredData_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StoredData_Init(TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + printf(" TPM_StoredData_Init: v%u\n", version); + if (version == 1) { + TPM_StructVer_Init(&(tpm_stored_data->ver)); + } + else { + ((TPM_STORED_DATA12 *)tpm_stored_data)->tag = TPM_TAG_STORED_DATA12; + ((TPM_STORED_DATA12 *)tpm_stored_data)->et = 0x0000; + } + TPM_SizedBuffer_Init(&(tpm_stored_data->sealInfo)); + TPM_SizedBuffer_Init(&(tpm_stored_data->encData)); + tpm_stored_data->tpm_seal_info = NULL; + return; +} + +/* TPM_StoredData_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_StoredData_Init() + After use, call TPM_StoredData_Delete() to free memory + + This function handles both TPM_STORED_DATA and TPM_STORED_DATA12 and returns the 'version'. +*/ + +TPM_RESULT TPM_StoredData_Load(TPM_STORED_DATA *tpm_stored_data, + unsigned int *version, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + /* Peek at the first byte to guess the version number. The data is verified later. + TPM_STORED_DATA is 01,01,00,00 TPM_STORED_DATA12 is 00,16,00,00 */ + if ((rc == 0) && (*stream_size > 0)) { + if (**stream == 0x01) { + *version = 1; + } + else { + *version = 2; + } + printf(" TPM_StoredData_Load: v%u\n", *version); + } + /* 1.1 load ver */ + if ((rc == 0) && (*version == 1)) { + rc = TPM_StructVer_Load(&(tpm_stored_data->ver), stream, stream_size); + } + /* 1.2 load tag */ + if ((rc == 0) && (*version != 1)) { + rc = TPM_Load16(&(((TPM_STORED_DATA12 *)tpm_stored_data)->tag), stream, stream_size); + } + /* 1.2 load et */ + if ((rc == 0) && (*version != 1)) { + rc = TPM_Load16(&(((TPM_STORED_DATA12 *)tpm_stored_data)->et), stream, stream_size); + } + /* check the TPM_STORED_DATA structure version */ + if ((rc == 0) && (*version == 1)) { + rc = TPM_StructVer_CheckVer(&(tpm_stored_data->ver)); + } + /* check the TPM_STORED_DATA12 structure tag */ + if ((rc == 0) && (*version != 1)) { + rc = TPM_StoredData_CheckTag((TPM_STORED_DATA12 *)tpm_stored_data); + } + /* load sealInfoSize and sealInfo */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_stored_data->sealInfo), stream, stream_size); + } + /* load the TPM_PCR_INFO or TPM_PCR_INFO_LONG cache */ + if (rc == 0) { + if (*version == 1) { + rc = TPM_PCRInfo_CreateFromBuffer(&(tpm_stored_data->tpm_seal_info), + &(tpm_stored_data->sealInfo)); + } + else { + rc = TPM_PCRInfoLong_CreateFromBuffer + (&(((TPM_STORED_DATA12 *)tpm_stored_data)->tpm_seal_info_long), + &(tpm_stored_data->sealInfo)); + } + } + /* load encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Load(&(tpm_stored_data->encData), stream, stream_size); + } + return rc; +} + +/* TPM_StoredData_StoreClearData() serializes a TPM_STORED_DATA structure, excluding encData, + appending results to 'sbuffer'. + + Before serializing, it serializes tpm_seal_info to sealInfoSize and sealInfo. + + This function handles both TPM_STORED_DATA and TPM_STORED_DATA12. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StoredData_StoreClearData(TPM_STORE_BUFFER *sbuffer, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoredData_StoreClearData: v%u\n", version); + /* 1.1 store ver */ + if ((rc == 0) && (version == 1)) { + rc = TPM_StructVer_Store(sbuffer, &(tpm_stored_data->ver)); + } + /* 1.2 store tag */ + if ((rc == 0) && (version != 1)) { + rc = TPM_Sbuffer_Append16(sbuffer, ((TPM_STORED_DATA12 *)tpm_stored_data)->tag); + } + /* 1.2 store et */ + if ((rc == 0) && (version != 1)) { + rc = TPM_Sbuffer_Append16(sbuffer, ((TPM_STORED_DATA12 *)tpm_stored_data)->et); + } + /* store sealInfoSize and sealInfo */ + if (rc == 0) { + /* copy cache to sealInfoSize and sealInfo */ + if (version == 1) { + rc = TPM_SizedBuffer_SetStructure(&(tpm_stored_data->sealInfo), + tpm_stored_data->tpm_seal_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfo_Store); + } + else { + rc = TPM_SizedBuffer_SetStructure(&(tpm_stored_data->sealInfo), + tpm_stored_data->tpm_seal_info, + (TPM_STORE_FUNCTION_T)TPM_PCRInfoLong_Store); + } + } + /* copy sealInfoSize and sealInfo to sbuffer */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_stored_data->sealInfo)); + } + return rc; +} + +/* TPM_StoredData_Store() + + Before serializing, it serializes tpm_seal_info to sealInfoSize and sealInfo. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StoredData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoredData_Store: v%u\n", version); + if (rc == 0) { + rc = TPM_StoredData_StoreClearData(sbuffer, tpm_stored_data, version); + } + /* store encDataSize and encData */ + if (rc == 0) { + rc = TPM_SizedBuffer_Store(sbuffer, &(tpm_stored_data->encData)); + } + return rc; +} + +/* TPM_StoredData_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_StoredData_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_StoredData_Delete(TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + printf(" TPM_StoredData_Delete: v%u\n", version); + if (tpm_stored_data != NULL) { + TPM_SizedBuffer_Delete(&(tpm_stored_data->sealInfo)); + TPM_SizedBuffer_Delete(&(tpm_stored_data->encData)); + if (version == 1) { + TPM_PCRInfo_Delete(tpm_stored_data->tpm_seal_info); + free(tpm_stored_data->tpm_seal_info); + } + else { + TPM_PCRInfoLong_Delete((TPM_PCR_INFO_LONG *)tpm_stored_data->tpm_seal_info); + free(tpm_stored_data->tpm_seal_info); + } + TPM_StoredData_Init(tpm_stored_data, version); + } + return; +} + +/* TPM_StoredData_CheckTag() verifies the tag and et members of a TPM_STORED_DATA12 structure + + */ + +TPM_RESULT TPM_StoredData_CheckTag(TPM_STORED_DATA12 *tpm_stored_data12) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StoredData_CheckTag:\n"); + if (rc == 0) { + if (tpm_stored_data12->tag != TPM_TAG_STORED_DATA12) { + printf("TPM_StoredData_CheckTag: Error, tag expected %04x found %04hx\n", + TPM_TAG_STORED_DATA12, tpm_stored_data12->tag); + rc = TPM_BAD_VERSION; + } + } + return rc; +} + +/* TPM_StoredData_GenerateDigest() generates a TPM_DIGEST over the TPM_STORED_DATA structure + excluding the encDataSize and encData members. +*/ + +TPM_RESULT TPM_StoredData_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; /* TPM_STORED_DATA serialization */ + + printf(" TPM_StoredData_GenerateDigest:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize the TPM_STORED_DATA excluding the encData fields */ + if (rc == 0) { + rc = TPM_StoredData_StoreClearData(&sbuffer, tpm_stored_data, version); + } + if (rc == 0) { + rc = TPM_SHA1Sbuffer(tpm_digest, &sbuffer); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + Processing Functions +*/ + +/* TPM_SealCryptCommon() rev 98 + + Handles the encrypt/decrypt actions common to TPM_Sealx and TPM_Unseal + + 'encrypt TRUE for encryption, FALSE for decryption + + The output o1 must be freed by the caller. +*/ + +static TPM_RESULT TPM_SealCryptCommon(BYTE **o1, /* freed by caller */ + TPM_ADIP_ENC_SCHEME adipEncScheme, + TPM_SIZED_BUFFER *inData, + TPM_AUTH_SESSION_DATA *auth_session_data, + TPM_NONCE nonceOdd) +{ + TPM_RESULT rc = 0; + BYTE *x1; /* XOR string, MGF1 output */ + TPM_DIGEST ctr; /* symmetric key algorithm CTR */ + + printf(" TPM_SealCryptCommon:\n"); + x1 = NULL; /* freed @1 */ + + /* allocate for the output o1 */ + if (rc == TPM_SUCCESS) { + rc = TPM_Malloc(o1, inData->size); /* freed by caller */ + } + if (rc == TPM_SUCCESS) { + TPM_PrintFour(" TPM_SealCryptCommon: input data", inData->buffer); + } + switch (adipEncScheme) { + case TPM_ET_XOR: + printf(" TPM_SealCryptCommon: TPM_ET_XOR\n"); + if (rc == TPM_SUCCESS) { + /* i. Use MGF1 to create string X1 of length sealedDataSize. The inputs to MGF1 are; + authLastnonceEven, nonceOdd, "XOR", and authHandle -> sharedSecret. The four + concatenated values form the Z value that is the seed for MFG1. */ + rc = TPM_MGF1_GenerateArray(&x1, /* MGF1 array */ + inData->size, /* MGF1 array length */ + + TPM_NONCE_SIZE + + TPM_NONCE_SIZE + + sizeof("XOR") -1 + + TPM_DIGEST_SIZE, /* seed length */ + + TPM_NONCE_SIZE, auth_session_data->nonceEven, + TPM_NONCE_SIZE, nonceOdd, + sizeof("XOR") -1, "XOR", + TPM_DIGEST_SIZE, auth_session_data->sharedSecret, + 0, NULL); + } + /* ii. Create o1 by XOR of d1 -> data and X1 */ + if (rc == TPM_SUCCESS) { + TPM_PrintFour(" TPM_SealCryptCommon: XOR key", x1); + TPM_XOR(*o1, inData->buffer, x1, inData->size); + } + break; + case TPM_ET_AES128_CTR: + printf(" TPM_SealCryptCommon: TPM_ET_AES128_CTR\n"); + /* i. Create o1 by encrypting d1 -> data using the algorithm indicated by inData -> + et */ + /* ii. Key is from authHandle -> sharedSecret */ + /* iii. IV is SHA-1 of (authLastNonceEven || nonceOdd) */ + if (rc == TPM_SUCCESS) { + rc = TPM_SHA1(ctr, + TPM_NONCE_SIZE, auth_session_data->nonceEven, + TPM_NONCE_SIZE, nonceOdd, + 0, NULL); + } + if (rc == TPM_SUCCESS) { + TPM_PrintFour(" TPM_SealCryptCommon: AES key", auth_session_data->sharedSecret); + TPM_PrintFour(" TPM_SealCryptCommon: CTR", ctr); + rc = TPM_SymmetricKeyData_CtrCrypt(*o1, /* output data */ + inData->buffer, /* input data */ + inData->size, /* data size */ + auth_session_data->sharedSecret, /* key */ + TPM_SECRET_SIZE, /* key size */ + ctr, /* CTR */ + TPM_DIGEST_SIZE); /* CTR size */ + } + break; + default: + printf("TPM_SealCryptCommon: Error, unsupported adipEncScheme %02x\n", adipEncScheme); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + if (rc == 0) { + TPM_PrintFour(" TPM_SealCryptCommon: output data", *o1); + + } + free(x1); /* @1 */ + return rc; +} + +/* 10.1 TPM_Seal rev 110 + + The SEAL operation allows software to explicitly state the future "trusted" configuration that + the platform must be in for the secret to be revealed. The SEAL operation also implicitly + includes the relevant platform configuration (PCR-values) when the SEAL operation was + performed. The SEAL operation uses the tpmProof value to BIND the blob to an individual TPM. + + TPM_Seal is used to encrypt private objects that can only be decrypted using TPM_Unseal. +*/ + +TPM_RESULT TPM_Process_Seal(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle of a loaded key that can perform seal + operations. */ + TPM_ENCAUTH encAuth; /* The encrypted authorization data for the sealed data. */ + TPM_SIZED_BUFFER pcrInfo; /* The PCR selection information. The caller MAY use + TPM_PCR_INFO_LONG. */ + TPM_SIZED_BUFFER inData; /* The data to be sealed to the platform and any specified + PCRs */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle + authorization. Must be an OS_AP session for this + command. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest for inputs and keyHandle. HMAC + key: key.usageAuth. */ + + /* processing */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + unsigned int v1PcrVersion = 1; /* pcrInfo version */ + TPM_STORED_DATA12 *s1_12; + TPM_PCR_INFO tpm_pcr_info; /* deserialized pcrInfo v1 */ + TPM_PCR_INFO_LONG tpm_pcr_info_long; /* deserialized pcrInfo v2 */ + unsigned char *stream; + uint32_t stream_size; + TPM_DIGEST a1Auth; + TPM_SEALED_DATA s2SealedData; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORED_DATA s1StoredData; /* Encrypted, integrity-protected data object that is the + result of the TPM_Seal operation. Returned as + SealedData */ + + printf("TPM_Process_Seal: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&pcrInfo); /* freed @1 */ + TPM_SizedBuffer_Init(&inData); /* freed @2 */ + TPM_StoredData_Init(&s1StoredData, v1PcrVersion); /* freed @3, default is v1 */ + TPM_PCRInfo_Init(&tpm_pcr_info); /* freed @4 */ + TPM_PCRInfoLong_Init(&tpm_pcr_info_long); /* freed @5 */ + TPM_SealedData_Init(&s2SealedData); /* freed @6 */ + s1_12 = (TPM_STORED_DATA12 *)&s1StoredData; /* to avoid casts */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get encAuth parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Seal: keyHandle %08x\n", keyHandle); + returnCode = TPM_Authdata_Load(encAuth, &command, ¶mSize); + } + /* get pcrInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&pcrInfo, &command, ¶mSize); + } + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Seal: Sealing %u bytes\n", inData.size); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Seal: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, using to encrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get keyHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + key, + NULL, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 2. If the inDataSize is 0 the TPM returns TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (inData.size == 0) { + printf("TPM_Process_Seal: Error, inDataSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 3. If the keyUsage field of the key indicated by keyHandle does not have the value + TPM_KEY_STORAGE, the TPM must return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_Seal: Error, key keyUsage %04hx must be TPM_KEY_STORAGE\n", + key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. If the keyHandle points to a migratable key then the TPM MUST return the error code + TPM_INVALID_KEY_USAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_Seal: Error, key keyFlags %08x indicates migratable\n", + key->keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Determine the version of pcrInfo */ + if (returnCode == TPM_SUCCESS) { + /* a. If pcrInfoSize is 0 */ + if (pcrInfo.size == 0) { + v1PcrVersion = 1; /* i. set V1 to 1 */ + } + else { /* b. Else */ + /* i. Point X1 as TPM_PCR_INFO_LONG structure to pcrInfo */ + /* ii. If X1 -> tag is TPM_TAG_PCR_INFO_LONG */ + if (htons(*(uint16_t *)(pcrInfo.buffer)) == TPM_TAG_PCR_INFO_LONG) { + v1PcrVersion = 2; /* (1) Set V1 to 2 */ + } + else { /* iii. Else */ + v1PcrVersion = 1; /* (1) Set V1 to 1 */ + } + } + /* 6. If V1 is 1 then */ + /* a. Create S1 a TPM_STORED_DATA structure */ + /* 7. else */ + /* a. Create S1 a TPM_STORED_DATA12 structure */ + /* b. Set S1 -> et to 0 */ + /* 8. Set S1 -> encDataSize to 0 */ + /* 9. Set S1 -> encData to all zeros */ + printf("TPM_Process_Seal: V%u\n", v1PcrVersion); + TPM_StoredData_Init(&s1StoredData, v1PcrVersion); + /* 10. Set S1 -> sealInfoSize to pcrInfoSize */ + /* NOTE This step is unnecessary. If pcrInfoSize is 0, sealInfoSize is already initialized + to 0. If pcrInfoSize is non-zero, sealInfoSize is the result of serialization of the + tpm_seal_info member, which is either a TPM_PCR_INFO or a TPM_PCR_INFO_LONG */ + } + /* 11. If pcrInfoSize is not 0 then */ + if ((returnCode == TPM_SUCCESS) && (pcrInfo.size != 0)) { + printf("TPM_Process_Seal: Creating PCR digest\n"); + /* assign the stream, so pcrInfo is not altered */ + stream = pcrInfo.buffer; + stream_size = pcrInfo.size; + /* a. if V1 is 1 then */ + if (v1PcrVersion == 1) { + /* i. Validate pcrInfo as a valid TPM_PCR_INFO structure, return TPM_BADINDEX on + error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfo_Load(&tpm_pcr_info, &stream, &stream_size); + if (returnCode != 0) { + returnCode = TPM_BADINDEX; + } + } + /* build the TPM_STORED_DATA S1 structure */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set S1 -> sealInfo -> pcrSelection to pcrInfo -> pcrSelection */ + returnCode = TPM_PCRInfo_CreateFromBuffer(&(s1StoredData.tpm_seal_info), &pcrInfo); + } + /* iii. Create h1 the composite hash of the PCR selected by pcrInfo -> pcrSelection */ + /* iv. Set S1 -> sealInfo -> digestAtCreation to h1 */ + /* NOTE hash directly to destination. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_PCRSelection_GenerateDigest(s1StoredData.tpm_seal_info->digestAtCreation, + &(tpm_pcr_info.pcrSelection), + tpm_state->tpm_stclear_data.PCRS); + } + /* v. Set S1 -> sealInfo -> digestAtRelease to pcrInfo -> digestAtRelease */ + /* NOTE digestAtRelease copied during TPM_PCRInfo_CreateFromBuffer() */ + } + /* b. else (v1 is 2) */ + else { + /* i. Validate pcrInfo as a valid TPM_PCR_INFO_LONG structure, return TPM_BADINDEX + on error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoLong_Load(&tpm_pcr_info_long, &stream, &stream_size); + if (returnCode != 0) { + returnCode = TPM_BADINDEX; + } + } + /* build the TPM_STORED_DATA S1 structure */ + if (returnCode == TPM_SUCCESS) { + /* ii. Set S1 -> sealInfo -> creationPCRSelection to pcrInfo -> creationPCRSelection + */ + /* iii. Set S1 -> sealInfo -> releasePCRSelection to pcrInfo -> releasePCRSelection + */ + /* iv. Set S1 -> sealInfo -> digestAtRelease to pcrInfo -> digestAtRelease */ + /* v. Set S1 -> sealInfo -> localityAtRelease to pcrInfo -> localityAtRelease */ + /* NOTE copied during TPM_PCRInfoLong_CreateFromBuffer() */ + returnCode = TPM_PCRInfoLong_CreateFromBuffer(&(s1_12->tpm_seal_info_long), + &pcrInfo); + } + if (returnCode == TPM_SUCCESS) { + /* vi. Create h2 the composite hash of the PCR selected by pcrInfo -> + creationPCRSelection */ + /* vii. Set S1 -> sealInfo -> digestAtCreation to h2 */ + /* NOTE hash directly to destination. */ + returnCode = + TPM_PCRSelection_GenerateDigest(s1_12->tpm_seal_info_long->digestAtCreation, + &(tpm_pcr_info_long.creationPCRSelection), + tpm_state->tpm_stclear_data.PCRS); + } + /* viii. Set S1 -> sealInfo -> localityAtCreation to TPM_STANY_FLAGS -> + localityModifier */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Locality_Set(&(s1_12->tpm_seal_info_long->localityAtCreation), + tpm_state->tpm_stany_flags.localityModifier); + } + } + } + /* 12. Create a1 by decrypting encAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, + NULL, + encAuth, + auth_session_data, + NULL, + NULL, + FALSE); /* even and odd */ + } + /* 13. The TPM provides NO validation of a1. Well-known values (like all zeros) are valid and + possible. */ + /* 14. Create S2 a TPM_SEALED_DATA structure */ + if (returnCode == TPM_SUCCESS) { + /* a. Set S2 -> payload to TPM_PT_SEAL */ + /* NOTE: Done at TPM_SealedData_Init() */ + /* b. Set S2 -> tpmProof to TPM_PERMANENT_DATA -> tpmProof */ + TPM_Secret_Copy(s2SealedData.tpmProof, tpm_state->tpm_permanent_data.tpmProof); + /* c. Create h3 the SHA-1 of S1 */ + /* d. Set S2 -> storedDigest to h3 */ + returnCode = TPM_StoredData_GenerateDigest(s2SealedData.storedDigest, + &s1StoredData, v1PcrVersion); + } + if (returnCode == TPM_SUCCESS) { + /* e. Set S2 -> authData to a1 */ + TPM_Secret_Copy(s2SealedData.authData, a1Auth); + /* f. Set S2 -> dataSize to inDataSize */ + /* g. Set S2 -> data to inData */ + returnCode = TPM_SizedBuffer_Copy(&(s2SealedData.data), &inData); + } + /* 15. Validate that the size of S2 can be encrypted by the key pointed to by keyHandle, return + TPM_BAD_DATASIZE on error */ + /* 16. Create s3 the encryption of S2 using the key pointed to by keyHandle */ + /* 17. Set continueAuthSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 18. Set S1 -> encDataSize to the size of s3 */ + /* 19. Set S1 -> encData to s3 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SealedData_GenerateEncData(&(s1StoredData.encData), &s2SealedData, key); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Seal: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 20. Return S1 as sealedData */ + returnCode = TPM_StoredData_Store(response, &s1StoredData, v1PcrVersion); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&pcrInfo); /* @1 */ + TPM_SizedBuffer_Delete(&inData); /* @2 */ + TPM_StoredData_Delete(&s1StoredData, v1PcrVersion); /* @3 */ + TPM_PCRInfo_Delete(&tpm_pcr_info); /* @4 */ + TPM_PCRInfoLong_Delete(&tpm_pcr_info_long); /* @5 */ + TPM_SealedData_Delete(&s2SealedData); /* @6 */ + return rcf; +} + +/* 10.7 TPM_Sealx rev 110 + + The TPM_Sealx command works exactly like the TPM_Seal command with the additional requirement of + encryption for the inData parameter. This command also places in the sealed blob the information + that the TPM_Unseal also requires encryption. + + TPM_Sealx requires the use of 1.2 data structures. The actions are the same as TPM_Seal without + the checks for 1.1 data structure usage. +*/ + +TPM_RESULT TPM_Process_Sealx(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle of a loaded key that can perform seal + operations. */ + TPM_ENCAUTH encAuth; /* The encrypted authorization data for the sealed data */ + TPM_SIZED_BUFFER pcrInfo; /* If 0 there are no PCR registers in use. pcrInfo MUST use + TPM_PCR_INFO_LONG */ + TPM_SIZED_BUFFER inData; /* The data to be sealed to the platform and any specified + PCRs */ + + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle + authorization. Must be an OSAP session for this command. + */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest for inputs and keyHandle. HMAC + key: key.usageAuth. */ + + /* processing */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_STORED_DATA12 s1StoredData; /* Encrypted, integrity-protected data object that + is the result of the TPM_Seal operation. Returned + as SealedData */ + TPM_STORED_DATA *s1_11; /* 1.1 version to avoid casts */ + TPM_SEALED_DATA s2SealedData; + TPM_DIGEST a1Auth; + BYTE *o1DecryptedData; + + printf("TPM_Process_Sealx: Ordinal Entry\n"); + s1_11 = (TPM_STORED_DATA *)&s1StoredData; /* 1.1 version to avoid casts */ + TPM_SizedBuffer_Init(&pcrInfo); /* freed @1 */ + TPM_SizedBuffer_Init(&inData); /* freed @2 */ + TPM_StoredData_Init(s1_11, 2); /* freed @3 */ + TPM_SealedData_Init(&s2SealedData); /* freed @4 */ + o1DecryptedData = NULL; /* freed @5 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get encAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(encAuth, &command, ¶mSize); + } + /* get pcrInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&pcrInfo, &command, ¶mSize); + } + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: Sealing %u bytes\n", inData.size); + TPM_PrintFour("TPM_Process_Sealx: Sealing data", inData.buffer); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Sealx: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, using to encrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get keyHandle -> usageAuth */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + key, + NULL, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. Validate the authorization to use the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 2. If the inDataSize is 0 the TPM returns TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (inData.size == 0) { + printf("TPM_Process_Sealx: Error, inDataSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* 3. If the keyUsage field of the key indicated by keyHandle does not have the value + TPM_KEY_STORAGE, the TPM must return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_Sealx: Error, key keyUsage %04hx must be TPM_KEY_STORAGE\n", + key->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. If the keyHandle points to a migratable key then the TPM MUST return the error code + TPM_INVALID_KEY_USAGE. */ + if (returnCode == TPM_SUCCESS) { + if (key->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_Sealx: Error, key keyFlags %08x indicates migratable\n", + key->keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. Create S1 a TPM_STORED_DATA12 structure */ + /* 6. Set S1 -> encDataSize to 0 */ + /* 7. Set S1 -> encData to all zeros */ + /* NOTE: Done by TPM_StoredData_Init() */ + /* 8. Set S1 -> sealInfoSize to pcrInfoSize */ + /* NOTE This step is unnecessary. If pcrInfoSize is 0, sealInfoSize is already initialized + to 0. If pcrInfoSize is non-zero, sealInfoSize is the result of serialization of the + tpm_seal_info member, which is a TPM_PCR_INFO_LONG */ + /* 9. If pcrInfoSize is not 0 then */ + if ((returnCode == TPM_SUCCESS) && (pcrInfo.size != 0)) { + printf("TPM_Process_Sealx: Setting sealInfo to pcrInfo\n"); + /* initializing the s -> TPM_PCR_INFO_LONG cache to the contents of pcrInfo */ + /* a. Validate pcrInfo as a valid TPM_PCR_INFO_LONG structure, return TPM_BADINDEX on + error */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRInfoLong_CreateFromBuffer(&(s1StoredData.tpm_seal_info_long), + &pcrInfo); + if (returnCode != TPM_SUCCESS) { + returnCode = TPM_BADINDEX; + } + } + /* b. Set S1 -> sealInfo -> creationPCRSelection to pcrInfo -> creationPCRSelection */ + /* c. Set S1 -> sealInfo -> releasePCRSelection to pcrInfo -> releasePCRSelection */ + /* d. Set S1 -> sealInfo -> digestAtRelease to pcrInfo -> digestAtRelease */ + /* e. Set S1 -> sealInfo -> localityAtRelease to pcrInfo -> localityAtRelease */ + /* NOTE copied during TPM_PCRInfoLong_CreateFromBuffer() */ + /* f. Create h2 the composite hash of the PCR selected by pcrInfo -> creationPCRSelection */ + /* g. Set S1 -> sealInfo -> digestAtCreation to h2 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_PCRSelection_GenerateDigest + (s1StoredData.tpm_seal_info_long->digestAtCreation, + &(s1StoredData.tpm_seal_info_long->creationPCRSelection), + tpm_state->tpm_stclear_data.PCRS); + } + /* h. Set S1 -> sealInfo -> localityAtCreation to TPM_STANY_DATA -> localityModifier */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Locality_Set(&(s1StoredData.tpm_seal_info_long->localityAtCreation), + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* 10. Create S2 a TPM_SEALED_DATA structure */ + /* NOTE: Done at TPM_SealedData_Init() */ + /* 11.Create a1 by decrypting encAuth according to the ADIP indicated by authHandle. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: Decrypting encAuth\n"); + returnCode = TPM_AuthSessionData_Decrypt(a1Auth, /* a1 even */ + NULL, /* a1 odd (2nd encAuth) */ + encAuth, /* encAuthEven */ + auth_session_data, + NULL, /* nonceOdd */ + NULL, /* encAuthOdd */ + FALSE); /* even and odd */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_Sealx: Decrypted Auth", a1Auth); + /* a. If authHandle indicates XOR encryption for the AuthData secrets */ + if (auth_session_data->adipEncScheme == TPM_ET_XOR) { + /* i. Set S1 -> et to TPM_ET_XOR || TPM_ET_KEY */ + /* (1) TPM_ET_KEY is added because TPM_Unseal uses zero as a special value indicating no + encryption. */ + s1StoredData.et = TPM_ET_XOR | TPM_ET_KEY; + } + /* b. Else */ + else { + /* i. Set S1 -> et to algorithm indicated by authHandle */ + s1StoredData.et = auth_session_data->adipEncScheme << 8; + } + } + /* 12. The TPM provides NO validation of a1. Well-known values (like all zeros) are valid and + possible. */ + /* 13. If authHandle indicates XOR encryption */ + /* a. Use MGF1 to create string X2 of length inDataSize. The inputs to MGF1 are; + authLastNonceEven, nonceOdd, "XOR", and authHandle -> sharedSecret. The four concatenated + values form the Z value that is the seed for MFG1. */ + /* b. Create o1 by XOR of inData and x2 */ + /* 14. Else */ + /* a. Create o1 by decrypting inData using the algorithm indicated by authHandle */ + /* b. Key is from authHandle -> sharedSecret */ + /* c. CTR is SHA-1 of (authLastNonceEven || nonceOdd) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: decrypting inData\n"); + returnCode = TPM_SealCryptCommon(&o1DecryptedData, /* freed by caller */ + auth_session_data->adipEncScheme, + &inData, + auth_session_data, + nonceOdd); + + } + /* 15. Create S2 a TPM_SEALED_DATA structure */ + if (returnCode == TPM_SUCCESS) { + /* a. Set S2 -> payload to TPM_PT_SEAL */ + /* NOTE: Done at TPM_SealedData_Init() */ + /* b. Set S2 -> tpmProof to TPM_PERMANENT_DATA -> tpmProof */ + TPM_Secret_Copy(s2SealedData.tpmProof, tpm_state->tpm_permanent_data.tpmProof); + /* c. Create h3 the SHA-1 of S1 */ + /* d. Set S2 -> storedDigest to h3 */ + returnCode = TPM_StoredData_GenerateDigest(s2SealedData.storedDigest, s1_11, 2); + } + /* e. Set S2 -> authData to a1 */ + if (returnCode == TPM_SUCCESS) { + TPM_Secret_Copy(s2SealedData.authData, a1Auth); + /* f. Set S2 -> dataSize to inDataSize */ + /* g. Set S2 -> data to o1 */ + returnCode = TPM_SizedBuffer_Set(&(s2SealedData.data), inData.size, o1DecryptedData); + } + /* 16. Validate that the size of S2 can be encrypted by the key pointed to by keyHandle, return + */ + /* TPM_BAD_DATASIZE on error */ + /* 17. Create s3 the encryption of S2 using the key pointed to by keyHandle */ + /* 18. Set continueAuthSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 19. Set S1 -> encDataSize to the size of s3 */ + /* 20. Set S1 -> encData to s3 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Sealx: Encrypting sealed data\n"); + returnCode = TPM_SealedData_GenerateEncData(&(s1StoredData.encData), &s2SealedData, key); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Sealx: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 21. Return S1 as sealedData */ + returnCode = TPM_StoredData_Store(response, s1_11, 2); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&pcrInfo); /* @1 */ + TPM_SizedBuffer_Delete(&inData); /* @2 */ + TPM_StoredData_Delete(s1_11, 2); /* @3 */ + TPM_SealedData_Delete(&s2SealedData); /* @4 */ + free(o1DecryptedData); /* @5 */ + return rcf; +} + +/* 10.2 TPM_Unseal rev 110 + + The TPM_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. Internally, TPM_Unseal accepts a data blob generated by a TPM_Seal + operation. TPM_Unseal decrypts the structure internally, checks the integrity of the resulting + data, and checks that the PCR named has the value named during TPM_Seal. Additionally, the + caller must supply appropriate authorization data for blob and for the key that was used to seal + that data. + + If the integrity, platform configuration and authorization checks succeed, the sealed data is + returned to the caller; otherwise, an error is generated. +*/ + +TPM_RESULT TPM_Process_Unseal(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* Handle of a loaded key that can unseal the data. */ + TPM_STORED_DATA inData; /* The encrypted data generated by TPM_Seal. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parentHandle. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and + parentHandle. HMAC key: parentKey.usageAuth. */ + TPM_AUTHHANDLE dataAuthHandle; /* The authorization handle used to authorize inData. */ + TPM_NONCE datanonceOdd; /* Nonce generated by system associated with + entityAuthHandle */ + TPM_BOOL continueDataSession = TRUE; /* Continue usage flag for dataAuthHandle. */ + TPM_AUTHDATA dataAuth; /* The authorization digest for the encrypted entity. HMAC + key: entity.usageAuth. */ + + /* processing */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_BOOL dataAuthHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_AUTH_SESSION_DATA *data_auth_session_data = NULL; /* session data for dataAuthHandle + */ + TPM_SECRET *hmacKey; + TPM_SECRET *dataHmacKey; + unsigned int v1StoredDataVersion = 1; /* version of TPM_STORED_DATA + inData */ + TPM_KEY *parentKey; + TPM_BOOL parentPCRStatus; + TPM_SECRET *parentUsageAuth; + TPM_SEALED_DATA d1SealedData; + TPM_DIGEST h1StoredDataDigest; + TPM_STORED_DATA12 *s2StoredData; + BYTE *o1Encrypted; /* For ADIP encryption */ + TPM_ADIP_ENC_SCHEME adipEncScheme; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + uint32_t secretSize = 0; /* Decrypted data that had been sealed */ + BYTE *secret = NULL; + + printf("TPM_Process_Unseal: Ordinal Entry\n"); + TPM_StoredData_Init(&inData, v1StoredDataVersion); /* freed @1, default is v1 */ + TPM_SealedData_Init(&d1SealedData); /* freed @2 */ + o1Encrypted = NULL; /* freed @3 */ + s2StoredData = (TPM_STORED_DATA12 *)&inData; /* inData when it's a TPM_STORED_DATA12 + structure */ + /* + get inputs + */ + /* get parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get inData parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: parentHandle %08x\n", parentHandle); + returnCode = TPM_StoredData_Load(&inData, &v1StoredDataVersion, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: inData is v%u\n", v1StoredDataVersion); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag21(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + printf("TPM_Process_Unseal: authHandle %08x\n", authHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&dataAuthHandle, + &dataAuthHandleValid, + datanonceOdd, + &continueDataSession, + dataAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: dataAuthHandle %08x\n", dataAuthHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_Unseal: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + dataAuthHandleValid = FALSE; + } + /* + Processing + */ + /* Verify that parentHandle points to a valid key. Get the TPM_KEY associated with parentHandle + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to decrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get parentHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the first session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. The TPM MUST validate that parentAuth authorizes the use of the key in parentHandle, on + error return TPM_AUTHFAIL */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* if there are no parent auth parameters */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_Unseal: Error, parent key authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* 2. If the keyUsage field of the key indicated by parentHandle does not have the value + TPM_KEY_STORAGE, the TPM MUST return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_Unseal: Error, key keyUsage %04hx must be TPM_KEY_STORAGE\n", + parentKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. The TPM MUST check that the TPM_KEY_FLAGS -> Migratable flag has the value FALSE in the + key indicated by parentKeyHandle. If not, the TPM MUST return the error code + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyFlags & TPM_MIGRATABLE) { + printf("TPM_Process_Unseal: Error, key keyFlags %08x indicates migratable\n", + parentKey->keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Determine the version of inData */ + /* a. If inData -> tag = TPM_TAG_STORED_DATA12 */ + /* i. Set V1 to 2 */ + /* ii. Map S2 a TPM_STORED_DATA12 structure to inData */ + /* b. Else If inData -> ver = 1.1 */ + /* i. Set V1 to 1 */ + /* ii. Map S2 a TPM_STORED_DATA structure to inData */ + /* c. Else */ + /* i. Return TPM_BAD_VERSION */ + /* NOTE: Done during TPM_StoredData_Load() */ + /* The extra indent of error checking is required because the next steps all return + TPM_NOTSEALED_BLOB on error */ + if (returnCode == TPM_SUCCESS) { + /* 5. Create d1 by decrypting S2 -> encData using the key pointed to by parentHandle */ + printf("TPM_Process_Unseal: Decrypting encData\n"); + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SealedData_DecryptEncData(&d1SealedData, /* TPM_SEALED_DATA */ + &(inData.encData), + parentKey); + } + /* 6. Validate d1 */ + /* a. d1 MUST be a TPM_SEALED_DATA structure */ + /* NOTE Done during TPM_SealedData_DecryptEncData() */ + /* b. d1 -> tpmProof MUST match TPM_PERMANENT_DATA -> tpmProof */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: Sealed data size %u\n", d1SealedData.data.size); + TPM_PrintFour("TPM_Process_Unseal: Sealed data", d1SealedData.data.buffer); + printf("TPM_Process_Unseal: Checking tpmProof\n"); + returnCode = TPM_Secret_Compare(d1SealedData.tpmProof, + tpm_state->tpm_permanent_data.tpmProof); + } + if (returnCode == TPM_SUCCESS) { + /* c. Set S2 -> encDataSize to 0 */ + /* d. Set S2 -> encData to all zeros */ + /* NOTE: This would be done at cleanup */ + TPM_SizedBuffer_Delete(&(inData.encData)); + /* e. Create h1 the SHA-1 of S2 */ + returnCode = TPM_StoredData_GenerateDigest(h1StoredDataDigest, + &inData, v1StoredDataVersion); + } + /* f. d1 -> storedDigest MUST match h1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: Checking storedDigest\n"); + returnCode = TPM_Digest_Compare(d1SealedData.storedDigest, h1StoredDataDigest); + } + /* g. d1 -> payload MUST be TPM_PT_SEAL */ + if (returnCode == TPM_SUCCESS) { + if (d1SealedData.payload != TPM_PT_SEAL) { + printf("TPM_Process_Unseal: Error, payload %02x not TPM_PT_SEAL\n", + d1SealedData.payload); + returnCode = TPM_NOTSEALED_BLOB; + } + } + /* h. Any failure MUST return TPM_NOTSEALED_BLOB */ + if (returnCode != TPM_SUCCESS) { + returnCode = TPM_NOTSEALED_BLOB; + } + } + /* 7. If S2 -> sealInfo is not 0 then */ + /* NOTE: Done by _CheckDigest() */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_Unseal: Checking PCR digest\n"); + /* a. If V1 is 1 then */ + if (v1StoredDataVersion == 1) { + /* i. Validate that S2 -> pcrInfo is a valid TPM_PCR_INFO structure */ + /* NOTE: Done during TPM_StoredData_Load() */ + /* ii. Create h2 the composite hash of the PCR selected by S2 -> pcrInfo -> pcrSelection + */ + /* c. Compare h2 with S2 -> pcrInfo -> digestAtRelease, on mismatch return + TPM_WRONGPCRVALUE */ + returnCode = TPM_PCRInfo_CheckDigest(inData.tpm_seal_info, + tpm_state->tpm_stclear_data.PCRS); /* PCR array */ + } + /* b. If V1 is 2 then */ + else { + /* i. Validate that S2 -> pcrInfo is a valid TPM_PCR_INFO_LONG structure */ + /* NOTE: Done during TPM_StoredData_Load() */ + /* ii. Create h2 the composite hash of the PCR selected by S2 -> pcrInfo -> + releasePCRSelection */ + /* iii. Check that S2 -> pcrInfo -> localityAtRelease for TPM_STANY_DATA -> + localityModifier is TRUE */ + /* (1) For example if TPM_STANY_DATA -> localityModifier was 2 then S2 -> pcrInfo -> + localityAtRelease -> TPM_LOC_TWO would have to be TRUE */ + /* c. Compare h2 with S2 -> pcrInfo -> digestAtRelease, on mismatch return + TPM_WRONGPCRVALUE */ + returnCode = + TPM_PCRInfoLong_CheckDigest(s2StoredData->tpm_seal_info_long, + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + tpm_state->tpm_stany_flags.localityModifier); + } + } + /* 8. The TPM MUST validate authorization to use d1 by checking that the HMAC calculation + using d1 -> authData as the shared secret matches the dataAuth. Return TPM_AUTHFAIL on + mismatch. */ + /* get the second session data */ + /* NOTE: While OSAP isn't specifically excluded, there is currently no way to set up an OSAP + session using TPM_SEALED_DATA as the entity */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&data_auth_session_data, + &dataHmacKey, + tpm_state, + dataAuthHandle, + TPM_PID_OIAP, /* currently require OIAP */ + 0, /* OSAP entity type */ + ordinal, + NULL, + &(d1SealedData.authData), /* OIAP */ + NULL); /* OSAP */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Auth2data_Check(tpm_state, + *dataHmacKey, /* HMAC key */ + inParamDigest, + data_auth_session_data, /* authorization session */ + datanonceOdd, /* Nonce generated by system + associated with authHandle */ + continueDataSession, + dataAuth); /* Authorization digest for input */ + } + if (returnCode == TPM_SUCCESS) { + /* 9. If V1 is 2 and S2 -> et specifies encryption (i.e. is not all zeros) then */ + if ((v1StoredDataVersion == 2) && (s2StoredData->et != 0x0000)) { + /* a. If tag is not TPM_TAG_RQU_AUTH2_COMMAND, return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + if (tag != TPM_TAG_RQU_AUTH2_COMMAND) { + printf("TPM_Process_Unseal: Error, sealed with encryption but auth-1\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* b. Verify that the authHandle session type is TPM_PID_OSAP or TPM_PID_DSAP, return + TPM_BAD_MODE on error. */ + if (returnCode == TPM_SUCCESS) { + if ((auth_session_data->protocolID != TPM_PID_OSAP) && + (auth_session_data->protocolID != TPM_PID_DSAP)) { + printf("TPM_Process_Unseal: Error, sealed with encryption but OIAP\n"); + returnCode = TPM_BAD_MODE; + } + } + /* c. If MSB of S2 -> et is TPM_ET_XOR */ + /* i. Use MGF1 to create string X1 of length sealedDataSize. The inputs to MGF1 are; + authLastnonceEven, nonceOdd, "XOR", and authHandle -> sharedSecret. The four + concatenated values form the Z value that is the seed for MFG1. */ + /* d. Else */ + /* i. Create o1 by encrypting d1 -> data using the algorithm indicated by inData -> + et */ + /* ii. Key is from authHandle -> sharedSecret */ + /* iii. IV is SHA-1 of (authLastNonceEven || nonceOdd) */ + if (returnCode == TPM_SUCCESS) { + /* entity type MSB is ADIP encScheme */ + adipEncScheme = (s2StoredData->et >> 8) & 0x00ff; + printf("TPM_Process_Unseal: Encrypting the output, encScheme %02x\n", + adipEncScheme); + returnCode = TPM_SealCryptCommon(&o1Encrypted, + adipEncScheme, + &(d1SealedData.data), + auth_session_data, + nonceOdd); + secretSize = d1SealedData.data.size; + secret = o1Encrypted; + } + /* e. Set continueAuthSession to FALSE */ + continueAuthSession = FALSE; + } + /* 10. else */ + else { + printf("TPM_Process_Unseal: No output encryption\n"); + /* a. Set o1 to d1 -> data */ + secretSize = d1SealedData.data.size; + secret = d1SealedData.data.buffer; + } + } + /* 11. Set the return secret as o1 */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_Unseal: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return secretSize */ + returnCode = TPM_Sbuffer_Append32(response, secretSize); + } + if (returnCode == TPM_SUCCESS) { + /* return secret */ + returnCode = TPM_Sbuffer_Append(response, secret, secretSize); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *dataHmacKey, /* HMAC key */ + data_auth_session_data, + outParamDigest, + datanonceOdd, + continueDataSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueDataSession) && + dataAuthHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, dataAuthHandle); + } + /* + cleanup + */ + TPM_StoredData_Delete(&inData, v1StoredDataVersion); /* @1 */ + TPM_SealedData_Delete(&d1SealedData); /* @2 */ + free(o1Encrypted); /* @3 */ + return rcf; +} + +/* 10.3 TPM_UnBind rev 87 + + TPM_UnBind takes the data blob that is the result of a Tspi_Data_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. + + UnBind SHALL operate on a single block only. +*/ + +TPM_RESULT TPM_Process_UnBind(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform + UnBind operations. */ + TPM_SIZED_BUFFER inData; /* Encrypted blob to be decrypted */ + TPM_AUTHHANDLE authHandle; /* The handle used for keyHandle authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA privAuth; /* The authorization digest that authorizes the inputs and + use of keyHandle. HMAC key: key.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_SECRET *keyUsageAuth; + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; /* for key */ + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + uint32_t decrypt_data_size; /* resulting decrypted data size */ + BYTE *decrypt_data = NULL; /* The resulting decrypted data. */ + unsigned char *stream; + uint32_t stream_size; + TPM_BOUND_DATA tpm_bound_data; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + size_t outDataSize = 0; /* The length of the returned decrypted data */ + BYTE *outData = NULL; /* The resulting decrypted data. */ + + printf("TPM_Process_UnBind: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&inData); /* freed @1 */ + TPM_BoundData_Init(&tpm_bound_data); /* freed @3 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get areaToSignSize and areaToSign parameters */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_UnBind: keyHandle %08x\n", keyHandle); + returnCode = TPM_SizedBuffer_Load(&inData, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_UnBind: UnBinding %u bytes\n", inData.size); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_UnBind: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* 1. If the inDataSize is 0 the TPM returns TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (inData.size == 0) { + printf("TPM_Process_UnBind: Error, inDataSize is 0\n"); + returnCode = TPM_BAD_PARAMETER; + } + } + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + if (key->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_UnBind: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + key, + keyUsageAuth, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 2. Validate the authorization to use the key pointed to by keyHandle */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 3. If the keyUsage field of the key referenced by keyHandle does not have the value + TPM_KEY_BIND or TPM_KEY_LEGACY, the TPM must return the error code TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((key->keyUsage != TPM_KEY_BIND) && (key->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_UnBind: Error, invalid keyUsage %04hx\n", (key->keyUsage)); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* Get the TPM_RSA_KEY_PARMS associated with key */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyParms_GetRSAKeyParms(&tpm_rsa_key_parms, &(key->algorithmParms)); + } + /* 4. Decrypt the inData using the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_RSAPrivateDecryptMalloc(&decrypt_data, /* decrypted data, freed @2 */ + &decrypt_data_size, /* actual size of decrypted data + data */ + inData.buffer, + inData.size, + key); + } + if (returnCode == TPM_SUCCESS) { + /* 5. if (keyHandle -> encScheme does not equal TPM_ES_RSAESOAEP_SHA1_MGF1) and (keyHandle + -> keyUsage equals TPM_KEY_LEGACY), */ + if ((key->algorithmParms.encScheme != TPM_ES_RSAESOAEP_SHA1_MGF1) && + (key->keyUsage == TPM_KEY_LEGACY)) { + printf("TPM_Process_UnBind: Legacy key\n"); + /* a. The payload does not have TPM specific markers to validate, so no consistency + check can be performed. */ + /* b. Set the output parameter outData to the value of the decrypted value of + inData. (Padding associated with the encryption wrapping of inData SHALL NOT be + returned.) */ + outData = decrypt_data; + /* c. Set the output parameter outDataSize to the size of outData, as deduced from the + decryption process. */ + outDataSize = decrypt_data_size; + } + /* 6. else */ + else { + printf("TPM_Process_UnBind: Payload is TPM_BOUND_DATA structure\n"); + /* a. Interpret the decrypted data under the assumption that it is a TPM_BOUND_DATA + structure, and validate that the payload type is TPM_PT_BIND */ + if (returnCode == TPM_SUCCESS) { + stream = decrypt_data; + stream_size = decrypt_data_size; + returnCode = TPM_BoundData_Load(&tpm_bound_data, + &stream, + &stream_size); + } + if (returnCode == TPM_SUCCESS) { + if (tpm_bound_data.payload != TPM_PT_BIND) { + printf("TPM_Process_UnBind: Error, " + "TPM_BOUND_DATA->payload %02x not TPM_PT_BIND\n", + tpm_bound_data.payload); + returnCode = TPM_INVALID_STRUCTURE; + } + } + /* b. Set the output parameter outData to the value of TPM_BOUND_DATA -> + payloadData. (Other parameters of TPM_BOUND_DATA SHALL NOT be returned. Padding + associated with the encryption wrapping of inData SHALL NOT be returned.) */ + if (returnCode == TPM_SUCCESS) { + outData = tpm_bound_data.payloadData; + /* c. Set the output parameter outDataSize to the size of outData, as deduced from + the decryption process and the interpretation of TPM_BOUND_DATA. */ + outDataSize = tpm_bound_data.payloadDataSize; + } + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_UnBind: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 10. Return the computed outData */ + /* append outDataSize */ + returnCode = TPM_Sbuffer_Append32(response, outDataSize); + } + if (returnCode == TPM_SUCCESS) { + /* append outData */ + returnCode = TPM_Sbuffer_Append(response, outData, outDataSize); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&inData); /* @1 */ + free(decrypt_data); /* @2 */ + TPM_BoundData_Delete(&tpm_bound_data); /* @3 */ + return rcf; +} + +/* 10.4 TPM_CreateWrapKey rev 114 + + 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_Process_CreateWrapKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* Handle of a loaded key that can perform key wrapping. */ + TPM_ENCAUTH dataUsageAuth; /* Encrypted usage authorization data for the key. */ + TPM_ENCAUTH dataMigrationAuth; /* Encrypted migration authorization data for the + key.*/ + TPM_KEY keyInfo; /* Information about key to be created, pubkey.keyLength and + keyInfo.encData elements are 0. MAY be TPM_KEY12 */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parent key + authorization. Must be an OSAP session. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* Ignored */ + TPM_AUTHDATA pubAuth; /* The authorization digest that authorizes the use of the + public key in parentHandle. HMAC key: + parentKey.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *parentKey = NULL; /* the key specified by parentHandle */ + TPM_BOOL parentPCRStatus; + TPM_RSA_KEY_PARMS *keyInfoRSAParms = NULL; /* substructure of keyInfo */ + TPM_SECRET du1UsageAuth; + TPM_SECRET dm1MigrationAuth; + TPM_STORE_ASYMKEY *wrappedStoreAsymkey; /* substructure of wrappedKey */ + TPM_PCR_INFO wrappedPCRInfo; + int ver; /* TPM_KEY or TPM_KEY12 */ + + /* output parameters */ + TPM_KEY wrappedKey; /* The TPM_KEY structure which includes the public and + encrypted private key. MAY be TPM_KEY12 */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + + printf("TPM_Process_CreateWrapKey: Ordinal Entry\n"); + TPM_Key_Init(&keyInfo); + TPM_Key_Init(&wrappedKey); + TPM_PCRInfo_Init(&wrappedPCRInfo); + /* + get inputs + */ + /* get parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get dataUsageAuth parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: parentHandle %08x\n", parentHandle); + returnCode = TPM_Authdata_Load(dataUsageAuth, &command, ¶mSize); + } + /* get dataMigrationAuth parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Authdata_Load(dataMigrationAuth, &command, ¶mSize); + } + /* get keyInfo parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_Load(&keyInfo, &command, ¶mSize); /* freed @1 */ + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + pubAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_CreateWrapKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, tpm_state, + parentHandle, + FALSE, /* not r/o, using to encrypt w/public key */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* get the session data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_OSAP, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + NULL, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /*OSAP*/ + } + /* 1. Validate the authorization to use the key pointed to by parentHandle. Return TPM_AUTHFAIL + on any error. */ + /* 2. Validate the session type for parentHandle is OSAP. */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_CreateWrapKey: sharedSecret", auth_session_data->sharedSecret); + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle + */ + continueAuthSession, + pubAuth); /* Authorization digest for input */ + } + /* 3. If the TPM is not designed to create a key of the type requested in keyInfo, return the + error code TPM_BAD_KEY_PROPERTY */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: Checking key properties\n"); + returnCode = TPM_Key_CheckProperties(&ver, &keyInfo, 0, + tpm_state->tpm_permanent_flags.FIPS); + } + /* Get the TPM_RSA_KEY_PARMS associated with keyInfo */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: key parameters v = %d\n", ver); + returnCode = TPM_KeyParms_GetRSAKeyParms(&keyInfoRSAParms, &(keyInfo.algorithmParms)); + } + /* 4. Verify that parentHandle->keyUsage equals TPM_KEY_STORAGE */ + if (returnCode == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_Process_CreateWrapKey: Error, parent keyUsage not TPM_KEY_STORAGE\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 5. If parentHandle -> keyFlags -> migratable is TRUE and keyInfo -> keyFlags -> migratable is + FALSE then return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((parentKey->keyFlags & TPM_MIGRATABLE) && !(keyInfo.keyFlags & TPM_MIGRATABLE)) { + printf("TPM_Process_CreateWrapKey: Error, parent not migratable\n"); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 6. Validate key parameters */ + /* a. keyInfo -> keyUsage MUST NOT be TPM_KEY_IDENTITY or TPM_KEY_AUTHCHANGE. If it is, return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if ((keyInfo.keyUsage == TPM_KEY_IDENTITY) || + (keyInfo.keyUsage == TPM_KEY_AUTHCHANGE)) { + printf("TPM_Process_CreateWrapKey: Error, Invalid key usage %04x\n", + keyInfo.keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* b. If keyInfo -> keyFlags -> migrateAuthority is TRUE then return TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (keyInfo.keyFlags & TPM_MIGRATEAUTHORITY) { + printf("TPM_Process_CreateWrapKey: Error, Invalid key flags %08x\n", + keyInfo.keyFlags); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 7. If TPM_PERMANENT_FLAGS -> FIPS is TRUE then + a. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS + b. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return TPM_NOTFIPS + c. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return TPM_NOTFIPS + NOTE Done in step 3 TPM_Key_CheckProperties() + */ + /* 8. If keyInfo -> keyUsage equals TPM_KEY_STORAGE or TPM_KEY_MIGRATE + i. algorithmID MUST be TPM_ALG_RSA + ii. encScheme MUST be TPM_ES_RSAESOAEP_SHA1_MGF1 + iii. sigScheme MUST be TPM_SS_NONE + iv. key size MUST be 2048 + v. exponentSize MUST be 0 + NOTE Done in step 3 TPM_Key_CheckProperties() + */ + /* 9. Determine the version of key + a.If keyInfo -> ver is 1.1 + i. Set V1 to 1 + ii. Map wrappedKey to a TPM_KEY structure + iii. Validate all remaining TPM_KEY structures + b. Else if keyInfo -> tag is TPM_TAG_KEY12 + i. Set V1 to 2 + ii. Map wrappedKey to a TPM_KEY12 structure + iii. Validate all remaining TPM_KEY12 structures + NOTE Check done by TPM_Key_CheckProperties() + NOTE Map done by TPM_Key_GenerateRSA() + */ + /* 10..Create DU1 by decrypting dataUsageAuth according to the ADIP indicated by authHandle */ + /* 11. Create DM1 by decrypting dataMigrationAuth according to the ADIP indicated by + authHandle */ + if (returnCode == TPM_SUCCESS) { + TPM_AuthSessionData_Decrypt(du1UsageAuth, + dm1MigrationAuth, + dataUsageAuth, /* even encAuth */ + auth_session_data, + nonceOdd, + dataMigrationAuth, /* odd encAuth */ + TRUE); + } + /* 12. Set continueAuthSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueAuthSession = FALSE; + } + /* 13. Generate asymmetric key according to algorithm information in keyInfo */ + /* 14. Fill in the wrappedKey structure with information from the newly generated key. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_CreateWrapKey: Generating key\n"); + returnCode = TPM_Key_GenerateRSA(&wrappedKey, + tpm_state, + parentKey, + tpm_state->tpm_stclear_data.PCRS, /* PCR array */ + ver, + keyInfo.keyUsage, + keyInfo.keyFlags, + keyInfo.authDataUsage, /* TPM_AUTH_DATA_USAGE */ + &(keyInfo.algorithmParms), /* TPM_KEY_PARMS */ + keyInfo.tpm_pcr_info, /* TPM_PCR_INFO */ + keyInfo.tpm_pcr_info_long); /* TPM_PCR_INFO_LONG */ + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GetStoreAsymkey(&wrappedStoreAsymkey, + &wrappedKey); + } + if (returnCode == TPM_SUCCESS) { + /* a. Set wrappedKey -> encData -> usageAuth to DU1 */ + TPM_Secret_Copy(wrappedStoreAsymkey->usageAuth, du1UsageAuth); + /* b. If the KeyFlags -> migratable bit is set to 1, the wrappedKey -> encData -> + migrationAuth SHALL contain the decrypted value from dataMigrationAuth. */ + if (wrappedKey.keyFlags & TPM_MIGRATABLE) { + TPM_Secret_Copy(wrappedStoreAsymkey->migrationAuth, dm1MigrationAuth); + } + /* c. If the KeyFlags -> migratable bit is set to 0, the wrappedKey -> encData -> + migrationAuth SHALL be set to the value tpmProof */ + else { + TPM_Secret_Copy(wrappedStoreAsymkey->migrationAuth, + tpm_state->tpm_permanent_data.tpmProof); + } + printf("TPM_Process_CreateWrapKey: wrappedKey.PCRInfoSize %d\n", wrappedKey.pcrInfo.size); + } + /* 15. If keyInfo->PCRInfoSize is non-zero. */ + /* a. If V1 is 1 */ + /* i. Set wrappedKey -> pcrInfo to a TPM_PCR_INFO structure using the pcrSelection to + indicate the PCR's in use */ + /* b. Else */ + /* i. Set wrappedKey -> pcrInfo to a TPM_PCR_INFO_LONG structure */ + /* c. Set wrappedKey -> pcrInfo to keyInfo -> pcrInfo */ + /* d. Set wrappedKey -> digestAtCreation to the TPM_COMPOSITE_HASH indicated by + creationPCRSelection */ + /* e. If V1 is 2 set wrappedKey -> localityAtCreation to TPM_STANY_DATA -> locality */ + /* NOTE Done by TPM_Key_GenerateRSA() */ + /* 16. Encrypt the private portions of the wrappedKey structure using the key in parentHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_GenerateEncData(&wrappedKey, parentKey); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_CreateWrapKey: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 17. Return the newly generated key in the wrappedKey parameter */ + returnCode = TPM_Key_Store(response, &wrappedKey); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* cleanup */ + TPM_Key_Delete(&keyInfo); /* @1 */ + TPM_Key_Delete(&wrappedKey); /* @2 */ + TPM_PCRInfo_Delete(&wrappedPCRInfo); /* @3 */ + return rcf; +} + +/* 27.8 TPM_LoadKey rev 114 + + Version 1.2 deprecates LoadKey due to the HMAC of the new keyhandle on return. The wrapping makes + use of the handle difficult in an environment where the TSS, or other management entity, is + changing the TPM handle to a virtual handle. + + Software using loadKey on a 1.2 TPM can have a collision with the returned handle as the 1.2 TPM + uses random values in the lower three bytes of the handle. All new software must use LoadKey2 to + allow management software the ability to manage the key handle. + + 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_Process_LoadKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* TPM handle of parent key. */ + TPM_KEY *inKey; /* Incoming key structure, both encrypted private and clear + public portions. MAY be TPM_KEY12 */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parentHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = FALSE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and + parentHandle. HMAC key: parentKey.usageAuth. */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_BOOL key_added = FALSE; /* key has been added to handle list */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY_HANDLE inKeyHandle; /* Internal TPM handle where decrypted key was loaded. */ + + printf("TPM_Process_LoadKey: Ordinal Entry\n"); + inKey = NULL; /* freed @1 */ + /* + get inputs + */ + /* get parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* Allocate space for inKey. The key cannot be a local variable, since it persists in key + storage after the command completes. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKey: parentHandle %08x\n", parentHandle); + returnCode = TPM_Malloc((unsigned char **)&inKey, sizeof(TPM_KEY)); /* freed @1 */ + } + /* get inKey parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_Key_Init(inKey); /* freed @2 */ + returnCode = TPM_Key_Load(inKey, &command, ¶mSize); /* freed @2 */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_LoadKey: inKey n", inKey->pubKey.buffer); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadKeyCommon(&inKeyHandle, /* output */ + &key_added, /* output */ + &hmacKey, /* output */ + &auth_session_data, /* output */ + tpm_state, + tag, + ordinal, + parentHandle, + inKey, + inParamDigest, + authHandle, /*uninitialized*/ + nonceOdd, + continueAuthSession, + parentAuth); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadKey: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return the key handle */ + returnCode = TPM_Sbuffer_Append32(response, inKeyHandle); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + /* if there was a failure, delete inKey */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(inKey); /* @2 */ + free(inKey); /* @1 */ + if (key_added) { + /* if there was a failure and inKey was stored in the handle list, free the handle. + Ignore errors, since only one error code can be returned. */ + TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, inKeyHandle); + } + } + return rcf; +} + +/* 10.5 TPM_LoadKey2 rev 107 + + Before the TPM can use a key to either wrap, unwrap, unbind, seal, unseal, sign or perform any + other action, it needs to be present in the TPM. The TPM_LoadKey2 function loads the key into + the TPM for further use. + + The TPM assigns the key handle. The TPM always locates a loaded key by use of the handle. The + assumption is that the handle may change due to key management operations. It is the + responsibility of upper level software to maintain the mapping between handle and any label used + by external software. + + This command has the responsibility of enforcing restrictions on the use of keys. For example, + when attempting to load a STORAGE key it will be checked for the restrictions on a storage key + (2048 size etc.). + + The load command must maintain a record of whether any previous key in the key hierarchy was + bound to a PCR using parentPCRStatus. + + The flag parentPCRStatus enables the possibility of checking that a platform passed through some + particular state or states before finishing in the current state. A grandparent key could be + linked to state-1, a parent key could linked to state-2, and a child key could be linked to + state-3, for example. The use of the child key then indicates that the platform passed through + states 1 and 2 and is currently in state 3, in this example. TPM_Startup with stType == + TPM_ST_CLEAR indicates that the platform has been reset, so the platform has not passed through + the previous states. Hence keys with parentPCRStatus==TRUE must be unloaded if TPM_Startup is + issued with stType == TPM_ST_CLEAR. + + If a TPM_KEY structure has been decrypted AND the integrity test using "pubDataDigest" has passed + AND the key is non-migratory, the key must have been created by the TPM. So there is every reason + to believe that the key poses no security threat to the TPM. While there is no known attack from + a rogue migratory key, there is a desire to verify that a loaded migratory key is a real key, + arising from a general sense of unease about execution of arbitrary data as a key. Ideally a + consistency check would consist of an encrypt/decrypt cycle, but this may be expensive. For RSA + keys, it is therefore suggested that the consistency test consists of dividing the supposed RSA + product by the supposed RSA prime, and checking that there is no remainder. +*/ + +TPM_RESULT TPM_Process_LoadKey2(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE parentHandle; /* TPM handle of parent key. */ + TPM_KEY *inKey; /* Incoming key structure, both encrypted private and clear + public portions. MAY be TPM_KEY12 */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for parentHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = FALSE; /* The continue use flag for the authorization + handle */ + TPM_AUTHDATA parentAuth; /* The authorization digest for inputs and + parentHandle. HMAC key: parentKey.usageAuth. */ + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_BOOL key_added = FALSE; /* key has been added to handle list */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_KEY_HANDLE inKeyHandle; /* Internal TPM handle where decrypted key was loaded. */ + + printf("TPM_Process_LoadKey2: Ordinal Entry\n"); + inKey = NULL; /* freed @1 */ + /* + get inputs + */ + /* get parentHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&parentHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* Allocate space for inKey. The key cannot be a local variable, since it persists in key + storage after the command completes. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_LoadKey2: parentHandle %08x\n", parentHandle); + returnCode = TPM_Malloc((unsigned char **)&inKey, sizeof(TPM_KEY)); /* freed @1 */ + } + /* get inKey parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_Key_Init(inKey); /* freed @2 */ + returnCode = TPM_Key_Load(inKey, &command, ¶mSize); /* freed @2 */ + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_LoadKey2: inKey n", inKey->pubKey.buffer); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + parentAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_LoadKey2: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_LoadKeyCommon(&inKeyHandle, /* output */ + &key_added, /* output */ + &hmacKey, /* output */ + &auth_session_data, /* output */ + tpm_state, + tag, + ordinal, + parentHandle, + inKey, + inParamDigest, + authHandle, /* uninitialized */ + nonceOdd, + continueAuthSession, + parentAuth); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_LoadKey2: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + /* In TPM_LoadKey2, the inKeyHandle is not part of the output HMAC */ + /* return the key handle */ + returnCode = TPM_Sbuffer_Append32(response, inKeyHandle); + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + /* if there was a failure, delete inKey */ + if ((rcf != 0) || (returnCode != TPM_SUCCESS)) { + TPM_Key_Delete(inKey); /* @2 */ + free(inKey); /* @1 */ + if (key_added) { + /* if there was a failure and inKey was stored in the handle list, free the handle. + Ignore errors, since only one error code can be returned. */ + TPM_KeyHandleEntries_DeleteHandle(tpm_state->tpm_key_handle_entries, inKeyHandle); + } + } + return rcf; +} + +/* TPM_LoadKeyCommon rev 114 + + Code common to TPM_LoadKey and TPM_LoadKey2. They differ only in whether the key handle is + included in the response HMAC calculation. +*/ + +static TPM_RESULT TPM_LoadKeyCommon(TPM_KEY_HANDLE *inKeyHandle, /* output */ + TPM_BOOL *key_added, /* output */ + TPM_SECRET **hmacKey, /* output */ + TPM_AUTH_SESSION_DATA **auth_session_data, /* output */ + tpm_state_t *tpm_state, + TPM_TAG tag, + TPM_COMMAND_CODE ordinal, + TPM_KEY_HANDLE parentHandle, + TPM_KEY *inKey, + TPM_DIGEST inParamDigest, + TPM_AUTHHANDLE authHandle, + TPM_NONCE nonceOdd, + TPM_BOOL continueAuthSession, + TPM_AUTHDATA parentAuth) +{ + TPM_RESULT rc = 0; + TPM_KEY *parentKey; /* the key specified by parentHandle */ + TPM_SECRET *parentUsageAuth; + TPM_BOOL parentPCRStatus; + TPM_BOOL parentPCRUsage; + int ver; + + printf("TPM_LoadKeyCommon:\n"); + *key_added = FALSE; /* key has been added to handle list */ + /* Verify that parentHandle points to a valid key. Get the TPM_KEY associated with parentHandle + */ + if (rc == TPM_SUCCESS) { + rc = TPM_KeyHandleEntries_GetKey(&parentKey, &parentPCRStatus, + tpm_state, parentHandle, + FALSE, /* not r/o, using to decrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* check TPM_AUTH_DATA_USAGE authDataUsage */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (parentKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_LoadKeyCommon: Error, authorization required\n"); + rc = TPM_AUTHFAIL; + } + } + /* get parentHandle -> usageAuth */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + rc = TPM_Key_GetUsageAuth(&parentUsageAuth, parentKey); + } + /* get the session data */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + rc = TPM_AuthSessions_GetData(auth_session_data, + hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + parentKey, + parentUsageAuth, /* OIAP */ + parentKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. Validate the command and the parameters using parentAuth and parentHandle -> usageAuth */ + if ((rc == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + rc = TPM_Authdata_Check(tpm_state, + **hmacKey, /* HMAC key */ + inParamDigest, + *auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + parentAuth); /* Authorization digest for input */ + } + /* 2. If parentHandle -> keyUsage is NOT TPM_KEY_STORAGE return TPM_INVALID_KEYUSAGE */ + if (rc == TPM_SUCCESS) { + if (parentKey->keyUsage != TPM_KEY_STORAGE) { + printf("TPM_LoadKeyCommon: Error, " + "parentHandle -> keyUsage should be TPM_KEY_STORAGE, is %04x\n", + parentKey->keyUsage); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* 3. If the TPM is not designed to operate on a key of the type specified by inKey, return the + error code TPM_BAD_KEY_PROPERTY. */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_CheckProperties(&ver, inKey, 0, tpm_state->tpm_permanent_flags.FIPS); + printf("TPM_LoadKeyCommon: key parameters v = %d\n", ver); + } + /* 4. The TPM MUST handle both TPM_KEY and TPM_KEY12 structures. + This step is done at TPM_Key_Load() + */ + /* 5. Decrypt the inKey -> privkey to obtain TPM_STORE_ASYMKEY structure using the key in + parentHandle. + */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_DecryptEncData(inKey, parentKey); + } + /* 6. Validate the integrity of inKey and decrypted TPM_STORE_ASYMKEY + a. Reproduce inKey -> TPM_STORE_ASYMKEY -> pubDataDigest using the fields of inKey, and check + that the reproduced value is the same as pubDataDigest + */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_CheckPubDataDigest(inKey); + } + /* 7. Validate the consistency of the key and it's key usage. */ + /* a. If inKey -> keyFlags -> migratable is TRUE, the TPM SHALL verify consistency of the public + and private components of the asymmetric key pair. If inKey -> keyFlags -> migratable is + FALSE, the TPM MAY verify consistency of the public and private components of the asymmetric + key pair. The consistency of an RSA key pair MAY be verified by dividing the supposed (P*Q) + product by a supposed prime and checking that there is no remainder. + + This step is done at TPM_Key_Load() + */ + /* b. If inKey -> keyUsage is TPM_KEY_IDENTITY, verify that inKey->keyFlags->migratable is + FALSE. If it is not, return TPM_INVALID_KEYUSAGE + */ + if (rc == TPM_SUCCESS) { + if ((inKey->keyUsage == TPM_KEY_IDENTITY) && + (inKey->keyFlags & TPM_MIGRATABLE)) { + printf("TPM_LoadKeyCommon: Error, identity key is migratable\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* c. If inKey -> keyUsage is TPM_KEY_AUTHCHANGE, return TPM_INVALID_KEYUSAGE */ + if (rc == TPM_SUCCESS) { + if (inKey->keyUsage == TPM_KEY_AUTHCHANGE) { + printf("TPM_LoadKeyCommon: Error, keyUsage is TPM_KEY_AUTHCHANGE\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + /* d. If inKey -> keyFlags -> migratable equals 0 then verify that TPM_STORE_ASYMKEY -> + migrationAuth equals TPM_PERMANENT_DATA -> tpmProof */ + if (rc == TPM_SUCCESS) { + if (!(inKey->keyFlags & TPM_MIGRATABLE)) { + rc = TPM_Secret_Compare(tpm_state->tpm_permanent_data.tpmProof, + inKey->tpm_store_asymkey->migrationAuth); + if (rc != 0) { + printf("TPM_LoadKeyCommon: Error, tpmProof mismatch\n"); + rc = TPM_INVALID_KEYUSAGE; + } + } + } + /* e. Validate the mix of encryption and signature schemes + f. If TPM_PERMANENT_FLAGS -> FIPS is TRUE then + i. If keyInfo -> keySize is less than 1024 return TPM_NOTFIPS + ii. If keyInfo -> authDataUsage specifies TPM_AUTH_NEVER return + TPM_NOTFIPS + iii. If keyInfo -> keyUsage specifies TPM_KEY_LEGACY return + TPM_NOTFIPS + g. If inKey -> keyUsage is TPM_KEY_STORAGE or TPM_KEY_MIGRATE + i. algorithmID MUST be TPM_ALG_RSA + ii. Key size MUST be 2048 + iii. exponentSize MUST be 0 + iv. sigScheme MUST be TPM_SS_NONE + h. If inKey -> keyUsage is TPM_KEY_IDENTITY + i. algorithmID MUST be TPM_ALG_RSA + ii. Key size MUST be 2048 + iv. exponentSize MUST be 0 + iii. encScheme MUST be TPM_ES_NONE + NOTE Done in step 3. + */ + if (rc == TPM_SUCCESS) { + /* i. If the decrypted inKey -> pcrInfo is NULL, */ + /* i. The TPM MUST set the internal indicator to indicate that the key is not using any PCR + registers. */ + /* j. Else */ + /* i. The TPM MUST store pcrInfo in a manner that allows the TPM to calculate a composite + hash whenever the key will be in use */ + /* ii. The TPM MUST handle both version 1.1 TPM_PCR_INFO and 1.2 TPM_PCR_INFO_LONG + structures according to the type of TPM_KEY structure */ + /* (1) The TPM MUST validate the TPM_PCR_INFO or TPM_PCR_INFO_LONG structures for legal + values. However, the digestAtRelease and localityAtRelease are not validated for + authorization until use time.*/ + /* NOTE TPM_Key_Load() loads the TPM_PCR_INFO or TPM_PCR_INFO_LONG cache */ + } + /* 8. Perform any processing necessary to make TPM_STORE_ASYMKEY key available for + operations. */ + /* NOTE Done at TPM_Key_Load() */ + /* 9. Load key and key information into internal memory of the TPM. If insufficient memory + exists return error TPM_NOSPACE. */ + /* 10. Assign inKeyHandle according to internal TPM rules. */ + /* 11. Set InKeyHandle -> parentPCRStatus to parentHandle -> parentPCRStatus. */ + if (rc == TPM_SUCCESS) { + *inKeyHandle = 0; /* no preferred value */ + rc = TPM_KeyHandleEntries_AddKeyEntry(inKeyHandle, /* output */ + tpm_state->tpm_key_handle_entries, /* input */ + inKey, /* input */ + parentPCRStatus, + 0); /* keyControl */ + } + if (rc == TPM_SUCCESS) { + printf(" TPM_LoadKeyCommon: Loaded key handle %08x\n", *inKeyHandle); + /* remember that the handle has been added to handle list, so it can be deleted on error */ + *key_added = TRUE; + + } + /* 12. If parentHandle indicates it is using PCR registers then set inKeyHandle -> + parentPCRStatus to TRUE. */ + if (rc == TPM_SUCCESS) { + rc = TPM_Key_GetPCRUsage(&parentPCRUsage, parentKey, 0); + } + if (rc == TPM_SUCCESS) { + if (parentPCRUsage) { + rc = TPM_KeyHandleEntries_SetParentPCRStatus(tpm_state->tpm_key_handle_entries, + *inKeyHandle, TRUE); + } + } + return rc; +} + +/* 10.6 TPM_GetPubKey rev 102 + + 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_Process_GetPubKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* TPM handle of key. */ + TPM_AUTHHANDLE authHandle; /* The authorization handle used for keyHandle + authorization. */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /*The continue use flag for the authorization + handle */ + TPM_AUTHDATA keyAuth; /* Authorization HMAC key: key.usageAuth. */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_SECRET *hmacKey; + TPM_KEY *key = NULL; /* the key specified by keyHandle */ + TPM_BOOL parentPCRStatus; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_SECRET *keyUsageAuth; + TPM_STORE_BUFFER pubkeyStream; + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + const unsigned char *pubkeyStreamBuffer; /* output */ + uint32_t pubkeyStreamLength; + + printf("TPM_Process_GetPubKey: Ordinal Entry\n"); + TPM_Sbuffer_Init(&pubkeyStream); /* freed @1 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetPubKey: keyHandle %08x\n", keyHandle); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + keyAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetPubKey: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_GetPubKey: Key handle %08x\n", keyHandle); + returnCode = TPM_KeyHandleEntries_GetKey(&key, &parentPCRStatus, tpm_state, keyHandle, + TRUE, /* read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* 1. If tag = TPM_TAG_RQU_AUTH1_COMMAND then */ + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, key); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + key, + keyUsageAuth, /* OIAP */ + key->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + + + /* a. Validate the command parameters using keyHandle -> usageAuth, on error return + TPM_AUTHFAIL */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + keyAuth); /* Authorization digest for input */ + } + /* 2. Else */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)){ + /* a. Verify that keyHandle -> authDataUsage is TPM_NO_READ_PUBKEY_AUTH or TPM_AUTH_NEVER, + on error return TPM_AUTHFAIL */ +#ifdef TPM_V12 + if ((key->authDataUsage != TPM_NO_READ_PUBKEY_AUTH) && + (key->authDataUsage != TPM_AUTH_NEVER)) { + printf("TPM_Process_GetPubKey: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } +#else /* TPM 1.1 does not have TPM_NO_READ_PUBKEY_AUTH */ + if (key->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_GetPubKey: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } +#endif + } +#ifdef TPM_V12 /* TPM 1.1 does not have readSRKPub */ + if (returnCode == TPM_SUCCESS) { + /* 3. If keyHandle == TPM_KH_SRK then */ + if ((keyHandle == TPM_KH_SRK) && + /* a. If TPM_PERMANENT_FLAGS -> readSRKPub is FALSE then return TPM_INVALID_KEYHANDLE */ + !tpm_state->tpm_permanent_flags.readSRKPub) { + printf("TPM_Process_GetPubKey: " + "Error, keyHandle is TPM_KH_SRK and readSRKPub is FALSE\n"); + returnCode = TPM_INVALID_KEYHANDLE; + } + } +#endif + /* 4. If keyHandle -> pcrInfoSize is not 0 */ + /* a. If keyHandle -> keyFlags has pcrIgnoredOnRead set to FALSE */ + /* i. Create a digestAtRelease according to the specified PCR registers and compare + to keyHandle -> digestAtRelease and if a mismatch return TPM_WRONGPCRVAL */ + /* ii. If specified validate any locality requests */ + /* NOTE: Done at TPM_KeyHandleEntries_GetKey() */ + /* 5. Create a TPM_PUBKEY structure and return */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Key_StorePubkey(&pubkeyStream, /* output */ + &pubkeyStreamBuffer, /* output */ + &pubkeyStreamLength, /* output */ + key); /* input */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetPubKey: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* TPM_PUBKEY structure */ + returnCode = TPM_Sbuffer_Append(response, pubkeyStreamBuffer, pubkeyStreamLength); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_Sbuffer_Delete(&pubkeyStream); /* @1 */ + return rcf; +} diff --git a/src/tpm_storage.h b/src/tpm_storage.h new file mode 100644 index 00000000..4e23d123 --- /dev/null +++ b/src/tpm_storage.h @@ -0,0 +1,165 @@ +/********************************************************************************/ +/* */ +/* Storage Functions */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_storage.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_STORAGE_H +#define TPM_STORAGE_H + +#include "tpm_global.h" +#include "tpm_store.h" +#include "tpm_types.h" + +/* + TPM_BOUND_DATA +*/ + +void TPM_BoundData_Init(TPM_BOUND_DATA *tpm_bound_data); +TPM_RESULT TPM_BoundData_Load(TPM_BOUND_DATA *tpm_bound_data, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_BoundData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_BOUND_DATA *tpm_bound_data); +void TPM_BoundData_Delete(TPM_BOUND_DATA *tpm_bound_data); + +/* + TPM_SEALED_DATA +*/ + +void TPM_SealedData_Init(TPM_SEALED_DATA *tpm_sealed_data); +TPM_RESULT TPM_SealedData_Load(TPM_SEALED_DATA *tpm_sealed_data, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_SealedData_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_SEALED_DATA *tpm_sealed_data); +void TPM_SealedData_Delete(TPM_SEALED_DATA *tpm_sealed_data); + +TPM_RESULT TPM_SealedData_DecryptEncData(TPM_SEALED_DATA *tpm_sealed_data, + TPM_SIZED_BUFFER *enc_data, + TPM_KEY *tpm_key); +TPM_RESULT TPM_SealedData_GenerateEncData(TPM_SIZED_BUFFER *enc_data, + const TPM_SEALED_DATA *tpm_sealed_data, + TPM_KEY *tpm_key); + +/* + TPM_STORED_DATA +*/ + +void TPM_StoredData_Init(TPM_STORED_DATA *tpm_stored_data, + unsigned int version); +TPM_RESULT TPM_StoredData_Load(TPM_STORED_DATA *tpm_stored_data, + unsigned int *version, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_StoredData_Store(TPM_STORE_BUFFER *sbuffer, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version); +void TPM_StoredData_Delete(TPM_STORED_DATA *tpm_stored_data, + unsigned int version); + +TPM_RESULT TPM_StoredData_CheckTag(TPM_STORED_DATA12 *tpm_stored_data12); +TPM_RESULT TPM_StoredData_StoreClearData(TPM_STORE_BUFFER *sbuffer, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version); +TPM_RESULT TPM_StoredData_GenerateDigest(TPM_DIGEST tpm_digest, + TPM_STORED_DATA *tpm_stored_data, + unsigned int version); + +/* + Processing functions +*/ + +TPM_RESULT TPM_Process_Seal(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_Sealx(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_Unseal(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_UnBind(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_CreateWrapKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_LoadKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_LoadKey2(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_GetPubKey(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + + +#endif diff --git a/src/tpm_store.c b/src/tpm_store.c new file mode 100644 index 00000000..8e6a2e08 --- /dev/null +++ b/src/tpm_store.c @@ -0,0 +1,594 @@ +/********************************************************************************/ +/* */ +/* Safe Storage Buffer */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_store.c 4668 2012-01-25 21:16:48Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +/* Generally useful utilities to serialize structures to a stream */ + +#include +#include +#include + +#include "tpm_commands.h" +#include "tpm_constants.h" +#include "tpm_crypto.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_memory.h" +#include "tpm_process.h" + +#include "tpm_store.h" + +/* + ->buffer; beginning of buffer + ->buffer_current; first empty position in buffer + ->buffer_end; one past last valid position in buffer +*/ + +/* local prototypes */ + +static void TPM_Sbuffer_AdjustParamSize(TPM_STORE_BUFFER *sbuffer); +static TPM_RESULT TPM_Sbuffer_AdjustReturnCode(TPM_STORE_BUFFER *sbuffer, TPM_RESULT returnCode); + + +/* TPM_Sbuffer_Init() sets up a new serialize buffer. It should be called before the first use. */ + +void TPM_Sbuffer_Init(TPM_STORE_BUFFER *sbuffer) +{ + sbuffer->buffer = NULL; + sbuffer->buffer_current = NULL; + sbuffer->buffer_end = NULL; +} + +/* TPM_Sbuffer_Load() loads TPM_STORE_BUFFER that has been serialized using + TPM_Sbuffer_AppendAsSizedBuffer(), as a size plus stream. +*/ + +TPM_RESULT TPM_Sbuffer_Load(TPM_STORE_BUFFER *sbuffer, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t length; + + /* get the length of the stream to be loaded */ + if (rc == 0) { + rc = TPM_Load32(&length, stream, stream_size); + } + /* check stream_size */ + if (rc == 0) { + if (*stream_size < length) { + printf("TPM_Sbuffer_Load: Error, stream_size %u less than %u\n", + *stream_size, length); + rc = TPM_BAD_PARAM_SIZE; + } + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, *stream, length); + *stream += length; + *stream_size -= length; + } + return rc; +} + +/* TPM_Sbuffer_Store() cannot simply store the elements, as they are pointers. Rather, the + TPM_Sbuffer_AppendAsSizedBuffer() function is used. +*/ + +/* TPM_Sbuffer_Delete() frees an existing buffer and reinitializes it. It must be called when a + TPM_STORE_BUFFER is no longer required, to avoid a memory leak. The buffer can be reused, but in + that case TPM_Sbuffer_Clear would be a better choice. */ + +void TPM_Sbuffer_Delete(TPM_STORE_BUFFER *sbuffer) +{ + free(sbuffer->buffer); + TPM_Sbuffer_Init(sbuffer); +} + +/* TPM_Sbuffer_Clear() removes all data from an existing buffer, allowing reuse. Memory is NOT + freed. */ + +void TPM_Sbuffer_Clear(TPM_STORE_BUFFER *sbuffer) +{ + sbuffer->buffer_current = sbuffer->buffer; + return; +} + +/* TPM_Sbuffer_Get() gets the resulting byte buffer and its size. */ + +void TPM_Sbuffer_Get(TPM_STORE_BUFFER *sbuffer, + const unsigned char **buffer, + uint32_t *length) +{ + *length = sbuffer->buffer_current - sbuffer->buffer; + *buffer = sbuffer->buffer; + return; +} + +/* TPM_Sbuffer_GetAll() gets the resulting byte buffer and its size, as well as the total size. */ + +void TPM_Sbuffer_GetAll(TPM_STORE_BUFFER *sbuffer, + unsigned char **buffer, + uint32_t *length, + uint32_t *total) +{ + *length = sbuffer->buffer_current - sbuffer->buffer; + *total = sbuffer->buffer_end - sbuffer->buffer; + *buffer = sbuffer->buffer; + return; +} + +/* TPM_SBuffer_Set() creates a TPM_STORE_BUFFER from + + 'buffer' - pointer to a buffer that was allocated (can be NULL) + + 'total' - the total number of allocated bytes (ignored if buffer is NULL) + + 'length' - the number of valid bytes in buffer (ignored if buffer is NULL, can be 0, cannot be + greater than total. +*/ + +TPM_RESULT TPM_SBuffer_Set(TPM_STORE_BUFFER *sbuffer, + unsigned char *buffer, + const uint32_t length, + const uint32_t total) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if (sbuffer == NULL) { + printf("TPM_SBuffer_Set: Error (fatal), sbuffer is NULL\n"); + rc = TPM_FAIL; + } + } + if (rc == 0) { + if (buffer != NULL) { + if (rc == 0) { + if (length > total) { + printf("TPM_SBuffer_Set: Error (fatal), length %u > total %u\n", + length, total); + rc = TPM_FAIL; + } + } + if (rc == 0) { + sbuffer->buffer = buffer; + sbuffer->buffer_current = buffer + length; + sbuffer->buffer_end = buffer + total; + } + } + else { /* buffer == NULL */ + sbuffer->buffer = NULL; + sbuffer->buffer_current = NULL; + sbuffer->buffer_end = NULL; + } + } + return rc; +} + +/* TPM_Sbuffer_Append() is the basic function to append 'data' of size 'data_length' to the + TPM_STORE_BUFFER + + Returns 0 if success, TPM_SIZE if the buffer cannot be allocated. +*/ + +TPM_RESULT TPM_Sbuffer_Append(TPM_STORE_BUFFER *sbuffer, + const unsigned char *data, + size_t data_length) +{ + TPM_RESULT rc = 0; + size_t free_length; /* length of free bytes in current buffer */ + size_t current_size; /* size of current buffer */ + size_t current_length; /* bytes in current buffer */ + size_t new_size; /* size of new buffer */ + + /* can data fit? */ + if (rc == 0) { + /* cast safe as end is always greater than current */ + free_length = (size_t)(sbuffer->buffer_end - sbuffer->buffer_current); + /* if data cannot fit in buffer as sized */ + if (free_length < data_length) { + /* This test will fail long before the add uint32_t overflow */ + if (rc == 0) { + /* cast safe as current is always greater than start */ + current_length = (size_t)(sbuffer->buffer_current - sbuffer->buffer); + if ((current_length + data_length) > TPM_ALLOC_MAX) { + printf("TPM_Sbuffer_Append: " + "Error, size %lu + %lu greater than maximum allowed\n", + (unsigned long)current_length, (unsigned long)data_length); + rc = TPM_SIZE; + } + } + if (rc == 0) { + /* cast safe as end is always greater than start */ + current_size = (size_t)(sbuffer->buffer_end - sbuffer->buffer); + /* optimize realloc's by rounding up data_length to the next increment */ + new_size = current_size + /* currently used */ + ((((data_length - 1)/TPM_STORE_BUFFER_INCREMENT) + 1) * + TPM_STORE_BUFFER_INCREMENT); + /* but not greater than maximum buffer size */ + if (new_size > TPM_ALLOC_MAX) { + new_size = TPM_ALLOC_MAX; + } + printf(" TPM_Sbuffer_Append: data_length %lu, growing from %lu to %lu\n", + (unsigned long)data_length, + (unsigned long)current_size, + (unsigned long)new_size); + rc = TPM_Realloc(&(sbuffer->buffer), new_size); + } + if (rc == 0) { + sbuffer->buffer_end = sbuffer->buffer + new_size; /* end */ + sbuffer->buffer_current = sbuffer->buffer + current_length; /* new empty position */ + } + } + } + /* append the data */ + if (rc == 0) { + memcpy(sbuffer->buffer_current, data, data_length); + sbuffer->buffer_current += data_length; + } + return rc; +} + +/* TPM_Sbuffer_Append8() is a special append that appends a uint8_t + */ + +TPM_RESULT TPM_Sbuffer_Append8(TPM_STORE_BUFFER *sbuffer, uint8_t data) +{ + TPM_RESULT rc = 0; + + rc = TPM_Sbuffer_Append(sbuffer, (const unsigned char *)(&data), sizeof(uint8_t)); + return rc; +} + +/* TPM_Sbuffer_Append16() is a special append that converts a uint16_t to big endian (network byte + order) and appends. */ + +TPM_RESULT TPM_Sbuffer_Append16(TPM_STORE_BUFFER *sbuffer, uint16_t data) +{ + TPM_RESULT rc = 0; + + uint16_t ndata = htons(data); + rc = TPM_Sbuffer_Append(sbuffer, (const unsigned char *)(&ndata), sizeof(uint16_t)); + return rc; +} + +/* TPM_Sbuffer_Append32() is a special append that converts a uint32_t to big endian (network byte + order) and appends. */ + +TPM_RESULT TPM_Sbuffer_Append32(TPM_STORE_BUFFER *sbuffer, uint32_t data) +{ + TPM_RESULT rc = 0; + + uint32_t ndata = htonl(data); + rc = TPM_Sbuffer_Append(sbuffer, (const unsigned char *)(&ndata), sizeof(uint32_t)); + return rc; +} + +/* TPM_Sbuffer_AppendAsSizedBuffer() appends the source to the destination using the + TPM_SIZED_BUFFER idiom. That is, for a uint32_t size is stored. Then the data is stored. + + Use this function when the stream is not self-describing and a size must be prepended. +*/ + +TPM_RESULT TPM_Sbuffer_AppendAsSizedBuffer(TPM_STORE_BUFFER *destSbuffer, + TPM_STORE_BUFFER *srcSbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; + uint32_t length; + + if (rc == 0) { + TPM_Sbuffer_Get(srcSbuffer, &buffer, &length); + rc = TPM_Sbuffer_Append32(destSbuffer, length); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(destSbuffer, buffer, length); + } + return rc; +} + +/* TPM_Sbuffer_AppendSBuffer() appends the source to the destination. The size is not prepended, so + the stream must be self-describing. +*/ + +TPM_RESULT TPM_Sbuffer_AppendSBuffer(TPM_STORE_BUFFER *destSbuffer, + TPM_STORE_BUFFER *srcSbuffer) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; + uint32_t length; + + if (rc == 0) { + TPM_Sbuffer_Get(srcSbuffer, &buffer, &length); + rc = TPM_Sbuffer_Append(destSbuffer, buffer, length); + } + return rc; +} + +/* TPM_Sbuffer_StoreInitialResponse() is a special purpose append specific to a TPM response. + + It appends the first 3 standard response parameters: + - response_tag + - parameter size + - return code + + For some TPM commands, this is the entire response. Other times, additional parameters + will be appended. See TPM_Sbuffer_StoreFinalResponse(). + + Returns: + 0 success + TPM_SIZE response could not fit in buffer +*/ + +TPM_RESULT TPM_Sbuffer_StoreInitialResponse(TPM_STORE_BUFFER *response, + TPM_TAG request_tag, + TPM_RESULT returnCode) +{ + TPM_RESULT rc = 0; + TPM_TAG response_tag; + + printf(" TPM_Sbuffer_StoreInitialResponse: returnCode %08x\n", returnCode); + if (rc == 0) { + if (request_tag == TPM_TAG_RQU_COMMAND) { + response_tag = TPM_TAG_RSP_COMMAND; + } + else if (request_tag == TPM_TAG_RQU_AUTH1_COMMAND) { + response_tag = TPM_TAG_RSP_AUTH1_COMMAND; + } + else if (request_tag == TPM_TAG_RQU_AUTH2_COMMAND) { + response_tag = TPM_TAG_RSP_AUTH2_COMMAND; + } + /* input tag error, returnCode is handled by caller TPM_CheckRequestTag() */ + else { + response_tag = TPM_TAG_RSP_COMMAND; + } + } + /* tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(response, response_tag); + } + /* paramSize */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(response, + sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT)); + } + /* returnCode */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(response, returnCode); + } + return rc; +} + +/* TPM_Sbuffer_StoreFinalResponse() is a special purpose append specific to a TPM response. + + It is used after TPM_Sbuffer_StoreInitialResponse() and all additional parameters are appended. + + 1 - If the additional parameters were successfully appended, this function adjusts the + preliminary parameter size set by TPM_Sbuffer_StoreInitialResponse() to reflect the additional + appends. + + 2 - If there was a failure during the additional appends, this function adjusts the return code + and removes the additional appends. +*/ + +TPM_RESULT TPM_Sbuffer_StoreFinalResponse(TPM_STORE_BUFFER *sbuffer, + TPM_RESULT returnCode, + tpm_state_t *tpm_state) +{ + TPM_RESULT rc = 0; + const unsigned char *buffer; + uint32_t length; + + printf(" TPM_Sbuffer_StoreFinalResponse: returnCode %08x\n", returnCode); + /* determine whether the response would exceed the output buffer size */ + TPM_Sbuffer_Get(sbuffer, &buffer, &length); + if (length > TPM_BUFFER_MAX) { + printf("TPM_Sbuffer_StoreFinalResponse: Error, response buffer %u exceeds max %u\n", + length, TPM_BUFFER_MAX); + returnCode = TPM_SIZE; + } + if (returnCode == TPM_SUCCESS) { + TPM_Sbuffer_AdjustParamSize(sbuffer); + } + else { + /* TPM_FAIL is reserved for "should never occur" errors that indicate a software or hardware + failure */ + if ((returnCode == TPM_FAIL) && (tpm_state != NULL)) { + printf(" TPM_Sbuffer_StoreFinalResponse: Set testState to %u \n", + TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + rc = TPM_Sbuffer_AdjustReturnCode(sbuffer, returnCode); + } + return rc; +} + +/* TPM_Sbuffer_AdjustParamSize() is a special purpose function to go back and adjust the response + paramSize after the response buffer is complete +*/ + +static void TPM_Sbuffer_AdjustParamSize(TPM_STORE_BUFFER *sbuffer) +{ + uint32_t paramSize; /* the correct paramsize */ + uint32_t nParamSize; /* the correct paramsize, in network byte order */ + uint32_t paramSizeOffset; + + /* actual size */ + paramSize = sbuffer->buffer_current - sbuffer->buffer; + paramSizeOffset = sizeof(TPM_TAG); + nParamSize = htonl(paramSize); /* network byte order */ + /* overwrite the original size */ + memcpy(sbuffer->buffer + paramSizeOffset, &nParamSize, sizeof(uint32_t)); + return; +} + +/* TPM_Sbuffer_AdjustReturnCode() is a special function to go back and adjust the response tag and + returnCode if there was a failure while appending the rest of the parameters. + + This should never fail, because sbuffer was allocated during TPM_Sbuffer_StoreInitialResponse(). +*/ + +static TPM_RESULT TPM_Sbuffer_AdjustReturnCode(TPM_STORE_BUFFER *sbuffer, TPM_RESULT returnCode) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + /* erase the previous result without freeing the buffer */ + sbuffer->buffer_current = sbuffer->buffer; + /* error tag */ + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_RSP_COMMAND); + } + /* paramSize */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, sizeof(TPM_TAG) + sizeof(uint32_t) + sizeof(TPM_RESULT)); + } + /* returnCode */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, returnCode); + } + return rc; +} + +/* Test appending to the TPM_STORE_BUFFER up to the limit */ + +TPM_RESULT TPM_Sbuffer_Test(void) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + size_t total_count; + unsigned char count; + unsigned char data[256]; /* dummy data */ + + printf(" TPM_Sbuffer_Test:\n"); + TPM_Sbuffer_Init(&sbuffer); + total_count = 0; + while ((total_count != TPM_ALLOC_MAX) && rc == 0) { + if (rc == 0) { + rc = TPM_Random(&count, 1); + } + if (rc == 0) { + printf(" TPM_Sbuffer_Test: count %u\n", count); + /* last time through */ + if (total_count + count > TPM_ALLOC_MAX) { + count = TPM_ALLOC_MAX - total_count; + } + rc = TPM_Sbuffer_Append(&sbuffer,data, count); + } + if (rc == 0) { + total_count += count; + } + printf(" TPM_Sbuffer_Test: total_count %lu\n", (unsigned long)total_count); + } + TPM_Sbuffer_Delete(&sbuffer); + return rc; +} + +/* type to byte stream */ +void STORE32(unsigned char *buffer, unsigned int offset, uint32_t value) +{ + buffer[offset + 0] = value >> 24; + buffer[offset + 1] = value >> 16; + buffer[offset + 2] = value >> 8; + buffer[offset + 3] = value >> 0; +} + +void STORE16(unsigned char *buffer, unsigned int offset, uint16_t value) +{ + buffer[offset + 0] = value >> 8; + buffer[offset + 1] = value >> 0; +} + +void STORE8(unsigned char *buffer, unsigned int offset, uint8_t value) + +{ + buffer[offset + 0] = value >> 0; +} + +/* TPM_Bitmap_Load() is a safe loading of a TPM_BOOL from a bitmap. + + If 'pos' is >= 32, the function fails. + TPM_BOOL is TRUE. if The bit at pos is set + 'pos' is incremented after the load. +*/ + +TPM_RESULT TPM_Bitmap_Load(TPM_BOOL *tpm_bool, + uint32_t tpm_bitmap, + uint32_t *pos) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if ((*pos) >= (sizeof(uint32_t) * CHAR_BIT)) { + printf("TPM_Bitmap_Load: Error (fatal), loading from position %u\n", *pos); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + *tpm_bool = (tpm_bitmap & (1 << (*pos))) != 0; + (*pos)++; + } + return rc; +} + +/* TPM_Bitmap_Store() is a safe storing of a TPM_BOOL into a bitmap. + + If 'pos' is >= 32, the function fails. + The bit at pos is set if the TPM_BOOL is TRUE. + 'pos' is incremented after the store. +*/ + +TPM_RESULT TPM_Bitmap_Store(uint32_t *tpm_bitmap, + TPM_BOOL tpm_bool, + uint32_t *pos) +{ + TPM_RESULT rc = 0; + + if (rc == 0) { + if ((*pos) >= (sizeof(uint32_t) * CHAR_BIT)) { + printf("TPM_Bitmap_Store: Error (fatal), storing to position %u\n", *pos); + rc = TPM_FAIL; /* should never occur */ + } + } + if (rc == 0) { + if (tpm_bool) { + *tpm_bitmap |= (1 << (*pos)); + } + (*pos)++; + } + return rc; +} + diff --git a/src/tpm_store.h b/src/tpm_store.h new file mode 100644 index 00000000..46b36c6e --- /dev/null +++ b/src/tpm_store.h @@ -0,0 +1,109 @@ +/********************************************************************************/ +/* */ +/* Safe Storage Buffer */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_store.h 4668 2012-01-25 21:16:48Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_STORE_H +#define TPM_STORE_H + +#include "tpm_global.h" +#include "tpm_load.h" +#include "tpm_types.h" + +void TPM_Sbuffer_Init(TPM_STORE_BUFFER *sbuffer); +TPM_RESULT TPM_Sbuffer_Load(TPM_STORE_BUFFER *sbuffer, + unsigned char **stream, + uint32_t *stream_size); +/* TPM_Sbuffer_Store(): See TPM_Sbuffer_AppendAsSizedBuffer() */ +void TPM_Sbuffer_Delete(TPM_STORE_BUFFER *sbuffer); + +void TPM_Sbuffer_Clear(TPM_STORE_BUFFER *sbuffer); +void TPM_Sbuffer_Get(TPM_STORE_BUFFER *sbuffer, + const unsigned char **buffer, + uint32_t *length); +void TPM_Sbuffer_GetAll(TPM_STORE_BUFFER *sbuffer, + unsigned char **buffer, + uint32_t *length, + uint32_t *total); +TPM_RESULT TPM_SBuffer_Set(TPM_STORE_BUFFER *sbuffer, + unsigned char *buffer, + const uint32_t length, + const uint32_t total); + +TPM_RESULT TPM_Sbuffer_Append(TPM_STORE_BUFFER *sbuffer, + const unsigned char *data, + size_t data_length); + +TPM_RESULT TPM_Sbuffer_Append8(TPM_STORE_BUFFER *sbuffer, uint8_t data); +TPM_RESULT TPM_Sbuffer_Append16(TPM_STORE_BUFFER *sbuffer, uint16_t data); +TPM_RESULT TPM_Sbuffer_Append32(TPM_STORE_BUFFER *sbuffer, uint32_t data); +TPM_RESULT TPM_Sbuffer_AppendAsSizedBuffer(TPM_STORE_BUFFER *destSbuffer, + TPM_STORE_BUFFER *srcSbuffer); +TPM_RESULT TPM_Sbuffer_AppendSBuffer(TPM_STORE_BUFFER *destSbuffer, + TPM_STORE_BUFFER *srcSbuffer); + + +TPM_RESULT TPM_Sbuffer_StoreInitialResponse(TPM_STORE_BUFFER *response, + TPM_TAG response_tag, + TPM_RESULT returnCode); +TPM_RESULT TPM_Sbuffer_StoreFinalResponse(TPM_STORE_BUFFER *sbuffer, + TPM_RESULT returnCode, + tpm_state_t *tpm_state); + +TPM_RESULT TPM_Sbuffer_Test(void); + +/* type to byte stream */ + +void STORE32(unsigned char *buffer, unsigned int offset, uint32_t value); +void STORE16(unsigned char *buffer, unsigned int offset, uint16_t value); +void STORE8 (unsigned char *buffer, unsigned int offset, uint8_t value); + +/* load and store to bitmap */ + +TPM_RESULT TPM_Bitmap_Load(TPM_BOOL *tpm_bool, + uint32_t tpm_bitmap, + uint32_t *pos); +TPM_RESULT TPM_Bitmap_Store(uint32_t *tpm_bitmap, + TPM_BOOL tpm_bool, + uint32_t *pos); + +/* generic function prototype for a structure store callback function */ + +typedef TPM_RESULT (*TPM_STORE_FUNCTION_T )(TPM_STORE_BUFFER *sbuffer, + const void *tpm_structure); + +#endif diff --git a/src/tpm_structures.h b/src/tpm_structures.h new file mode 100644 index 00000000..f0b40d43 --- /dev/null +++ b/src/tpm_structures.h @@ -0,0 +1,2629 @@ +/********************************************************************************/ +/* */ +/* TPM Structures */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_structures.h 4528 2011-03-29 22:16:28Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_STRUCTURES_H +#define TPM_STRUCTURES_H + +#include +#include "tpm_constants.h" +#include "tpm_types.h" +#include "tpm_nvram_const.h" + +/* Sanity check on build macros are centralized here, since any TPM will use this header */ + +#if !defined (TPM_POSIX) && !defined (TPM_WINDOWS) && !defined(TPM_SYSTEM_P) +#error "Must define either TPM_POSIX or TPM_WINDOWS or TPM_SYSTEM_P" +#endif + +#if defined (TPM_NV_XCRYPTO_FLASH) && defined (TPM_NV_DISK) +#error "Cannot define TPM_NV_XCRYPTO_FLASH and TPM_NV_DISK" +#endif + +#if defined (TPM_WINDOWS) && defined (TPM_UNIX_DOMAIN_SOCKET) +#error "Cannot define TPM_WINDOWS and TPM_UNIX_DOMAIN_SOCKET" +#endif + +#if defined (TPM_USE_CHARDEV) && defined (TPM_UNIX_DOMAIN_SOCKET) +#error "Cannot define TPM_USE_CHARDEV and TPM_UNIX_DOMAIN_SOCKET" +#endif + +#if defined (TPM_NV_XCRYPTO_FLASH) && defined (TPM_UNIX_DOMAIN_SOCKET) +#error "Cannot define TPM_NV_XCRYPTO_FLASH and TPM_UNIX_DOMAIN_SOCKET" +#endif + +#if defined (TPM_XCRYPTO_USE_HW) && !defined(TPM_NV_XCRYPTO_FLASH) +#error "TPM_XCRYPTO_USE_HW requires TPM_NV_XCRYPTO_FLASH" +#endif + +#if defined (TPM_VTPM) && defined (TPM_UNIX_DOMAIN_SOCKET) +#error "Cannot define TPM_VTPM and TPM_UNIX_DOMAIN_SOCKET" +#endif + + + +#if defined (TPM_V11) && defined (TPM_V12) +#error "Cannot define TPM_V12 and TPM_V11" +#endif + +#if !defined (TPM_V11) && !defined (TPM_V12) +#error "Must define either TPM_V12 or TPM_V11" +#endif + +#if defined (TPM_DES) && defined (TPM_AES) +#error "Cannot define TPM_DES and TPM_AES" +#endif +#if !defined (TPM_DES) && !defined (TPM_AES) +#error "Must define either TPM_DES or TPM_AES" +#endif + +/* This structure is typically a cast from a subset of a larger TPM structure. Two members - a 4 + bytes size followed by a 4 bytes pointer to the data is a common TPM structure idiom. */ + +typedef struct tdTPM_SIZED_BUFFER { + uint32_t size; + BYTE *buffer; +} TPM_SIZED_BUFFER; + +/* This structure implements a safe storage buffer, used throughout the code when serializing + structures to a stream. +*/ + +typedef struct tdTPM_STORE_BUFFER { + unsigned char *buffer; /* beginning of buffer */ + unsigned char *buffer_current; /* first empty position in buffer */ + unsigned char *buffer_end; /* one past last valid position in buffer */ +} TPM_STORE_BUFFER; + +/* 5.1 TPM_STRUCT_VER rev 100 + + This indicates the version of the structure or TPM. + + Version 1.2 deprecates the use of this structure in all other structures. The structure is not + deprecated as many of the structures that contain this structure are not deprecated. +*/ + +#define TPM_MAJOR 0x01 + +#if defined TPM_V12 +#define TPM_MINOR 0x02 +#endif + +#if defined TPM_V11 +#define TPM_MINOR 0x01 +#endif + +typedef struct tdTPM_STRUCT_VER { + BYTE major; /* This SHALL indicate the major version of the structure. MUST be 0x01 */ + BYTE minor; /* This SHALL indicate the minor version of the structure. MUST be 0x01 */ + BYTE revMajor; /* This MUST be 0x00 on output, ignored on input */ + BYTE revMinor; /* This MUST be 0x00 on output, ignored on input */ +} TPM_STRUCT_VER; + +/* 5.2 TPM_VERSION_BYTE rev 87 + + Allocating a byte for the version information is wasteful of space. The current allocation does + not provide sufficient resolution to indicate completely the version of the TPM. To allow for + backwards compatibility the size of the structure does not change from 1.1. + + To enable minor version, or revision, numbers with 2-digit resolution, the byte representing a + version splits into two BDC encoded nibbles. The ordering of the low and high order provides + backwards compatibility with existing numbering. + + An example of an implementation of this is; a version of 1.23 would have the value 2 in bit + positions 3-0 and the value 3 in bit positions 7-4. + + TPM_VERSION_BYTE is a byte. The byte is broken up according to the following rule + + 7-4 leastSigVer Least significant nibble of the minor version. MUST be values within the range of + 0000-1001 + 3-0 mostSigVer Most significant nibble of the minor version. MUST be values within the range of + 0000-1001 +*/ + +/* 5.3 TPM_VERSION rev 116 + + 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; /* This SHALL indicate the major version of the TPM, mostSigVer MUST + be 0x1, leastSigVer MUST be 0x0 */ + TPM_VERSION_BYTE minor; /* This SHALL indicate the minor version of the TPM, mostSigVer MUST + be 0x1 or 0x2, leastSigVer MUST be 0x0 */ + BYTE revMajor; /* This SHALL be the value of the TPM_PERMANENT_DATA -> revMajor */ + BYTE revMinor; /* This SHALL be the value of the TPM_PERMANENT_DATA -> revMinor */ +} TPM_VERSION; + +/* 5.4 TPM_DIGEST rev 111 + + The digest value reports the result of a hash operation. + + In version 1 the hash algorithm is SHA-1 with a resulting hash result being 20 bytes or 160 bits. + + It is understood that algorithm agility is lost due to fixing the hash at 20 bytes and on + SHA-1. The reason for fixing is due to the internal use of the digest. It is the authorization + values, it provides the secrets for the HMAC and the size of 20 bytes determines the values that + can be stored and encrypted. For this reason, the size is fixed and any changes to this value + require a new version of the specification. + + The digestSize parameter MUST indicate the block size of the algorithm and MUST be 20 or greater. + + For all TPM v1 hash operations, the hash algorithm MUST be SHA-1 and the digestSize parameter is + therefore equal to 20. +*/ + +#define TPM_DIGEST_SIZE 20 +typedef BYTE TPM_DIGEST[TPM_DIGEST_SIZE]; + +#if 0 +/* kgold - This was designed as a structure with one element. Changed to a simple BYTE array, like + TPM_SECRET. */ +typedef struct tdTPM_DIGEST { + BYTE digest[TPM_DIGEST_SIZE]; /* This SHALL be the actual digest information */ +} TPM_DIGEST; +#endif + +/* Redefinitions */ + +typedef TPM_DIGEST TPM_CHOSENID_HASH; /* This SHALL be the digest of the chosen identityLabel and + privacyCA for a new TPM identity.*/ + +typedef TPM_DIGEST TPM_COMPOSITE_HASH; /* This SHALL be the hash of a list of PCR indexes and PCR + values that a key or data is bound to. */ + +typedef TPM_DIGEST TPM_DIRVALUE; /* This SHALL be the value of a DIR register */ + +typedef TPM_DIGEST TPM_HMAC; /* This shall be the output of the HMAC algorithm */ + +typedef TPM_DIGEST TPM_PCRVALUE; /* The value inside of the PCR */ + +typedef TPM_DIGEST TPM_AUDITDIGEST; /* This SHALL be the value of the current internal audit + state */ + +/* 5.5 TPM_NONCE rev 99 + + A nonce is a random value that provides protection from replay and other attacks. Many of the + commands and protocols in the specification require a nonce. This structure provides a consistent + view of what a nonce is. +*/ + +#define TPM_NONCE_SIZE 20 +typedef BYTE TPM_NONCE[TPM_NONCE_SIZE]; + +#if 0 +/* kgold - This was designed as a structure with one element. Changed to a simple BYTE array, like + TPM_SECRET. */ +typedef struct tdTPM_NONCE { + BYTE nonce[TPM_NONCE_SIZE]; /* This SHALL be the 20 bytes of random data. When created by the + TPM the value MUST be the next 20 bytes from the RNG */ +} TPM_NONCE; +#endif + +typedef TPM_NONCE TPM_DAA_TPM_SEED; /* This SHALL be a random value generated by a TPM + immediately after the EK is installed in that TPM, + whenever an EK is installed in that TPM */ +typedef TPM_NONCE TPM_DAA_CONTEXT_SEED; /* This SHALL be a random value */ + +/* 5.6 TPM_AUTHDATA rev 87 + + The authorization data is the information that is saved or passed to provide proof of ownership + of an entity. For version 1 this area is always 20 bytes. +*/ + +#define TPM_AUTHDATA_SIZE 20 +typedef BYTE TPM_AUTHDATA[TPM_AUTHDATA_SIZE]; + +#define TPM_SECRET_SIZE 20 +typedef BYTE TPM_SECRET[TPM_SECRET_SIZE]; + +#if 0 /* kgold - define TPM_SECRET directly, so the size can be defined */ +typedef TPM_AUTHDATA TPM_SECRET; /* A secret plain text value used in the authorization process. */ +#endif + +typedef TPM_AUTHDATA TPM_ENCAUTH; /* A cipher text (encrypted) version of authorization data. The + encryption mechanism depends on the context. */ + +/* 5.7 TPM_KEY_HANDLE_LIST rev 87 + + TPM_KEY_HANDLE_LIST is a structure used to describe the handles of all keys currently loaded into + a TPM. +*/ + +#if 0 /* This is the version from the specification part 2 */ +typedef struct tdTPM_KEY_HANDLE_LIST { + uint16_t loaded; /* The number of keys currently loaded in the TPM. */ + [size_is(loaded)] TPM_KEY_HANDLE handle[]; /* An array of handles, one for each key currently + loaded in the TPM */ +} TPM_KEY_HANDLE_LIST; +#endif + +/* 5.11 TPM_CHANGEAUTH_VALIDATE rev 87 + + This structure provides an area that will stores the new authorization data and the challenger's + nonce. +*/ + +typedef struct tdTPM_CHANGEAUTH_VALIDATE { + TPM_SECRET newAuthSecret; /* This SHALL be the new authorization data for the target entity */ + TPM_NONCE n1; /* This SHOULD be a nonce, to enable the caller to verify that the + target TPM is on-line. */ +} TPM_CHANGEAUTH_VALIDATE; + + + +/* PCR */ + +/* NOTE: The TPM requires and the code assumes a multiple of CHAR_BIT (8). 48 registers (6 bytes) + may be a bad number, as it makes TPM_PCR_INFO and TPM_PCR_INFO_LONG indistinguishable in the + first two bytes. */ + +#if defined TPM_V11 +#define TPM_NUM_PCR 16 /* Use PC Client specification values */ +#endif + +#if defined TPM_V12 +#define TPM_NUM_PCR 24 /* Use PC Client specification values */ +#endif + +#if (CHAR_BIT != 8) +#error "CHAR_BIT must be 8" +#endif + +#if ((TPM_NUM_PCR % 8) != 0) +#error "TPM_NUM_PCR must be a multiple of 8" +#endif + +/* 8.1 TPM_PCR_SELECTION rev 110 + + This structure provides a standard method of specifying a list of PCR registers. +*/ + +typedef struct tdTPM_PCR_SELECTION { + uint16_t sizeOfSelect; /* The size in bytes of the pcrSelect structure */ + BYTE pcrSelect[TPM_NUM_PCR/CHAR_BIT]; /* This SHALL be a bit map that indicates if a PCR + is active or not */ +} TPM_PCR_SELECTION; + +/* 8.2 TPM_PCR_COMPOSITE rev 97 + + 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; /* This SHALL be the indication of which PCR values are active */ +#if 0 + uint32_t valueSize; /* This SHALL be the size of the pcrValue field (not the number of + PCR's) */ + TPM_PCRVALUE *pcrValue; /* This SHALL be an array of TPM_PCRVALUE structures. The values + come in the order specified by the select parameter and are + concatenated into a single blob */ +#endif + TPM_SIZED_BUFFER pcrValue; +} TPM_PCR_COMPOSITE; + +/* 8.3 TPM_PCR_INFO rev 87 + + The TPM_PCR_INFO structure contains the information related to the wrapping of a key or the + sealing of data, to a set of PCRs. +*/ + +typedef struct tdTPM_PCR_INFO { + TPM_PCR_SELECTION pcrSelection; /* This SHALL be the selection of PCRs to which the + data or key is bound. */ + TPM_COMPOSITE_HASH digestAtRelease; /* This SHALL be the digest of the PCR indices and + PCR values to verify when revealing Sealed Data + or using a key that was wrapped to PCRs. NOTE: + This is passed in by the host, and used as + authorization to use the key */ + TPM_COMPOSITE_HASH digestAtCreation; /* This SHALL be the composite digest value of the + PCR values, at the time when the sealing is + performed. NOTE: This is generated at key + creation, but is just informative to the host, + not used for authorization */ +} TPM_PCR_INFO; + +/* 8.6 TPM_LOCALITY_SELECTION rev 87 + + 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; + +#define TPM_LOC_FOUR 0x10 /* Locality 4 */ +#define TPM_LOC_THREE 0x08 /* Locality 3 */ +#define TPM_LOC_TWO 0x04 /* Locality 2 */ +#define TPM_LOC_ONE 0x02 /* Locality 1 */ +#define TPM_LOC_ZERO 0x01 /* Locality 0. This is the same as the legacy interface. */ + +#define TPM_LOC_ALL 0x1f /* kgold - added all localities */ +#define TPM_LOC_MAX 4 /* kgold - maximum value for TPM_MODIFIER_INDICATOR */ + + +/* 8.4 TPM_PCR_INFO_LONG rev 109 + + The TPM_PCR_INFO structure contains the information related to the wrapping of a key or the + sealing of data, to a set of PCRs. + + The LONG version includes information necessary to properly define the configuration that creates + the blob using the PCR selection. +*/ + +typedef struct tdTPM_PCR_INFO_LONG { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_PCR_INFO_LONG */ +#endif + TPM_LOCALITY_SELECTION localityAtCreation; /* This SHALL be the locality modifier of the + function that creates the PCR info structure */ + TPM_LOCALITY_SELECTION localityAtRelease; /* This SHALL be the locality modifier required to + reveal Sealed Data or use a key that was wrapped + to PCRs */ + TPM_PCR_SELECTION creationPCRSelection; /* This SHALL be the selection of PCRs active when + the blob is created */ + TPM_PCR_SELECTION releasePCRSelection; /* This SHALL be the selection of PCRs to which the + data or key is bound. */ + TPM_COMPOSITE_HASH digestAtCreation; /* This SHALL be the composite digest value of the + PCR values, at the time when the sealing is + performed. */ + TPM_COMPOSITE_HASH digestAtRelease; /* This SHALL be the digest of the PCR indices and + PCR values to verify when revealing Sealed Data + or using a key that was wrapped to PCRs. */ +} TPM_PCR_INFO_LONG; + +/* 8.5 TPM_PCR_INFO_SHORT rev 87 + + This structure is for defining 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; /* This SHALL be the selection of PCRs that specifies the + digestAtRelease */ + TPM_LOCALITY_SELECTION localityAtRelease; /* This SHALL be the locality modifier required to + release the information. This value must not be + zero (0). */ + TPM_COMPOSITE_HASH digestAtRelease; /* This SHALL be the digest of the PCR indices and + PCR values to verify when revealing auth data */ +} TPM_PCR_INFO_SHORT; + +/* 8.8 TPM_PCR_ATTRIBUTES rev 107 + + These attributes are available on a per PCR basis. + + The TPM is not required to maintain this structure internally to the TPM. + + When a challenger evaluates a PCR an understanding of this structure is vital to the proper + understanding of the platform configuration. As this structure is static for all platforms of the + same type the structure does not need to be reported with each quote. +*/ + +typedef struct tdTPM_PCR_ATTRIBUTES { + TPM_BOOL pcrReset; /* A value of TRUE SHALL indicate that the PCR register can be reset + using the TPM_PCR_RESET command. */ + TPM_LOCALITY_SELECTION pcrExtendLocal; /* An indication of which localities can perform + extends on the PCR. */ + TPM_LOCALITY_SELECTION pcrResetLocal; /* An indication of which localities can reset the + PCR */ +} TPM_PCR_ATTRIBUTES; + +/* + 9. Storage Structures +*/ + +/* 9.1 TPM_STORED_DATA rev 87 + + The definition of this structure is necessary to ensure the enforcement of security properties. + + This structure is in use by the TPM_Seal and TPM_Unseal commands to identify the PCR index and + values that must be present to properly unseal the data. + + This structure only provides 1.1 data store and uses PCR_INFO + + 1. This structure is created during the TPM_Seal process. The confidential data is encrypted + using a nonmigratable key. When the TPM_Unseal decrypts this structure the TPM_Unseal uses the + public information in the structure to validate the current configuration and release the + decrypted data + + 2. When sealInfoSize is not 0 sealInfo MUST be TPM_PCR_INFO +*/ + +typedef struct tdTPM_STORED_DATA { + TPM_STRUCT_VER ver; /* This MUST be 1.1.0.0 */ + TPM_SIZED_BUFFER sealInfo; +#if 0 + uint32_t sealInfoSize; /* Size of the sealInfo parameter */ + BYTE* sealInfo; /* This SHALL be a structure of type TPM_PCR_INFO or a 0 length + array if the data is not bound to PCRs. */ +#endif + TPM_SIZED_BUFFER encData; +#if 0 + uint32_t encDataSize; /* This SHALL be the size of the encData parameter */ + BYTE* encData; /* This shall be an encrypted TPM_SEALED_DATA structure containing + the confidential part of the data. */ +#endif + /* NOTE: kgold - Added this structure, a cache of PCRInfo when not NULL */ + TPM_PCR_INFO *tpm_seal_info; +} TPM_STORED_DATA; + + +/* 9.2 TPM_STORED_DATA12 rev 101 + + The definition of this structure is necessary to ensure the enforcement of security properties. + This structure is in use by the TPM_Seal and TPM_Unseal commands to identify the PCR index and + values that must be present to properly unseal the data. + + 1. This structure is created during the TPM_Seal process. The confidential data is encrypted + using a nonmigratable key. When the TPM_Unseal decrypts this structure the TPM_Unseal uses the + public information in the structure to validate the current configuration and release the + decrypted data. + + 2. If sealInfoSize is not 0 then sealInfo MUST be TPM_PCR_INFO_LONG +*/ + +typedef struct tdTPM_STORED_DATA12 { + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_STORED_DATA12 */ + TPM_ENTITY_TYPE et; /* The type of blob */ + TPM_SIZED_BUFFER sealInfo; +#if 0 + uint32_t sealInfoSize; /* Size of the sealInfo parameter */ + BYTE* sealInfo; /* This SHALL be a structure of type TPM_PCR_INFO_LONG or a 0 length + array if the data is not bound to PCRs. */ +#endif + TPM_SIZED_BUFFER encData; +#if 0 + uint32_t encDataSize; /* This SHALL be the size of the encData parameter */ + BYTE* encData; /* This shall be an encrypted TPM_SEALED_DATA structure containing + the confidential part of the data. */ +#endif + /* NOTE: kgold - Added this structure, a cache of PCRInfo when not NULL */ + TPM_PCR_INFO_LONG *tpm_seal_info_long; +} TPM_STORED_DATA12; + +/* 9.3 TPM_SEALED_DATA rev 87 + + This structure contains confidential information related to sealed data, including the data + itself. + + 1. To tie the TPM_STORED_DATA structure to the TPM_SEALED_DATA structure this structure contains + a digest of the containing TPM_STORED_DATA structure. + + 2. The digest calculation does not include the encDataSize and encData parameters. +*/ + +typedef struct tdTPM_SEALED_DATA { + TPM_PAYLOAD_TYPE payload; /* This SHALL indicate the payload type of TPM_PT_SEAL */ + TPM_SECRET authData; /* This SHALL be the authorization data for this value */ + TPM_SECRET tpmProof; /* This SHALL be a copy of TPM_PERMANENT_FLAGS -> tpmProof */ + TPM_DIGEST storedDigest; /* This SHALL be a digest of the TPM_STORED_DATA structure, + excluding the fields TPM_STORED_DATA -> encDataSize and + TPM_STORED_DATA -> encData. */ + TPM_SIZED_BUFFER data; /* This SHALL be the data to be sealed */ +#if 0 + uint32_t dataSize; /* This SHALL be the size of the data parameter */ + BYTE* data; /* This SHALL be the data to be sealed */ +#endif +} TPM_SEALED_DATA; + + +/* 9.4 TPM_SYMMETRIC_KEY rev 87 + + This structure describes a symmetric key, used during the process "Collating a Request for a + Trusted Platform Module Identity". +*/ + +typedef struct tdTPM_SYMMETRIC_KEY { + TPM_ALGORITHM_ID algId; /* This SHALL be the algorithm identifier of the symmetric key. */ + TPM_ENC_SCHEME encScheme; /* This SHALL fully identify the manner in which the key will be + used for encryption operations. */ + uint16_t size; /* This SHALL be the size of the data parameter in bytes */ + BYTE* data; /* This SHALL be the symmetric key data */ + /* NOTE Cannot make this a TPM_SIZED_BUFFER because uint16_t */ +} TPM_SYMMETRIC_KEY; + +/* 9.5 TPM_BOUND_DATA rev 87 + + This structure is defined because it is used by a TPM_UnBind command in a consistency check. + + The intent of TCG is to promote "best practice" heuristics for the use of keys: a signing key + shouldn't be used for storage, and so on. These heuristics are used because of the potential + threats that arise when the same key is used in different ways. The heuristics minimize the + number of ways in which a given key can be used. + + One such heuristic is that a key of type TPM_KEY_BIND, and no other type of key, should always be + used to create the blob that is unwrapped by TPM_UnBind. Binding is not a TPM function, so the + only choice is to perform a check for the correct payload type when a blob is unwrapped by a key + of type TPM_KEY_BIND. This requires the blob to have internal structure. + + Even though payloadData has variable size, TPM_BOUND_DATA deliberately does not include the size + of payloadData. This is to maximise the size of payloadData that can be encrypted when + TPM_BOUND_DATA is encrypted in a single block. When using TPM-UnBind to obtain payloadData, the + size of payloadData is deduced as a natural result of the (RSA) decryption process. + + 1. This structure MUST be used for creating data when (wrapping with a key of type TPM_KEY_BIND) + or (wrapping using the encryption algorithm TPM_ES_RSAESOAEP_SHA1_MGF1). If it is not, the + TPM_UnBind command will fail. +*/ + +typedef struct tdTPM_BOUND_DATA { + TPM_STRUCT_VER ver; /* This MUST be 1.1.0.0 */ + TPM_PAYLOAD_TYPE payload; /* This SHALL be the value TPM_PT_BIND */ + uint32_t payloadDataSize; /* NOTE: added, not part of serialization */ + BYTE *payloadData; /* The bound data */ +} TPM_BOUND_DATA; + +/* + 10. TPM_KEY Complex +*/ + +/* 10.1.1 TPM_RSA_KEY_PARMS rev 87 + + This structure describes the parameters of an RSA key. +*/ + +/* TPM_RSA_KEY_LENGTH_MAX restricts the maximum size of an RSA key. It has two uses: + - bounds the size of the TPM state + - protects against a denial of service attack where the attacker creates a very large key +*/ + +#ifdef TPM_RSA_KEY_LENGTH_MAX /* if the builder defines a value */ +#if ((TPM_RSA_KEY_LENGTH_MAX % 16) != 0) +#error "TPM_RSA_KEY_LENGTH_MAX must be a multiple of 16" +#endif +#if (TPM_RSA_KEY_LENGTH_MAX < 2048) +#error "TPM_RSA_KEY_LENGTH_MAX must be at least 2048" +#endif +#endif /* TPM_RSA_KEY_LENGTH_MAX */ + +#ifndef TPM_RSA_KEY_LENGTH_MAX /* default if the builder does not define a value */ +#define TPM_RSA_KEY_LENGTH_MAX 2048 +#endif + +typedef struct tdTPM_RSA_KEY_PARMS { + uint32_t keyLength; /* This specifies the size of the RSA key in bits */ + uint32_t numPrimes; /* This specifies the number of prime factors used by this RSA key. */ +#if 0 + uint32_t exponentSize; /* This SHALL be the size of the exponent. If the key is using the + default exponent then the exponentSize MUST be 0. */ + BYTE *exponent; /* The public exponent of this key */ +#endif + TPM_SIZED_BUFFER exponent; /* The public exponent of this key */ + +} TPM_RSA_KEY_PARMS; + + +/* 10.1 TPM_KEY_PARMS rev 87 + + This provides a standard mechanism to define the parameters used to generate a key pair, and to + store the parts of a key shared between the public and private key parts. +*/ + +typedef struct tdTPM_KEY_PARMS { + TPM_ALGORITHM_ID algorithmID; /* This SHALL be the key algorithm in use */ + TPM_ENC_SCHEME encScheme; /* This SHALL be the encryption scheme that the key uses to encrypt + information */ + TPM_SIG_SCHEME sigScheme; /* This SHALL be the signature scheme that the key uses to perform + digital signatures */ +#if 0 + uint32_t parmSize; /* This SHALL be the size of the parms field in bytes */ + BYTE* parms; /* This SHALL be the parameter information dependent upon the key + algorithm. */ +#endif + TPM_SIZED_BUFFER parms; /* This SHALL be the parameter information dependent upon the key + algorithm. */ + /* NOTE: kgold - Added this structure. It acts as a cache of the result of parms and parmSize + deserialization when non-NULL. */ + TPM_RSA_KEY_PARMS *tpm_rsa_key_parms; +} TPM_KEY_PARMS; + +/* 10.1.2 TPM_SYMMETRIC_KEY_PARMS rev 87 + + This structure describes the parameters for symmetric algorithms +*/ + +typedef struct tdTPM_SYMMETRIC_KEY_PARMS { + uint32_t keyLength; /* This SHALL indicate the length of the key in bits */ + uint32_t blockSize; /* This SHALL indicate the block size of the algorithm*/ + uint32_t ivSize; /* This SHALL indicate the size of the IV */ + BYTE *IV; /* The initialization vector */ +} TPM_SYMMETRIC_KEY_PARMS; + +#if 0 +/* 10.4 TPM_STORE_PUBKEY rev 99 + + 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_t keyLength; /* This SHALL be the length of the key field. */ + BYTE *key; /* This SHALL be a structure interpreted according to the algorithm Id in + the corresponding TPM_KEY_PARMS structure. */ +} TPM_STORE_PUBKEY; +#endif + +/* 10.7 TPM_STORE_PRIVKEY rev 87 + + This structure can be used in conjunction with a corresponding TPM_PUBKEY to construct a private + key which can be unambiguously used. +*/ + +#if 0 +typedef struct tdTPM_STORE_PRIVKEY { + uint32_t keyLength; /* This SHALL be the length of the key field. */ + BYTE* key; /* This SHALL be a structure interpreted according to the algorithm Id in + the corresponding TPM_KEY structure. */ +} TPM_STORE_PRIVKEY; +#endif + +/* NOTE: Hard coded for RSA keys. This will change if other algorithms are supported */ + +typedef struct tdTPM_STORE_PRIVKEY { + TPM_SIZED_BUFFER d_key; /* private key */ + TPM_SIZED_BUFFER p_key; /* private prime factor */ + TPM_SIZED_BUFFER q_key; /* private prime factor */ +} TPM_STORE_PRIVKEY; + +/* 10.6 TPM_STORE_ASYMKEY rev 87 + + The TPM_STORE_ASYMKEY structure provides the area to identify the confidential information + related to a key. This will include the private key factors for an asymmetric key. + + The structure is designed so that encryption of a TPM_STORE_ASYMKEY structure containing a 2048 + bit RSA key can be done in one operation if the encrypting key is 2048 bits. + + Using typical RSA notation the structure would include P, and when loading the key include the + unencrypted P*Q which would be used to recover the Q value. + + To accommodate the future use of multiple prime RSA keys the specification of additional prime + factors is an optional capability. + + This structure provides the basis of defining the protection of the private key. Changes in this + structure MUST be reflected in the TPM_MIGRATE_ASYMKEY structure (section 10.8). +*/ + +typedef struct tdTPM_STORE_ASYMKEY { + TPM_PAYLOAD_TYPE payload; /* This SHALL set to TPM_PT_ASYM to indicate an asymmetric + key. If used in TPM_CMK_ConvertMigration the value SHALL + be TPM_PT_MIGRATE_EXTERNAL. If used in TPM_CMK_CreateKey + the value SHALL be TPM_PT_MIGRATE_RESTRICTED */ + TPM_SECRET usageAuth; /* This SHALL be the authorization data necessary to + authorize the use of this value */ + TPM_SECRET migrationAuth; /* This SHALL be the migration authorization data for a + migratable key, or the TPM secret value tpmProof for a + non-migratable key created by the TPM. + + If the TPM sets this parameter to the value tpmProof, + then the TPM_KEY.keyFlags.migratable of the corresponding + TPM_KEY structure MUST be set to 0. + + If this parameter is set to the migration authorization + data for the key in parameter PrivKey, then the + TPM_KEY.keyFlags.migratable of the corresponding TPM_KEY + structure SHOULD be set to 1. */ + TPM_DIGEST pubDataDigest; /* This SHALL be the digest of the corresponding TPM_KEY + structure, excluding the fields TPM_KEY.encSize and + TPM_KEY.encData. + + When TPM_KEY -> pcrInfoSize is 0 then the digest + calculation has no input from the pcrInfo field. The + pcrInfoSize field MUST always be part of the digest + calculation. + */ + TPM_STORE_PRIVKEY privKey; /* This SHALL be the private key data. The privKey can be a + variable length which allows for differences in the key + format. The maximum size of the area would be 151 + bytes. */ +} TPM_STORE_ASYMKEY; + +/* 10.8 TPM_MIGRATE_ASYMKEY rev 87 + + 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. + + This structure provides the basis of defining the protection of the private key. + + k1k2 - 132 privkey.key (128 + 4) + k1 - 20, OAEP seed + k2 - 112, partPrivKey + TPM_STORE_PRIVKEY 4 partPrivKey.keyLength + 108 partPrivKey.key (128 - 20) +*/ + +typedef struct tdTPM_MIGRATE_ASYMKEY { + TPM_PAYLOAD_TYPE payload; /* This SHALL set to TPM_PT_MIGRATE or TPM_PT_CMK_MIGRATE to + indicate an migrating asymmetric key or TPM_PT_MAINT to indicate + a maintenance key. */ + TPM_SECRET usageAuth; /* This SHALL be a copy of the usageAuth from the TPM_STORE_ASYMKEY + structure. */ + TPM_DIGEST pubDataDigest; /* This SHALL be a copy of the pubDataDigest from the + TPM_STORE_ASYMKEY structure. */ +#if 0 + uint32_t partPrivKeyLen; /* This SHALL be the size of the partPrivKey field */ + BYTE *partPrivKey; /* This SHALL be the k2 area as described in TPM_CreateMigrationBlob + */ +#endif + TPM_SIZED_BUFFER partPrivKey; +} TPM_MIGRATE_ASYMKEY; + +/* 10.2 TPM_KEY rev 87 + + The TPM_KEY structure provides a mechanism to transport the entire asymmetric key pair. The + private portion of the key is always encrypted. + + The reason for using a size and pointer for the PCR info structure is save space when the key is + not bound to a PCR. The only time the information for the PCR is kept with the key is when the + key needs PCR info. + + The 1.2 version has a change in the PCRInfo area. For 1.2 the structure uses the + TPM_PCR_INFO_LONG structure to properly define the PCR registers in use. +*/ + +typedef struct tdTPM_KEY { + TPM_STRUCT_VER ver; /* This MUST be 1.1.0.0 */ + TPM_KEY_USAGE keyUsage; /* This SHALL be the TPM key usage that determines the operations + permitted with this key */ + TPM_KEY_FLAGS keyFlags; /* This SHALL be the indication of migration, redirection etc.*/ + TPM_AUTH_DATA_USAGE authDataUsage; /* This SHALL Indicate the conditions where it is required + that authorization be presented.*/ + TPM_KEY_PARMS algorithmParms; /* This SHALL be the information regarding the algorithm for + this key*/ +#if 0 + uint32_t PCRInfoSize; /* This SHALL be the length of the pcrInfo parameter. If the key is + not bound to a PCR this value SHOULD be 0.*/ + BYTE* PCRInfo; /* This SHALL be a structure of type TPM_PCR_INFO, or an empty array + if the key is not bound to PCRs.*/ + TPM_STORE_PUBKEY pubKey; /* This SHALL be the public portion of the key */ + uint32_t encDataSize; /* This SHALL be the size of the encData parameter. */ + BYTE* encData; /* This SHALL be an encrypted TPM_STORE_ASYMKEY structure or + TPM_MIGRATE_ASYMKEY structure */ +#endif + TPM_SIZED_BUFFER pcrInfo; + TPM_SIZED_BUFFER pubKey; + TPM_SIZED_BUFFER encData; + /* This SHALL be an encrypted TPM_STORE_ASYMKEY structure or TPM_MIGRATE_ASYMKEY structure */ + /* NOTE: kgold - Added these structures, a cache of PCRInfo when not NULL */ + TPM_PCR_INFO *tpm_pcr_info; /* for TPM_KEY */ + TPM_PCR_INFO_LONG *tpm_pcr_info_long; /* for TPM_KEY12 */ + /* NOTE: kgold - Added these structures. They act as a cache of the result of encData + decryption when non-NULL. In the case of internal keys (e.g. SRK) there is no encData, so + these structures are always non-NULL. */ + TPM_STORE_ASYMKEY *tpm_store_asymkey; + TPM_MIGRATE_ASYMKEY *tpm_migrate_asymkey; +} TPM_KEY; + +/* 10.3 TPM_KEY12 rev 87 + + This provides the same functionality as TPM_KEY but uses the new PCR_INFO_LONG structures and the + new structure tagging. In all other aspects this is the same structure. +*/ + +/* NOTE: The TPM_KEY12 structure is never instantiated. It is just needed for the cast of TPM_KEY + to get the TPM_KEY12->tag member. */ + +typedef struct tdTPM_KEY12 { + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_KEY12 */ + uint16_t fill; /* MUST be 0x0000 */ + TPM_KEY_USAGE keyUsage; /* This SHALL be the TPM key usage that determines the operations + permitted with this key */ + TPM_KEY_FLAGS keyFlags; /* This SHALL be the indication of migration, redirection etc. */ + TPM_AUTH_DATA_USAGE authDataUsage; /* This SHALL Indicate the conditions where it is required + that authorization be presented. */ + TPM_KEY_PARMS algorithmParms; /* This SHALL be the information regarding the algorithm for + this key */ +#if 0 + uint32_t PCRInfoSize; /* This SHALL be the length of the pcrInfo parameter. If the key is + not bound to a PCR this value SHOULD be 0. */ + BYTE* PCRInfo; /* This SHALL be a structure of type TPM_PCR_INFO_LONG, or an empty + array if the key is not bound to PCRs. */ + TPM_STORE_PUBKEY pubKey; /* This SHALL be the public portion of the key */ + uint32_t encDataSize; /* This SHALL be the size of the encData parameter. */ + BYTE* encData; /* This SHALL be an encrypted TPM_STORE_ASYMKEY structure + TPM_MIGRATE_ASYMKEY structure */ +#endif + TPM_SIZED_BUFFER pcrInfo; + TPM_SIZED_BUFFER pubKey; + TPM_SIZED_BUFFER encData; +} TPM_KEY12; + + +/* 10.5 TPM_PUBKEY rev 99 + + The TPM_PUBKEY structure contains the public portion of an asymmetric key pair. It contains all + the information necessary for its unambiguous usage. It is possible to construct this structure + from a TPM_KEY, using the algorithmParms and pubKey fields. + + The pubKey member of this structure shall contain the public key for a specific algorithm. +*/ + +typedef struct tdTPM_PUBKEY { + TPM_KEY_PARMS algorithmParms; /* This SHALL be the information regarding this key */ +#if 0 + TPM_STORE_PUBKEY pubKey; /* This SHALL be the public key information */ +#endif + TPM_SIZED_BUFFER pubKey; +} TPM_PUBKEY; + +/* 5.b. The TPM must support a minimum of 2 key slots. */ + +#ifdef TPM_KEY_HANDLES +#if (TPM_KEY_HANDLES < 2) +#error "TPM_KEY_HANDLES minimum is 2" +#endif +#endif + +/* Set the default to 3 so that there can be one owner evict key */ + +#ifndef TPM_KEY_HANDLES +#define TPM_KEY_HANDLES 3 /* entries in global TPM_KEY_HANDLE_ENTRY array */ +#endif + +/* TPM_GetCapability uses a uint_16 for the number of key slots */ + +#if (TPM_KEY_HANDLES > 0xffff) +#error "TPM_KEY_HANDLES must be less than 0x10000" +#endif + +/* The TPM does not have to support any minumum number of owner evict keys. Adjust this value to + match the amount of NV space available. An owner evict key consumes about 512 bytes. + + A value greater than (TPM_KEY_HANDLES - 2) is useless, as the TPM reserves 2 key slots for + non-owner evict keys to avoid blocking. +*/ + +#ifndef TPM_OWNER_EVICT_KEY_HANDLES +#define TPM_OWNER_EVICT_KEY_HANDLES 1 +#endif + +#if (TPM_OWNER_EVICT_KEY_HANDLES > (TPM_KEY_HANDLES - 2)) +#error "TPM_OWNER_EVICT_KEY_HANDLES too large for TPM_KEY_HANDLES" +#endif + +/* This is the version used by the TPM implementation. It is part of the global TPM state */ + +/* kgold: Added TPM_KEY member. There needs to be a mapping between a key handle + and the pointer to TPM_KEY objects, and this seems to be the right place for it. */ + +typedef struct tdTPM_KEY_HANDLE_ENTRY { + TPM_KEY_HANDLE handle; /* Handles for a key currently loaded in the TPM */ + TPM_KEY *key; /* Pointer to the key object */ + TPM_BOOL parentPCRStatus; /* TRUE if parent of this key uses PCR's */ + TPM_KEY_CONTROL keyControl; /* Attributes that can control various aspects of key usage and + manipulation. */ +} TPM_KEY_HANDLE_ENTRY; + +/* 5.12 TPM_MIGRATIONKEYAUTH rev 87 + + This structure provides the proof that the associated public key has TPM Owner authorization to + be a migration key. +*/ + +typedef struct tdTPM_MIGRATIONKEYAUTH { + TPM_PUBKEY migrationKey; /* This SHALL be the public key of the migration facility */ + TPM_MIGRATE_SCHEME migrationScheme; /* This shall be the type of migration operation.*/ + TPM_DIGEST digest; /* This SHALL be the digest value of the concatenation of + migration key, migration scheme and tpmProof */ +} TPM_MIGRATIONKEYAUTH; + +/* 5.13 TPM_COUNTER_VALUE rev 87 + + This structure returns the counter value. For interoperability, the value size should be 4 bytes. +*/ + +#define TPM_COUNTER_LABEL_SIZE 4 +#define TPM_COUNT_ID_NULL 0xffffffff /* unused value TPM_CAP_PROP_ACTIVE_COUNTER expects this + value if no counter is active */ +#define TPM_COUNT_ID_ILLEGAL 0xfffffffe /* after releasing an active counter */ + +typedef struct tdTPM_COUNTER_VALUE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_COUNTER_VALUE */ +#endif + BYTE label[TPM_COUNTER_LABEL_SIZE]; /* The label for the counter */ + TPM_ACTUAL_COUNT counter; /* The 32-bit counter value. */ + /* NOTE: Added. TPMWG email says the specification structure is the public part, but these are + vendor specific private members. */ + TPM_SECRET authData; /* Authorization secret for counter */ + TPM_BOOL valid; + TPM_DIGEST digest; /* for OSAP comparison */ +} TPM_COUNTER_VALUE; + +/* 5.14 TPM_SIGN_INFO Structure rev 102 + + This is an addition in 1.2 and is the structure signed for certain commands (e.g., + TPM_ReleaseTransportSigned). Some commands have a structure specific to that command (e.g., + TPM_Quote uses TPM_QUOTE_INFO) and do not use TPM_SIGN_INFO. + + TPM_Sign uses this structure when the signature scheme is TPM_SS_RSASSAPKCS1v15_INFO. +*/ + +#define TPM_SIGN_INFO_FIXED_SIZE 4 + +typedef struct tdTPM_SIGN_INFO { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_SIGNINFO */ +#endif + BYTE fixed[TPM_SIGN_INFO_FIXED_SIZE]; /* The ASCII text that identifies what function was + performing the signing operation*/ + TPM_NONCE replay; /* Nonce provided by caller to prevent replay attacks */ +#if 0 + uint32_t dataLen; /* The length of the data area */ + BYTE* data; /* The data that is being signed */ +#endif + TPM_SIZED_BUFFER data; /* The data that is being signed */ +} TPM_SIGN_INFO; + +/* 5.15 TPM_MSA_COMPOSITE Structure rev 87 + + TPM_MSA_COMPOSITE contains an arbitrary number of digests of public keys belonging to Migration + Authorities. An instance of TPM_MSA_COMPOSITE is incorporated into the migrationAuth value of a + certified-migration-key (CMK), and any of the Migration Authorities specified in that instance is + able to approve the migration of that certified-migration-key. + + TPMs MUST support TPM_MSA_COMPOSITE structures with MSAlist of four (4) or less, and MAY support + larger values of MSAlist. +*/ + +typedef struct tdTPM_MSA_COMPOSITE { + uint32_t MSAlist; /* The number of migAuthDigests. MSAlist MUST be one (1) or + greater. */ + TPM_DIGEST *migAuthDigest; /* An arbitrary number of digests of public keys belonging + to Migration Authorities. */ +} TPM_MSA_COMPOSITE; + +/* 5.16 TPM_CMK_AUTH + + The signed digest of TPM_CMK_AUTH is a ticket to prove that the entity with public key + "migrationAuthority" has approved the public key "destination Key" as a migration destination for + the key with public key "sourceKey". + + Normally the digest of TPM_CMK_AUTH is signed by the private key corresponding to + "migrationAuthority". + + To reduce data size, TPM_CMK_AUTH contains just the digests of "migrationAuthority", + "destinationKey" and "sourceKey". +*/ + +typedef struct tdTPM_CMK_AUTH { + TPM_DIGEST migrationAuthorityDigest; /* The digest of the public key of a Migration + Authority */ + TPM_DIGEST destinationKeyDigest; /* The digest of a TPM_PUBKEY structure that is an + approved destination key for the private key + associated with "sourceKey"*/ + TPM_DIGEST sourceKeyDigest; /* The digest of a TPM_PUBKEY structure whose + corresponding private key is approved by the + Migration Authority to be migrated as a child to + the destinationKey. */ +} TPM_CMK_AUTH; + +/* 5.18 TPM_SELECT_SIZE rev 87 + + This structure provides the indication for the version and sizeOfSelect structure in GetCapability +*/ + +typedef struct tdTPM_SELECT_SIZE { + BYTE major; /* This SHALL indicate the major version of the TPM. This MUST be 0x01 */ + BYTE minor; /* This SHALL indicate the minor version of the TPM. This MAY be 0x01 or + 0x02 */ + uint16_t reqSize; /* This SHALL indicate the value for a sizeOfSelect field in the + TPM_SELECTION structure */ +} TPM_SELECT_SIZE; + +/* 5.19 TPM_CMK_MIGAUTH rev 89 + + Structure to keep track of the CMK migration authorization +*/ + +typedef struct tdTPM_CMK_MIGAUTH { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* Set to TPM_TAG_CMK_MIGAUTH */ +#endif + TPM_DIGEST msaDigest; /* The digest of a TPM_MSA_COMPOSITE structure containing the + migration authority public key and parameters. */ + TPM_DIGEST pubKeyDigest; /* The hash of the associated public key */ +} TPM_CMK_MIGAUTH; + +/* 5.20 TPM_CMK_SIGTICKET rev 87 + + Structure to keep track of the CMK migration authorization +*/ + +typedef struct tdTPM_CMK_SIGTICKET { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* Set to TPM_TAG_CMK_SIGTICKET */ +#endif + TPM_DIGEST verKeyDigest; /* The hash of a TPM_PUBKEY structure containing the public key and + parameters of the key that can verify the ticket */ + TPM_DIGEST signedData; /* The ticket data */ +} TPM_CMK_SIGTICKET; + +/* 5.21 TPM_CMK_MA_APPROVAL rev 87 + + Structure to keep track of the CMK migration authorization +*/ + +typedef struct tdTPM_CMK_MA_APPROVAL { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* Set to TPM_TAG_CMK_MA_APPROVAL */ +#endif + TPM_DIGEST migrationAuthorityDigest; /* The hash of a TPM_MSA_COMPOSITE structure + containing the hash of one or more migration + authority public keys and parameters. */ +} TPM_CMK_MA_APPROVAL; + +/* 20.2 Delegate Definitions rev 101 + + The delegations are in a 64-bit field. Each bit describes a capability that the TPM Owner 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. + + If a TPM command is not listed in the following table, then the TPM Owner cannot delegate that + capability to a trusted process. For the TPM commands that are listed in the following table, if + the bit associated with a TPM command is set to zero in the row of the table that identifies a + trusted process, then that process has not been delegated to use that TPM command. + + The minimum granularity for delegation is at the ordinal level. It is not possible to delegate an + option of an ordinal. This implies that if the options present a difficulty and there is a need + to separate the delegations then there needs to be a split into two separate ordinals. +*/ + +#define TPM_DEL_OWNER_BITS 0x00000001 +#define TPM_DEL_KEY_BITS 0x00000002 + +typedef struct tdTPM_DELEGATIONS { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_DELEGATIONS */ +#endif + uint32_t delegateType; /* Owner or key */ + uint32_t per1; /* The first block of permissions */ + uint32_t per2; /* The second block of permissions */ +} TPM_DELEGATIONS; + +/* 20.4 TPM_FAMILY_LABEL rev 85 + + Used in the family table to hold a one-byte numeric value (sequence number) that software can map + to a string of bytes that can be displayed or used by applications. + + This is not sensitive data. +*/ + +#if 0 +typedef struct tdTPM_FAMILY_LABEL { + BYTE label; /* A sequence number that software can map to a string of bytes that can be + displayed or used by the applications. This MUST not contain sensitive + information. */ +} TPM_FAMILY_LABEL; +#endif + +typedef BYTE TPM_FAMILY_LABEL; /* NOTE: No need for a structure here */ + +/* 20.5 TPM_FAMILY_TABLE_ENTRY rev 101 + + The family table entry is an individual row in the family table. There are no sensitive values in + a family table entry. + + Each family table entry contains values to facilitate table management: the familyID sequence + number value that associates a family table row with one or more delegate table rows, a + verification sequence number value that identifies when rows in the delegate table were last + verified, and BYTE family label value that software can map to an ASCII text description of the + entity using the family table entry +*/ + +typedef struct tdTPM_FAMILY_TABLE_ENTRY { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_FAMILY_TABLE_ENTRY */ +#endif + TPM_FAMILY_LABEL familyLabel; /* A sequence number that software can map to a string of + bytes that can be displayed of used by the applications. + This MUST not contain sensitive informations. */ + TPM_FAMILY_ID familyID; /* The family ID in use to tie values together. This is not + a sensitive value. */ + TPM_FAMILY_VERIFICATION verificationCount; /* The value inserted into delegation rows to + indicate that they are the current generation of + rows. Used to identify when a row in the delegate + table was last verified. This is not a sensitive + value. */ + TPM_FAMILY_FLAGS flags; /* See section on TPM_FAMILY_FLAGS. */ + /* NOTE Added */ + TPM_BOOL valid; +} TPM_FAMILY_TABLE_ENTRY; + +/* 20.6 TPM_FAMILY_TABLE rev 87 + + 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. +*/ + +#ifdef TPM_NUM_FAMILY_TABLE_ENTRY_MIN +#if (TPM_NUM_FAMILY_TABLE_ENTRY_MIN < 8) +#error "TPM_NUM_FAMILY_TABLE_ENTRY_MIN minimum is 8" +#endif +#endif + +#ifndef TPM_NUM_FAMILY_TABLE_ENTRY_MIN +#define TPM_NUM_FAMILY_TABLE_ENTRY_MIN 8 +#endif + +typedef struct tdTPM_FAMILY_TABLE { + TPM_FAMILY_TABLE_ENTRY famTableRow[TPM_NUM_FAMILY_TABLE_ENTRY_MIN]; +} TPM_FAMILY_TABLE; + +/* 20.7 TPM_DELEGATE_LABEL rev 87 + + Used in both the delegate table and the family table to hold a string of bytes that can be + displayed or used by applications. This is not sensitive data. +*/ + +#if 0 +typedef struct tdTPM_DELEGATE_LABEL { + BYTE label; /* A byte that can be displayed or used by the applications. This MUST not + contain sensitive information. */ +} TPM_DELEGATE_LABEL; +#endif + +typedef BYTE TPM_DELEGATE_LABEL; /* NOTE: No need for structure */ + +/* 20.8 TPM_DELEGATE_PUBLIC rev 101 + + The information of a delegate row that is public and does not have any sensitive information. + + PCR_INFO_SHORT is appropriate here as the command to create this is done using owner + authorization, hence the owner authorized the command and the delegation. There is no need to + validate what configuration was controlling the platform during the blob creation. +*/ + +typedef struct tdTPM_DELEGATE_PUBLIC { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_DELEGATE_PUBLIC */ +#endif + TPM_DELEGATE_LABEL rowLabel; /* This SHALL be the label for the row. It + MUST not contain any sensitive information. */ + TPM_PCR_INFO_SHORT pcrInfo; /* This SHALL be the designation of the process that can use + the permission. This is a not sensitive + value. PCR_SELECTION may be NULL. + + If selected the pcrInfo MUST be checked on each use of + the delegation. Use of the delegation is where the + delegation is passed as an authorization handle. */ + TPM_DELEGATIONS permissions; /* This SHALL be the permissions that are allowed to the + indicated process. This is not a sensitive value. */ + TPM_FAMILY_ID familyID; /* This SHALL be the family ID that identifies which family + the row belongs to. This is not a sensitive value. */ + TPM_FAMILY_VERIFICATION verificationCount; /* A copy of verificationCount from the associated + family table. This is not a sensitive value. */ +} TPM_DELEGATE_PUBLIC; + + +/* 20.9 TPM_DELEGATE_TABLE_ROW rev 101 + + A row of the delegate table. +*/ + +typedef struct tdTPM_DELEGATE_TABLE_ROW { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_DELEGATE_TABLE_ROW */ +#endif + TPM_DELEGATE_PUBLIC pub; /* This SHALL be the public information for a table row. */ + TPM_SECRET authValue; /* This SHALL be the authorization value that can use the + permissions. This is a sensitive value. */ + /* NOTE Added */ + TPM_BOOL valid; +} TPM_DELEGATE_TABLE_ROW; + +/* 20.10 TPM_DELEGATE_TABLE rev 87 + + This is the delegate table. The table contains a minimum of 2 rows. + + This will be an entry in the TPM_PERMANENT_DATA structure. +*/ + +#ifdef TPM_NUM_DELEGATE_TABLE_ENTRY_MIN +#if (TPM_NUM_DELEGATE_TABLE_ENTRY_MIN < 2) +#error "TPM_NUM_DELEGATE_TABLE_ENTRY_MIN minimum is 2" +#endif +#endif + +#ifndef TPM_NUM_DELEGATE_TABLE_ENTRY_MIN +#define TPM_NUM_DELEGATE_TABLE_ENTRY_MIN 2 +#endif + + +typedef struct tdTPM_DELEGATE_TABLE { + TPM_DELEGATE_TABLE_ROW delRow[TPM_NUM_DELEGATE_TABLE_ENTRY_MIN]; /* The array of delegations */ +} TPM_DELEGATE_TABLE; + +/* 20.11 TPM_DELEGATE_SENSITIVE rev 115 + + The TPM_DELEGATE_SENSITIVE structure is the area of a delegate blob that contains sensitive + information. + + This structure is normative for loading unencrypted blobs before there is an owner. It is + informative for TPM_CreateOwnerDelegation and TPM_LoadOwnerDelegation after there is an owner and + encrypted blobs are used, since the structure is under complete control of the TPM. +*/ + +typedef struct tdTPM_DELEGATE_SENSITIVE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This MUST be TPM_TAG_DELEGATE_SENSITIVE */ +#endif + TPM_SECRET authValue; /* AuthData value */ +} TPM_DELEGATE_SENSITIVE; + +/* 20.12 TPM_DELEGATE_OWNER_BLOB rev 87 + + This data structure contains all the information necessary to externally store a set of owner + delegation rights that can subsequently be loaded or used by this TPM. + + The encryption mechanism for the sensitive area is a TPM choice. The TPM may use asymmetric + encryption and the SRK for the key. The TPM may use symmetric encryption and a secret key known + only to the TPM. +*/ + +typedef struct tdTPM_DELEGATE_OWNER_BLOB { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This MUST be TPM_TAG_DELG_OWNER_BLOB */ +#endif + TPM_DELEGATE_PUBLIC pub; /* The public information for this blob */ + TPM_DIGEST integrityDigest; /* The HMAC to guarantee the integrity of the entire structure */ + TPM_SIZED_BUFFER additionalArea; /* An area that the TPM can add to the blob which MUST NOT + contain any sensitive information. This would include any + IV material for symmetric encryption */ + TPM_SIZED_BUFFER sensitiveArea; /* The area that contains the encrypted + TPM_DELEGATE_SENSITIVE */ +} TPM_DELEGATE_OWNER_BLOB; + +/* 20.13 TPM_DELEGATE_KEY_BLOB rev 87 + + A structure identical to TPM_DELEGATE_OWNER_BLOB but which stores delegation information for user + keys. As compared to TPM_DELEGATE_OWNER_BLOB, it adds a hash of the corresponding public key + value to the public information. +*/ + +typedef struct tdTPM_DELEGATE_KEY_BLOB { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This MUST be TPM_TAG_DELG_KEY_BLOB */ +#endif + TPM_DELEGATE_PUBLIC pub; /* The public information for this blob */ + TPM_DIGEST integrityDigest; /* The HMAC to guarantee the integrity of the entire + structure */ + TPM_DIGEST pubKeyDigest; /* The digest, that uniquely identifies the key for which + this usage delegation applies. */ + TPM_SIZED_BUFFER additionalArea; /* An area that the TPM can add to the blob which MUST NOT + contain any sensitive information. This would include any + IV material for symmetric encryption */ + TPM_SIZED_BUFFER sensitiveArea; /* The area that contains the encrypted + TPM_DELEGATE_SENSITIVE */ +} TPM_DELEGATE_KEY_BLOB; + +/* 15.1 TPM_CURRENT_TICKS rev 110 + + This structure holds the current number of time ticks in the TPM. The value is the number of time + ticks from the start of the current session. Session start is a variable function that is + platform dependent. Some platforms may have batteries or other power sources and keep the TPM + clock session across TPM initialization sessions. + + The element of the TPM_CURRENT_TICKS structure provides the number of microseconds per + tick. The platform manufacturer must satisfy input clock requirements set by the TPM vendor to + ensure the accuracy of the tickRate. + + No external entity may ever set the current number of time ticks held in TPM_CURRENT_TICKS. This + value is always reset to 0 when a new clock session starts and increments under control of the + TPM. + + Maintaining the relationship between the number of ticks counted by the TPM and some real world + clock is a task for external software. +*/ + +/* This is not a true UINT64, but a special structure to hold currentTicks */ + +typedef struct tdTPM_UINT64 { + uint32_t sec; + uint32_t usec; +} TPM_UINT64; + +typedef struct tdTPM_CURRENT_TICKS { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_CURRENT_TICKS */ +#endif + TPM_UINT64 currentTicks; /* The number of ticks since the start of this tick session */ + /* upper is seconds, lower is useconds */ + uint16_t tickRate; /* The number of microseconds per tick. The maximum resolution of + the TPM tick counter is thus 1 microsecond. The minimum + resolution SHOULD be 1 millisecond. */ + TPM_NONCE tickNonce; /* TPM_NONCE tickNonce The nonce created by the TPM when resetting + the currentTicks to 0. This indicates the beginning of a time + session. This value MUST be valid before the first use of + TPM_CURRENT_TICKS. The value can be set at TPM_Startup or just + prior to first use. */ + /* NOTE Added */ + TPM_UINT64 initialTime; /* Time from TPM_GetTimeOfDay() */ +} TPM_CURRENT_TICKS; + +/* + 13. Transport Structures +*/ + +/* 13.1 TPM _TRANSPORT_PUBLIC rev 87 + + The public information relative to a transport session +*/ + +typedef struct tdTPM_TRANSPORT_PUBLIC { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_TRANSPORT_PUBLIC */ +#endif + TPM_TRANSPORT_ATTRIBUTES transAttributes; /* The attributes of this session */ + TPM_ALGORITHM_ID algId; /* This SHALL be the algorithm identifier of the + symmetric key. */ + TPM_ENC_SCHEME encScheme; /* This SHALL fully identify the manner in which the + key will be used for encryption operations. */ +} TPM_TRANSPORT_PUBLIC; + +/* 13.2 TPM_TRANSPORT_INTERNAL rev 88 + + The internal information regarding transport session +*/ + +/* 7.6 TPM_STANY_DATA */ + +#ifdef TPM_MIN_TRANS_SESSIONS +#if (TPM_MIN_TRANS_SESSIONS < 3) +#error "TPM_MIN_TRANS_SESSIONS minimum is 3" +#endif +#endif + +#ifndef TPM_MIN_TRANS_SESSIONS +#define TPM_MIN_TRANS_SESSIONS 3 +#endif + +typedef struct tdTPM_TRANSPORT_INTERNAL { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_TRANSPORT_INTERNAL */ +#endif + TPM_AUTHDATA authData; /* The shared secret for this session */ + TPM_TRANSPORT_PUBLIC transPublic; /* The public information of this session */ + TPM_TRANSHANDLE transHandle; /* The handle for this session */ + TPM_NONCE transNonceEven; /* The even nonce for the rolling protocol */ + TPM_DIGEST transDigest; /* The log of transport events */ + /* added kgold */ + TPM_BOOL valid; /* entry is valid */ +} TPM_TRANSPORT_INTERNAL; + +/* 13.3 TPM_TRANSPORT_LOG_IN rev 87 + + The logging of transport commands occurs in two steps, before execution with the input + parameters and after execution with the output parameters. + + This structure is in use for input log calculations. +*/ + +typedef struct tdTPM_TRANSPORT_LOG_IN { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_TRANSPORT_LOG_IN */ +#endif + TPM_DIGEST parameters; /* The actual parameters contained in the digest are subject to the + rules of the command using this structure. To find the exact + calculation refer to the actions in the command using this + structure. */ + TPM_DIGEST pubKeyHash; /* The hash of any keys in the transport command */ +} TPM_TRANSPORT_LOG_IN; + +/* 13.4 TPM_TRANSPORT_LOG_OUT rev 88 + + The logging of transport commands occurs in two steps, before execution with the input parameters + and after execution with the output parameters. + + This structure is in use for output log calculations. + + This structure is in use for the INPUT logging during releaseTransport. +*/ + +typedef struct tdTPM_TRANSPORT_LOG_OUT { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_TRANSPORT_LOG_OUT */ +#endif + TPM_CURRENT_TICKS currentTicks; /* The current tick count. This SHALL be the value of the + current TPM tick counter. */ + TPM_DIGEST parameters; /* The actual parameters contained in the digest are subject + to the rules of the command using this structure. To find + the exact calculation refer to the actions in the command + using this structure. */ + TPM_MODIFIER_INDICATOR locality; /* The locality that called TPM_ExecuteTransport */ +} TPM_TRANSPORT_LOG_OUT; + +/* 13.5 TPM_TRANSPORT_AUTH structure rev 87 + + This structure provides the validation for the encrypted AuthData value. +*/ + +typedef struct tdTPM_TRANSPORT_AUTH { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_TRANSPORT_AUTH */ +#endif + TPM_AUTHDATA authData; /* The AuthData value */ +} TPM_TRANSPORT_AUTH; + +/* 22.3 TPM_DAA_ISSUER rev 91 + + This structure is the abstract representation of non-secret settings controlling a DAA + context. The structure is required when loading public DAA data into a TPM. TPM_DAA_ISSUER + parameters are normally held outside the TPM as plain text data, and loaded into a TPM when a DAA + session is required. A TPM_DAA_ISSUER structure contains no integrity check: the TPM_DAA_ISSUER + structure at time of JOIN is indirectly verified by the issuer during the JOIN process, and a + digest of the verified TPM_DAA_ISSUER structure is held inside the TPM_DAA_TPM structure created + by the JOIN process. Parameters DAA_digest_X are digests of public DAA_generic_X parameters, and + used to verify that the correct value of DAA_generic_X has been loaded. DAA_generic_q is stored + in its native form to reduce command complexity. +*/ + +typedef struct tdTPM_DAA_ISSUER { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DAA_ISSUER */ +#endif + TPM_DIGEST DAA_digest_R0; /* A digest of the parameter "R0", which is not secret and may be + common to many TPMs. */ + TPM_DIGEST DAA_digest_R1; /* A digest of the parameter "R1", which is not secret and may be + common to many TPMs. */ + TPM_DIGEST DAA_digest_S0; /* A digest of the parameter "S0", which is not secret and may be + common to many TPMs. */ + TPM_DIGEST DAA_digest_S1; /* A digest of the parameter "S1", which is not secret and may be + common to many TPMs. */ + TPM_DIGEST DAA_digest_n; /* A digest of the parameter "n", which is not secret and may be + common to many TPMs. */ + TPM_DIGEST DAA_digest_gamma; /* A digest of the parameter "gamma", which is not secret + and may be common to many TPMs. */ + BYTE DAA_generic_q[26]; /* The parameter q, which is not secret and may be common to + many TPMs. Note that q is slightly larger than a digest, + but is stored in its native form to simplify the + TPM_DAA_join command. Otherwise, JOIN requires 3 input + parameters. */ +} TPM_DAA_ISSUER; + +/* 22.4 TPM_DAA_TPM rev 91 + + This structure is the abstract representation of TPM specific parameters used during a DAA + context. TPM-specific DAA parameters may be stored outside the TPM, and hence this + structure is needed to save private DAA data from a TPM, or load private DAA data into a + TPM. + + If a TPM_DAA_TPM structure is stored outside the TPM, it is stored in a confidential format that + can be interpreted only by the TPM created it. This is to ensure that secret parameters are + rendered confidential, and that both secret and non-secret data in TPM_DAA_TPM form a + self-consistent set. + + TPM_DAA_TPM includes a digest of the public DAA parameters that were used during creation of the + TPM_DAA_TPM structure. This is needed to verify that a TPM_DAA_TPM is being used with the public + DAA parameters used to create the TPM_DAA_TPM structure. Parameters DAA_digest_v0 and + DAA_digest_v1 are digests of public DAA_private_v0 and DAA_private_v1 parameters, and used to + verify that the correct private parameters have been loaded. + + Parameter DAA_count is stored in its native form, because it is smaller than a digest, and is + required to enforce consistency. +*/ + +typedef struct tdTPM_DAA_TPM { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DAA_TPM */ +#endif + TPM_DIGEST DAA_digestIssuer; /* A digest of a TPM_DAA_ISSUER structure that contains the + parameters used to generate this TPM_DAA_TPM + structure. */ + TPM_DIGEST DAA_digest_v0; /* A digest of the parameter "v0", which is secret and specific to + this TPM. "v0" is generated during a JOIN phase. */ + TPM_DIGEST DAA_digest_v1; /* A digest of the parameter "v1", which is secret and specific to + this TPM. "v1" is generated during a JOIN phase. */ + TPM_DIGEST DAA_rekey; /* A digest related to the rekeying process, which is not secret but + is specific to this TPM, and must be consistent across JOIN/SIGN + sessions. "rekey" is generated during a JOIN phase. */ + uint32_t DAA_count; /* The parameter "count", which is not secret but must be consistent + across JOIN/SIGN sessions. "count" is an input to the TPM from + the host system. */ +} TPM_DAA_TPM; + +/* 22.5 TPM_DAA_CONTEXT rev 91 + + TPM_DAA_CONTEXT structure is created and used inside a TPM, and never leaves the TPM. This + entire section is informative as the TPM does not expose this structure. TPM_DAA_CONTEXT + includes a digest of the public and private DAA parameters that were used during creation of the + TPM_DAA_CONTEXT structure. This is needed to verify that a TPM_DAA_CONTEXT is being used with the + public and private DAA parameters used to create the TPM_DAA_CONTEXT structure. +*/ + +typedef struct tdTPM_DAA_CONTEXT { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DAA_CONTEXT */ +#endif + TPM_DIGEST DAA_digestContext; /* A digest of parameters used to generate this + structure. The parameters vary, depending on whether the + session is a JOIN session or a SIGN session. */ + TPM_DIGEST DAA_digest; /* A running digest of certain parameters generated during DAA + computation; operationally the same as a PCR (which holds a + running digest of integrity metrics). */ + TPM_DAA_CONTEXT_SEED DAA_contextSeed; /* The seed used to generate other DAA + session parameters */ + BYTE DAA_scratch[256]; /* Memory used to hold different parameters at different + times of DAA computation, but only one parameter at a + time. The maximum size of this field is 256 bytes */ + BYTE DAA_stage; /* A counter, indicating the stage of DAA computation that was most + recently completed. The value of the counter is zero if the TPM + currently contains no DAA context. + + When set to zero (0) the TPM MUST clear all other fields in this + structure. + + The TPM MUST set DAA_stage to 0 on TPM_Startup(ANY) */ + TPM_BOOL DAA_scratch_null; +} TPM_DAA_CONTEXT; + +/* 22.6 TPM_DAA_JOINDATA rev 91 + + 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]; /* A TPM-specific secret "u0", used during the JOIN phase, + and discarded afterwards. */ + BYTE DAA_join_u1[138]; /* A TPM-specific secret "u1", used during the JOIN phase, + and discarded afterwards. */ + TPM_DIGEST DAA_digest_n0; /* A digest of the parameter "n0", which is an RSA public key with + exponent 2^16 +1 */ +} TPM_DAA_JOINDATA; + +/* DAA Session structure + +*/ + +#ifdef TPM_MIN_DAA_SESSIONS +#if (TPM_MIN_DAA_SESSIONS < 1) +#error "TPM_MIN_DAA_SESSIONS minimum is 1" +#endif +#endif + +#ifndef TPM_MIN_DAA_SESSIONS +#define TPM_MIN_DAA_SESSIONS 1 +#endif + +typedef struct tdTPM_DAA_SESSION_DATA { + TPM_DAA_ISSUER DAA_issuerSettings; /* A set of DAA issuer parameters controlling a DAA + session. (non-secret) */ + TPM_DAA_TPM DAA_tpmSpecific; /* A set of DAA parameters associated with a + specific TPM. (secret) */ + TPM_DAA_CONTEXT DAA_session; /* A set of DAA parameters associated with a DAA + session. (secret) */ + TPM_DAA_JOINDATA DAA_joinSession; /* A set of DAA parameters used only during the JOIN + phase of a DAA session, and generated by the + TPM. (secret) */ + /* added kgold */ + TPM_HANDLE daaHandle; /* DAA session handle */ + TPM_BOOL valid; /* array entry is valid */ + /* FIXME should have handle type Join or Sign */ +} TPM_DAA_SESSION_DATA; + +/* 22.8 TPM_DAA_BLOB rev 98 + + The structure passed during the join process +*/ + +typedef struct tdTPM_DAA_BLOB { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DAA_BLOB */ +#endif + TPM_RESOURCE_TYPE resourceType; /* The resource type: enc(DAA_tpmSpecific) or enc(v0) or + enc(v1) */ + BYTE label[16]; /* Label for identification of the blob. Free format + area. */ + TPM_DIGEST blobIntegrity; /* The integrity of the entire blob including the sensitive + area. This is a HMAC calculation with the entire + structure (including sensitiveData) being the hash and + daaProof is the secret */ + TPM_SIZED_BUFFER additionalData; /* Additional information set by the TPM that helps define + and reload the context. The information held in this area + MUST NOT expose any information held in shielded + locations. This should include any IV for symmetric + encryption */ + TPM_SIZED_BUFFER sensitiveData; /* A TPM_DAA_SENSITIVE structure */ +#if 0 + uint32_t additionalSize; + [size_is(additionalSize)] BYTE* additionalData; + uint32_t sensitiveSize; + [size_is(sensitiveSize)] BYTE* sensitiveData; +#endif +} TPM_DAA_BLOB; + +/* 22.9 TPM_DAA_SENSITIVE rev 91 + + The encrypted area for the DAA parameters +*/ + +typedef struct tdTPM_DAA_SENSITIVE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DAA_SENSITIVE */ +#endif + TPM_SIZED_BUFFER internalData; /* DAA_tpmSpecific or DAA_private_v0 or DAA_private_v1 */ +#if 0 + uint32_t internalSize; + [size_is(internalSize)] BYTE* internalData; +#endif +} TPM_DAA_SENSITIVE; + +/* 7.1 TPM_PERMANENT_FLAGS rev 110 + + These flags maintain state information for the TPM. The values are not affected by any + TPM_Startup command. + + The flag history includes: + + Rev 62 specLevel 1 errataRev 0: 15 BOOLs + Rev 85 specLevel 2 errataRev 0: 19 BOOLs + Added: nvLocked, readSRKPub, tpmEstablished, maintenanceDone + Rev 94 specLevel 2 errataRev 1: 19 BOOLs + Rev 103 specLevel 2 errataRev 2: 20 BOOLs + Added: disableFullDALogicInfo +*/ + +typedef struct tdTPM_PERMANENT_FLAGS { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_PERMANENT_FLAGS */ +#endif + TPM_BOOL disable; /* disable The state of the disable flag. The default state is TRUE + */ + TPM_BOOL ownership; /* The ability to install an owner. The default state is TRUE. */ + TPM_BOOL deactivated; /* The state of the inactive flag. The default state is TRUE. */ + TPM_BOOL readPubek; /* The ability to read the PUBEK without owner authorization. The + default state is TRUE. + + set TRUE on owner clear + set FALSE on take owner, disablePubekRead + */ + TPM_BOOL disableOwnerClear; /* Whether the owner authorized clear commands are active. The + default state is FALSE. */ + TPM_BOOL allowMaintenance; /* Whether the TPM Owner may create a maintenance archive. The + default state is TRUE. */ + TPM_BOOL physicalPresenceLifetimeLock; /* This bit can only be set to TRUE; it cannot be set to + FALSE except during the manufacturing process. + + FALSE: The state of either physicalPresenceHWEnable or + physicalPresenceCMDEnable MAY be changed. (DEFAULT) + + TRUE: The state of either physicalPresenceHWEnable or + physicalPresenceCMDEnable MUST NOT be changed for the + life of the TPM. */ + TPM_BOOL physicalPresenceHWEnable; /* FALSE: Disable the hardware signal indicating physical + presence. (DEFAULT) + + TRUE: Enables the hardware signal indicating physical + presence. */ + TPM_BOOL physicalPresenceCMDEnable; /* FALSE: Disable the command indicating physical + presence. (DEFAULT) + + TRUE: Enables the command indicating physical + presence. */ + TPM_BOOL CEKPUsed; /* TRUE: The PRIVEK and PUBEK were created using + TPM_CreateEndorsementKeyPair. + + FALSE: The PRIVEK and PUBEK were created using a manufacturer's + process. NOTE: This flag has no default value as the key pair + MUST be created by one or the other mechanism. */ + TPM_BOOL TPMpost; /* TRUE: After TPM_Startup, if there is a call to + TPM_ContinueSelfTest the TPM MUST execute the actions of + TPM_SelfTestFull + + FALSE: After TPM_Startup, if there is a call to + TPM_ContinueSelfTest the TPM MUST execute TPM_ContinueSelfTest + + If the TPM supports the implicit invocation of + TPM_ContinueSelftTest upon the use of an untested resource, the + TPM MUST use the TPMPost flag to call either TPM_ContinueSelfTest + or TPM_SelfTestFull + + The TPM manufacturer sets this bit during TPM manufacturing and + the bit is unchangeable after shipping the TPM + + The default state is FALSE */ + TPM_BOOL TPMpostLock; /* With the clarification of TPMPost TPMpostLock is now + unnecessary. + This flag is now deprecated */ + TPM_BOOL FIPS; /* TRUE: This TPM operates in FIPS mode + FALSE: This TPM does NOT operate in FIPS mode */ + TPM_BOOL tpmOperator; /* TRUE: The operator authorization value is valid + FALSE: the operator authorization value is not set */ + TPM_BOOL enableRevokeEK; /* TRUE: The TPM_RevokeTrust command is active + FALSE: the TPM RevokeTrust command is disabled */ + TPM_BOOL nvLocked; /* TRUE: All NV area authorization checks are active + FALSE: No NV area checks are performed, except for maxNVWrites. + FALSE is the default value */ + TPM_BOOL readSRKPub; /* TRUE: GetPubKey will return the SRK pub key + FALSE: GetPubKey will not return the SRK pub key + Default SHOULD be FALSE */ + TPM_BOOL tpmEstablished; /* TRUE: TPM_HASH_START has been executed at some time + FALSE: TPM_HASH_START has not been executed at any time + Default is FALSE - resets using TPM_ResetEstablishmentBit */ + TPM_BOOL maintenanceDone; /* TRUE: A maintenance archive has been created for the current + SRK */ +#if (TPM_REVISION >= 103) /* added for rev 103 */ + TPM_BOOL disableFullDALogicInfo; /* TRUE: The full dictionary attack TPM_GetCapability info is + deactivated. The returned structure is TPM_DA_INFO_LIMITED. + FALSE: The full dictionary attack TPM_GetCapability info is + activated. The returned structure is TPM_DA_INFO. + Default is FALSE. + */ +#endif + /* NOTE: Cannot add vendor specific flags here, since TPM_GetCapability() returns the serialized + structure */ +} TPM_PERMANENT_FLAGS; + +/* 7.2 TPM_STCLEAR_FLAGS rev 109 + + 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. +*/ + +typedef struct tdTPM_STCLEAR_FLAGS { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_STCLEAR_FLAGS */ +#endif + TPM_BOOL deactivated; /* Prevents the operation of most capabilities. There is no + default state. It is initialized by TPM_Startup to the + same value as TPM_PERMANENT_FLAGS -> + deactivated. TPM_SetTempDeactivated sets it to TRUE. */ + TPM_BOOL disableForceClear; /* Prevents the operation of TPM_ForceClear when TRUE. The + default state is FALSE. TPM_DisableForceClear sets it to + TRUE. */ + TPM_BOOL physicalPresence; /* Command assertion of physical presence. The default state + is FALSE. This flag is affected by the + TSC_PhysicalPresence command but not by the hardware + signal. */ + TPM_BOOL physicalPresenceLock; /* Indicates whether changes to the TPM_STCLEAR_FLAGS -> + physicalPresence flag are permitted. + TPM_Startup(ST_CLEAR) sets PhysicalPresenceLock to its + default state of FALSE (allow changes to the + physicalPresence flag). When TRUE, the physicalPresence + flag is FALSE. TSC_PhysicalPresence can change the state + of physicalPresenceLock. */ + TPM_BOOL bGlobalLock; /* Set to FALSE on each TPM_Startup(ST_CLEAR). Set to TRUE + when a write to NV_Index =0 is successful */ + /* NOTE: Cannot add vendor specific flags here, since TPM_GetCapability() returns the serialized + structure */ +} TPM_STCLEAR_FLAGS; + + +/* 7.3 TPM_STANY_FLAGS rev 87 + + These flags reset on any TPM_Startup command. +*/ + +typedef struct tdTPM_STANY_FLAGS { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_STANY_FLAGS */ +#endif + TPM_BOOL postInitialise; /* Prevents the operation of most capabilities. There is no default + state. It is initialized by TPM_Init to TRUE. TPM_Startup sets it + to FALSE. */ + TPM_MODIFIER_INDICATOR localityModifier; /*This SHALL indicate for each command the presence of + a locality modifier for the command. It MUST be set + to NULL after the TPM executes each command. */ +#if 0 + TPM_BOOL transportExclusive; /* Defaults to FALSE. TRUE when there is an exclusive transport + session active. Execution of ANY command other than + TPM_ExecuteTransport or TPM_ReleaseTransportSigned MUST + invalidate the exclusive transport session. */ +#endif + TPM_TRANSHANDLE transportExclusive; /* Defaults to 0x00000000, Set to the handle when an + exclusive transport session is active */ + TPM_BOOL TOSPresent; /* Defaults to FALSE + Set to TRUE on TPM_HASH_START + set to FALSE using setCapability */ + /* NOTE: Added kgold */ + TPM_BOOL stateSaved; /* Defaults to FALSE + Set to TRUE on TPM_SaveState + Set to FALSE on any other ordinal + + This is an optimization flag, so the file need not be deleted if + it does not exist. + */ +} TPM_STANY_FLAGS; + +/* 7.4 TPM_PERMANENT_DATA rev 105 + + This structure contains the data fields that are permanently held in the TPM and not affected by + TPM_Startup(any). + + Many of these fields contain highly confidential and privacy sensitive material. The TPM must + maintain the protections around these fields. +*/ + +#ifdef TPM_MIN_COUNTERS +#if (TPM_MIN_COUNTERS < 4) +#error "TPM_MIN_COUNTERS minumum is 4" +#endif +#endif + +#ifndef TPM_MIN_COUNTERS +#define TPM_MIN_COUNTERS 4 /* the minimum number of counters is 4 */ +#endif + +#define TPM_DELEGATE_KEY TPM_KEY +#define TPM_MAX_NV_WRITE_NOOWNER 64 + +/* Although the ordinal is 32 bits, only the lower 8 bits seem to be used. So for now, define an + array of 256/8 bytes for ordinalAuditStatus - kgold */ + +#define TPM_ORDINALS_MAX 256 /* assumes a multiple of CHAR_BIT */ +#define TPM_AUTHDIR_SIZE 1 /* Number of DIR registers */ + + + + +typedef struct tdTPM_PERMANENT_DATA { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_PERMANENT_DATA */ +#endif + BYTE revMajor; /* This is the TPM major revision indicator. This SHALL be set by + the TPME, only. The default value is manufacturer-specific. */ + BYTE revMinor; /* This is the TPM minor revision indicator. This SHALL be set by + the TPME, only. The default value is manufacturer-specific. */ + TPM_SECRET tpmProof; /* This is a random number that each TPM maintains to validate blobs + in the SEAL and other processes. The default value is + manufacturer-specific. */ + TPM_NONCE EKReset; /* Nonce held by TPM to validate TPM_RevokeTrust. This value is set + as the next 20 bytes from the TPM RNG when the EK is set + (was fipsReset - kgold) */ + TPM_SECRET ownerAuth; /* This is the TPM-Owner's authorization data. The default value is + manufacturer-specific. */ + TPM_SECRET operatorAuth; /* The value that allows the execution of the SetTempDeactivated + command */ + TPM_DIRVALUE authDIR; /* The array of TPM Owner authorized DIR. Points to the same + location as the NV index value. (kgold - was array of 1) */ +#ifndef TPM_NOMAINTENANCE + TPM_PUBKEY manuMaintPub; /* This is the manufacturer's public key to use in the maintenance + operations. The default value is manufacturer-specific. */ +#endif + TPM_KEY endorsementKey; /* This is the TPM's endorsement key pair. */ + TPM_KEY srk; /* This is the TPM's StorageRootKey. */ + TPM_SYMMETRIC_KEY_TOKEN contextKey; /* This is the key in use to perform context saves. The key + may be symmetric or asymmetric. The key size is + predicated by the algorithm in use. */ + TPM_SYMMETRIC_KEY_TOKEN delegateKey; /* This key encrypts delegate rows that are stored + outside the TPM. */ + TPM_COUNTER_VALUE auditMonotonicCounter; /* This SHALL be the audit monotonic counter for the + TPM. This value starts at 0 and increments + according to the rules of auditing */ + TPM_COUNTER_VALUE monotonicCounter[TPM_MIN_COUNTERS]; /* This SHALL be the monotonic + counters for the TPM. The + individual counters start and + increment according to the rules + of monotonic counters. */ + TPM_PCR_ATTRIBUTES pcrAttrib[TPM_NUM_PCR]; /* The attributes for all of the PCR registers + supported by the TPM. */ + BYTE ordinalAuditStatus[TPM_ORDINALS_MAX/CHAR_BIT]; /* Table indicating which ordinals are being + audited. */ +#if 0 + /* kgold - The xcrypto RNG is good enough that this is not needed */ + BYTE* rngState; /* State information describing the random number + generator. */ +#endif + TPM_FAMILY_TABLE familyTable; /* The family table in use for delegations */ + TPM_DELEGATE_TABLE delegateTable; /* The delegate table */ + uint32_t lastFamilyID; /* A value that sets the high water mark for family ID's. Set to 0 + during TPM manufacturing and never reset. */ + uint32_t noOwnerNVWrite; /* The count of NV writes that have occurred when there is no TPM + Owner. + + This value starts at 0 in manufacturing and after each + TPM_OwnerClear. If the value exceeds 64 the TPM returns + TPM_MAXNVWRITES to any command attempting to manipulate the NV + storage. */ + TPM_CMK_DELEGATE restrictDelegate; /* The settings that allow for the delegation and + use on CMK keys. Default value is false. */ + TPM_DAA_TPM_SEED tpmDAASeed; /* This SHALL be a random value generated after generation + of the EK. + + tpmDAASeed does not change during TPM Owner changes. If + the EK is removed (RevokeTrust) then the TPM MUST + invalidate the tpmDAASeed. The owner can force a change + in the value through TPM_SetCapability. + + (linked to daaProof) */ + TPM_NONCE daaProof; /* This is a random number that each TPM maintains to validate blobs + in the DAA processes. The default value is manufacturer-specific. + + The value is not changed when the owner is changed. It is + changed when the EK changes. The owner can force a change in the + value through TPM_SetCapability. */ + TPM_SYMMETRIC_KEY_TOKEN daaBlobKey; /* This is the key in use to perform DAA encryption and + decryption. The key may be symmetric or asymmetric. The + key size is predicated by the algorithm in use. + + This value MUST be changed when daaProof changes. + + This key MUST NOT be a copy of the EK or SRK. + + (linked to daaProof) */ + /* NOTE: added kgold */ + TPM_BOOL ownerInstalled; /* TRUE: The TPM has an owner installed. + FALSE: The TPM has no owner installed. (default) */ + BYTE tscOrdinalAuditStatus; /* extra byte to track TSC ordinals */ + TPM_BOOL allowLoadMaintPub; /* TRUE allows the TPM_LoadManuMaintPub command */ + +} TPM_PERMANENT_DATA; + +/* 7.6 TPM_STANY_DATA */ + +#ifdef TPM_MIN_AUTH_SESSIONS +#if (TPM_MIN_AUTH_SESSIONS < 3) +#error "TPM_MIN_AUTH_SESSIONS minimum is 3" +#endif +#endif + +#ifndef TPM_MIN_AUTH_SESSIONS +#define TPM_MIN_AUTH_SESSIONS 3 +#endif + +/* NOTE: Vendor specific */ + +typedef struct tdTPM_AUTH_SESSION_DATA { + /* vendor specific */ + TPM_AUTHHANDLE handle; /* Handle for a session */ + TPM_PROTOCOL_ID protocolID; /* TPM_PID_OIAP, TPM_PID_OSAP, TPM_PID_DSAP */ + TPM_ENT_TYPE entityTypeByte; /* The type of entity in use (TPM_ET_SRK, TPM_ET_OWNER, + TPM_ET_KEYHANDLE ... */ + TPM_ADIP_ENC_SCHEME adipEncScheme; /* ADIP encryption scheme */ + TPM_NONCE nonceEven; /* OIAP, OSAP, DSAP */ + TPM_SECRET sharedSecret; /* OSAP */ + TPM_DIGEST entityDigest; /* OSAP tracks which entity established the OSAP session */ + TPM_DELEGATE_PUBLIC pub; /* DSAP */ + TPM_BOOL valid; /* added kgold: array entry is valid */ +} TPM_AUTH_SESSION_DATA; + + +/* 3. contextList MUST support a minimum of 16 entries, it MAY support more. */ + +#ifdef TPM_MIN_SESSION_LIST +#if (TPM_MIN_SESSION_LIST < 16) +#error "TPM_MIN_SESSION_LIST minimum is 16" +#endif +#endif + +#ifndef TPM_MIN_SESSION_LIST +#define TPM_MIN_SESSION_LIST 16 +#endif + +/* 7.5 TPM_STCLEAR_DATA rev 101 + + This is an informative structure and not normative. It is purely for convenience of writing the + spec. + + Most of the data in this structure resets on TPM_Startup(ST_Clear). A TPM may implement rules + that provide longer-term persistence for the data. The TPM reflects how it handles the data in + various TPM_GetCapability fields including startup effects. +*/ + +typedef struct tdTPM_STCLEAR_DATA { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_STCLEAR_DATA */ +#endif + TPM_NONCE contextNonceKey; /* This is the nonce in use to properly identify saved key context + blobs This SHALL be set to all zeros on each TPM_Startup + (ST_Clear). + */ + TPM_COUNT_ID countID; /* This is the handle for the current monotonic counter. This SHALL + be set to zero on each TPM_Startup(ST_Clear). */ + uint32_t ownerReference; /* Points to where to obtain the owner secret in OIAP and OSAP + commands. This allows a TSS to manage 1.1 applications on a 1.2 + TPM where delegation is in operation. */ + TPM_BOOL disableResetLock; /* Disables TPM_ResetLockValue upon authorization failure. + The value remains TRUE for the timeout period. + + Default is FALSE. + + The value is in the STCLEAR_DATA structure as the + implementation of this flag is TPM vendor specific. */ + TPM_PCRVALUE PCRS[TPM_NUM_PCR]; /* Platform configuration registers */ +#if (TPM_REVISION >= 103) /* added for rev 103 */ + uint32_t deferredPhysicalPresence; /* The value can save the assertion of physicalPresence. + Individual bits indicate to its ordinal that + physicalPresence was previously asserted when the + software state is such that it can no longer be asserted. + Set to zero on each TPM_Startup(ST_Clear). */ +#endif + /* NOTE: Added for dictionary attack mitigation */ + uint32_t authFailCount; /* number of authorization failures without a TPM_ResetLockValue */ + uint32_t authFailTime; /* time of threshold failure in seconds */ + /* NOTE: Moved from TPM_STANY_DATA. Saving this state is optional. This implementation + does. */ + TPM_AUTH_SESSION_DATA authSessions[TPM_MIN_AUTH_SESSIONS]; /* List of current + sessions. Sessions can be OSAP, + OIAP, DSAP and Transport */ + /* NOTE: Added for transport */ + TPM_TRANSPORT_INTERNAL transSessions[TPM_MIN_TRANS_SESSIONS]; + /* 22.7 TPM_STANY_DATA Additions (for DAA) - moved to TPM_STCLEAR_DATA for startup state */ + TPM_DAA_SESSION_DATA daaSessions[TPM_MIN_DAA_SESSIONS]; + /* 1. The group of contextNonceSession, contextCount, contextList MUST reset at the same + time. */ + TPM_NONCE contextNonceSession; /* This is the nonce in use to properly identify saved + session context blobs. This MUST be set to all zeros on + each TPM_Startup (ST_Clear). The nonce MAY be set to + null on TPM_Startup( any). */ + uint32_t contextCount; /* This is the counter to avoid session context blob replay + attacks. This MUST be set to 0 on each TPM_Startup + (ST_Clear). The value MAY be set to 0 on TPM_Startup + (any). */ + uint32_t contextList[TPM_MIN_SESSION_LIST]; /* This is the list of outstanding session blobs. + All elements of this array MUST be set to 0 on + each TPM_Startup (ST_Clear). The values MAY be + set to 0 on TPM_Startup (any). */ + /* NOTE Added auditDigest effect, saved with ST_STATE */ + TPM_DIGEST auditDigest; /* This is the extended value that is the audit log. This + SHALL be set to all zeros at the start of each audit + session. */ + /* NOTE Storage for the ordinal response */ + TPM_STORE_BUFFER ordinalResponse; /* outgoing response buffer for this ordinal */ +} TPM_STCLEAR_DATA; + +/* 7.6 TPM_STANY_DATA rev 87 + + This is an informative structure and not normative. It is purely for convenience of writing the + spec. + + Most of the data in this structure resets on TPM_Startup(ST_State). A TPM may implement rules + that provide longer-term persistence for the data. The TPM reflects how it handles the data in + various getcapability fields including startup effects. +*/ + +typedef struct tdTPM_STANY_DATA { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_STANY_DATA */ +#endif + TPM_CURRENT_TICKS currentTicks; /* This is the current tick counter. This is reset to 0 + according to the rules when the TPM can tick. See the + section on the tick counter for details. */ +} TPM_STANY_DATA; + +/* 11. Signed Structures */ + +/* 11.1 TPM_CERTIFY_INFO rev 101 + + When the TPM certifies a key, it must provide a signature with a TPM identity key on information + that describes that key. This structure provides the mechanism to do so. + + Key usage and keyFlags must have their upper byte set to zero to avoid collisions with the other + signature headers. +*/ + +typedef struct tdTPM_CERTIFY_INFO { + TPM_STRUCT_VER version; /* This MUST be 1.1.0.0 */ + TPM_KEY_USAGE keyUsage; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified. The + upper byte MUST be zero */ + TPM_KEY_FLAGS keyFlags; /* This SHALL be set to the same value as the corresponding + parameter in the TPM_KEY structure that describes the + public key that is being certified. The upper byte MUST + be zero */ + TPM_AUTH_DATA_USAGE authDataUsage; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified */ + TPM_KEY_PARMS algorithmParms; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified */ + TPM_DIGEST pubkeyDigest; /* This SHALL be a digest of the value TPM_KEY -> pubKey -> + key in a TPM_KEY representation of the key to be + certified */ + TPM_NONCE data; /* This SHALL be externally provided data. */ + TPM_BOOL parentPCRStatus; /* This SHALL indicate if any parent key was wrapped to a + PCR */ + TPM_SIZED_BUFFER pcrInfo; /* */ +#if 0 + uint32_t PCRInfoSize; /* This SHALL be the size of the pcrInfo parameter. A value + of zero indicates that the key is not wrapped to a PCR */ + BYTE* PCRInfo; /* This SHALL be the TPM_PCR_INFO structure. */ +#endif + /* NOTE: kgold - Added this structure, a cache of PCRInfo when not NULL */ + TPM_PCR_INFO *tpm_pcr_info; +} TPM_CERTIFY_INFO; + +/* 11.2 TPM_CERTIFY_INFO2 rev 101 + + When the TPM certifies a key, it must provide a signature with a TPM identity key on information + that describes that key. This structure provides the mechanism to do so. + + Key usage and keyFlags must have their upper byte set to zero to avoid collisions with the other + signature headers. +*/ + +typedef struct tdTPM_CERTIFY_INFO2 { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_CERTIFY_INFO2 */ +#endif + BYTE fill; /* MUST be 0x00 */ + TPM_PAYLOAD_TYPE payloadType; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified */ + TPM_KEY_USAGE keyUsage; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified. The + upper byte MUST be zero */ + TPM_KEY_FLAGS keyFlags; /* This SHALL be set to the same value as the corresponding + parameter in the TPM_KEY structure that describes the + public key that is being certified. The upper byte MUST + be zero. */ + TPM_AUTH_DATA_USAGE authDataUsage; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified */ + TPM_KEY_PARMS algorithmParms; /* This SHALL be the same value that would be set in a + TPM_KEY representation of the key to be certified */ + TPM_DIGEST pubkeyDigest; /* This SHALL be a digest of the value TPM_KEY -> pubKey -> + key in a TPM_KEY representation of the key to be + certified */ + TPM_NONCE data; /* This SHALL be externally provided data. */ + TPM_BOOL parentPCRStatus; /* This SHALL indicate if any parent key was wrapped to a + PCR */ +#if 0 + uint32_t PCRInfoSize; /* This SHALL be the size of the pcrInfo parameter. A value + of zero indicates that the key is not wrapped to a PCR */ + BYTE* PCRInfo; /* This SHALL be the TPM_PCR_INFO_SHORT structure. */ +#endif + TPM_SIZED_BUFFER pcrInfo; +#if 0 + uint32_t migrationAuthoritySize; /* This SHALL be the size of migrationAuthority */ + BYTE *migrationAuthority; /* If the key to be certified has [payload == + TPM_PT_MIGRATE_RESTRICTED or payload + ==TPM_PT_MIGRATE_EXTERNAL], migrationAuthority is the + digest of the TPM_MSA_COMPOSITE and has TYPE == + TPM_DIGEST. Otherwise it is NULL. */ +#endif + TPM_SIZED_BUFFER migrationAuthority; + /* NOTE: kgold - Added this structure, a cache of PCRInfo when not NULL */ + TPM_PCR_INFO_SHORT *tpm_pcr_info_short; +} TPM_CERTIFY_INFO2; + +/* 11.3 TPM_QUOTE_INFO rev 87 + + 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; /* This MUST be 1.1.0.0 */ + BYTE fixed[4]; /* This SHALL always be the string 'QUOT' */ + TPM_COMPOSITE_HASH digestValue; /* This SHALL be the result of the composite hash algorithm + using the current values of the requested PCR indices. */ + TPM_NONCE externalData; /* 160 bits of externally supplied data */ +} TPM_QUOTE_INFO; + +/* 11.4 TPM_QUOTE_INFO2 rev 87 + + This structure provides the mechanism for the TPM to quote the current values of a list of PCRs. +*/ + +typedef struct tdTPM_QUOTE_INFO2 { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_QUOTE_INFO2 */ +#endif + BYTE fixed[4]; /* This SHALL always be the string 'QUT2' */ + TPM_NONCE externalData; /* 160 bits of externally supplied data */ + TPM_PCR_INFO_SHORT infoShort; /* */ +} TPM_QUOTE_INFO2; + +/* 12.1 TPM_EK_BLOB rev 87 + + This structure provides a wrapper to each type of structure that will be in use when the + endorsement key is in use. +*/ + +typedef struct tdTPM_EK_BLOB { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_EK_BLOB */ +#endif + TPM_EK_TYPE ekType; /* This SHALL be set to reflect the type of blob in use */ + TPM_SIZED_BUFFER blob; /* The blob of information depending on the type */ +#if 0 + uint32_t blobSize; /* */ + [size_is(blobSize)] byte* blob; /* */ +#endif +} TPM_EK_BLOB; + +/* 12.2 TPM_EK_BLOB_ACTIVATE rev 87 + + This structure contains the symmetric key to encrypt the identity credential. This structure + always is contained in a TPM_EK_BLOB. +*/ + +typedef struct tdTPM_EK_BLOB_ACTIVATE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_EK_BLOB_ACTIVATE */ +#endif + TPM_SYMMETRIC_KEY sessionKey; /* This SHALL be the session key used by the CA to encrypt + the TPM_IDENTITY_CREDENTIAL */ + TPM_DIGEST idDigest; /* This SHALL be the digest of the TPM identity public key + that is being certified by the CA */ + TPM_PCR_INFO_SHORT pcrInfo; /* This SHALL indicate the PCR's and localities */ +} TPM_EK_BLOB_ACTIVATE; + +/* 12.3 TPM_EK_BLOB_AUTH rev 87 + + This structure contains the symmetric key to encrypt the identity credential. This structure + always is contained in a TPM_EK_BLOB. +*/ + +typedef struct tdTPM_EK_BLOB_AUTH { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_EK_BLOB_AUTH */ +#endif + TPM_SECRET authValue; /* This SHALL be the authorization value */ +} TPM_EK_BLOB_AUTH; + +/* 12.5 TPM_IDENTITY_CONTENTS rev 87 + + 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; /* This MUST be 1.1.0.0 */ + uint32_t ordinal; /* This SHALL be the ordinal of the TPM_MakeIdentity + command. */ + TPM_CHOSENID_HASH labelPrivCADigest; /* This SHALL be the result of hashing the chosen + identityLabel and privacyCA for the new TPM + identity */ + TPM_PUBKEY identityPubKey; /* This SHALL be the public key structure of the identity + key */ +} TPM_IDENTITY_CONTENTS; + +/* 12.8 TPM_ASYM_CA_CONTENTS rev 87 + + This structure contains the symmetric key to encrypt the identity credential. +*/ + +typedef struct tdTPM_ASYM_CA_CONTENTS { + TPM_SYMMETRIC_KEY sessionKey; /* This SHALL be the session key used by the CA to encrypt + the TPM_IDENTITY_CREDENTIAL */ + TPM_DIGEST idDigest; /* This SHALL be the digest of the TPM_PUBKEY of the key + that is being certified by the CA */ +} TPM_ASYM_CA_CONTENTS; + +/* + 14. Audit Structures +*/ + +/* 14.1 TPM_AUDIT_EVENT_IN rev 87 + + This structure provides the auditing of the command upon receipt of the command. It provides the + information regarding the input parameters. +*/ + +typedef struct tdTPM_AUDIT_EVENT_IN { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_AUDIT_EVENT_IN */ +#endif + TPM_DIGEST inputParms; /* Digest value according to the HMAC digest rules of the + "above the line" parameters (i.e. the first HMAC digest + calculation). When there are no HMAC rules, the input + digest includes all parameters including and after the + ordinal. */ + TPM_COUNTER_VALUE auditCount; /* The current value of the audit monotonic counter */ +} TPM_AUDIT_EVENT_IN; + +/* 14.2 TPM_AUDIT_EVENT_OUT rev 87 + + This structure reports the results of the command execution. It includes the return code and the + output parameters. +*/ + +typedef struct tdTPM_AUDIT_EVENT_OUT { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_AUDIT_EVENT_OUT */ +#endif + TPM_DIGEST outputParms; /* Digest value according to the HMAC digest rules of the + "above the line" parameters (i.e. the first HMAC digest + calculation). When there are no HMAC rules, the output + digest includes the return code, the ordinal, and all + parameters after the return code. */ + TPM_COUNTER_VALUE auditCount; /* The current value of the audit monotonic counter */ +} TPM_AUDIT_EVENT_OUT; + +/* + 18. Context structures +*/ + +/* 18.1 TPM_CONTEXT_BLOB rev 102 + + This is the header for the wrapped context. The blob contains all information necessary to reload + the context back into the TPM. + + The additional data is used by the TPM manufacturer to save information that will assist in the + reloading of the context. This area must not contain any shielded data. For instance, the field + could contain some size information that allows the TPM more efficient loads of the context. The + additional area could not contain one of the primes for a RSA key. + + To ensure integrity of the blob when using symmetric encryption the TPM vendor could use some + valid cipher chaining mechanism. To ensure the integrity without depending on correct + implementation, the TPM_CONTEXT_BLOB structure uses a HMAC of the entire structure using tpmProof + as the secret value. + + Since both additionalData and sensitiveData are informative, any or all of additionalData + could be moved to sensitiveData. +*/ + +#define TPM_CONTEXT_LABEL_SIZE 16 + +typedef struct tdTPM_CONTEXT_BLOB { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_CONTEXTBLOB */ +#endif + TPM_RESOURCE_TYPE resourceType; /* The resource type */ + TPM_HANDLE handle; /* Previous handle of the resource */ + BYTE label[TPM_CONTEXT_LABEL_SIZE]; /* Label for identification of the blob. Free format + area. */ + uint32_t contextCount; /* MUST be TPM_STANY_DATA -> contextCount when creating the + structure. This value is ignored for context blobs that + reference a key. */ + TPM_DIGEST integrityDigest; /* The integrity of the entire blob including the sensitive + area. This is a HMAC calculation with the entire + structure (including sensitiveData) being the hash and + tpmProof is the secret */ +#if 0 + uint32_t additionalSize; + [size_is(additionalSize)] BYTE* additionalData; + uint32_t sensitiveSize; + [size_is(sensitiveSize)] BYTE* sensitiveData; +#endif + TPM_SIZED_BUFFER additionalData; /* Additional information set by the TPM that helps define + and reload the context. The information held in this area + MUST NOT expose any information held in shielded + locations. This should include any IV for symmetric + encryption */ + TPM_SIZED_BUFFER sensitiveData; /* The normal information for the resource that can be + exported */ +} TPM_CONTEXT_BLOB; + +/* 18.2 TPM_CONTEXT_SENSITIVE rev 87 + + 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. +*/ + +typedef struct tdTPM_CONTEXT_SENSITIVE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_CONTEXT_SENSITIVE */ +#endif + TPM_NONCE contextNonce; /* On context blobs other than keys this MUST be + TPM_STANY_DATA - > contextNonceSession For keys the value + is TPM_STCLEAR_DATA -> contextNonceKey */ +#if 0 + uint32_t internalSize; + [size_is(internalSize)] BYTE* internalData; +#endif + TPM_SIZED_BUFFER internalData; /* The internal data area */ +} TPM_CONTEXT_SENSITIVE; + +/* 19.2 TPM_NV_ATTRIBUTES rev 99 + + This structure allows the TPM to keep track of the data and permissions to manipulate the area. +*/ + +typedef struct tdTPM_NV_ATTRIBUTES { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* TPM_TAG_NV_ATTRIBUTES */ +#endif + uint32_t attributes; /* The attribute area */ +} TPM_NV_ATTRIBUTES; + +/* 19.3 TPM_NV_DATA_PUBLIC rev 110 + + This structure represents the public description and controls on the NV area. + + bReadSTClear and bWriteSTClear are volatile, in that they are set FALSE at TPM_Startup(ST_Clear). + bWriteDefine is persistent, in that it remains TRUE through startup. + + A pcrSelect of 0 indicates that the digestAsRelease is not checked. In this case, the TPM is not + required to consume NVRAM space to store the digest, although it may do so. When + TPM_GetCapability (TPM_CAP_NV_INDEX) returns the structure, a TPM that does not store the digest + can return zero. A TPM that does store the digest may return either the digest or zero. +*/ + +typedef struct tdTPM_NV_DATA_PUBLIC { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_NV_DATA_PUBLIC */ +#endif + TPM_NV_INDEX nvIndex; /* The index of the data area */ + TPM_PCR_INFO_SHORT pcrInfoRead; /* The PCR selection that allows reading of the area */ + TPM_PCR_INFO_SHORT pcrInfoWrite; /* The PCR selection that allows writing of the area */ + TPM_NV_ATTRIBUTES permission; /* The permissions for manipulating the area */ + TPM_BOOL bReadSTClear; /* Set to FALSE on each TPM_Startup(ST_Clear) and set to + TRUE after a ReadValuexxx with datasize of 0 */ + TPM_BOOL bWriteSTClear; /* Set to FALSE on each TPM_Startup(ST_CLEAR) and set to + TRUE after a WriteValuexxx with a datasize of 0. */ + TPM_BOOL bWriteDefine; /* Set to FALSE after TPM_NV_DefineSpace and set to TRUE + after a successful WriteValuexxx with a datasize of 0 */ + uint32_t dataSize; /* The size of the data area in bytes */ +} TPM_NV_DATA_PUBLIC; + +/* 19.4 TPM_NV_DATA_SENSITIVE rev 101 + + This is an internal structure that the TPM uses to keep the actual NV data and the controls + regarding the area. +*/ + +typedef struct tdTPM_NV_DATA_SENSITIVE { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* This SHALL be TPM_TAG_NV_DATA_SENSITIVE */ +#endif + TPM_NV_DATA_PUBLIC pubInfo; /* The public information regarding this area */ + TPM_AUTHDATA authValue; /* The authorization value to manipulate the value */ + BYTE *data; /* The data area. This MUST not contain any sensitive information as + the TPM does not provide any confidentiality on the data. */ + /* NOTE Added kg */ + TPM_DIGEST digest; /* for OSAP comparison */ +} TPM_NV_DATA_SENSITIVE; + +typedef struct tdTPM_NV_INDEX_ENTRIES { + uint32_t nvIndexCount; /* number of entries */ + TPM_NV_DATA_SENSITIVE *tpm_nvindex_entry; /* array of TPM_NV_DATA_SENSITIVE */ +} TPM_NV_INDEX_ENTRIES; + +/* TPM_NV_DATA_ST + + This is a cache of the the NV defined space volatile flags, used during error rollback +*/ + +typedef struct tdTPM_NV_DATA_ST { + TPM_NV_INDEX nvIndex; /* The index of the data area */ + TPM_BOOL bReadSTClear; + TPM_BOOL bWriteSTClear; +} TPM_NV_DATA_ST; + +/* + 21. Capability areas +*/ + +/* 21.6 TPM_CAP_VERSION_INFO rev 99 + + This structure is an output from a TPM_GetCapability -> TPM_CAP_VERSION_VAL request. TPM returns + the current version and revision of the TPM. + + The specLevel and errataRev are defined in the document "Specification and File Naming + Conventions" + + The tpmVendorID is a value unique to each vendor. It is defined in the document "TCG Vendor + Naming". + + The vendor specific area allows the TPM vendor to provide support for vendor options. The TPM + vendor may define the area to the TPM vendor's needs. +*/ + +typedef struct tdTPM_CAP_VERSION_INFO { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_CAP_VERSION_INFO */ +#endif + TPM_VERSION version; /* The version and revision */ + uint16_t specLevel; /* A number indicating the level of ordinals supported */ + BYTE errataRev; /* A number indicating the errata version of the specification */ + BYTE tpmVendorID[4]; /* The vendor ID unique to each TPM manufacturer. */ + uint16_t vendorSpecificSize; /* The size of the vendor specific area */ + BYTE* vendorSpecific; /* Vendor specific information */ + /* NOTE Cannot be TPM_SIZED_BUFFER, because of uint16_t */ +} TPM_CAP_VERSION_INFO; + +/* 21.10 TPM_DA_ACTION_TYPE rev 100 + + This structure indicates the action taken when the dictionary attack mitigation logic is active, + when TPM_DA_STATE is TPM_DA_STATE_ACTIVE. +*/ + +typedef struct tdTPM_DA_ACTION_TYPE { + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DA_ACTION_TYPE */ + uint32_t actions; /* The action taken when TPM_DA_STATE is TPM_DA_STATE_ACTIVE. */ +} TPM_DA_ACTION_TYPE; + +/* 21.7 TPM_DA_INFO rev 100 + + This structure is an output from a TPM_GetCapability -> TPM_CAP_DA_LOGIC request if + TPM_PERMANENT_FLAGS -> disableFullDALogicInfo is FALSE. + + It returns static information describing the TPM response to authorization failures that might + indicate a dictionary attack and dynamic information regarding the current state of the + dictionary attack mitigation logic. +*/ + +typedef struct tdTPM_DA_INFO { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DA_INFO */ +#endif + TPM_DA_STATE state; /* Dynamic. The actual state of the dictionary attack mitigation + logic. See 21.9. */ + uint16_t currentCount; /* Dynamic. The actual count of the authorization failure counter + for the selected entity type */ + uint16_t thresholdCount; /* Static. Dictionary attack mitigation threshold count for the + selected entity type */ + TPM_DA_ACTION_TYPE actionAtThreshold; /* Static Action of the TPM when currentCount passes + thresholdCount. See 21.10. */ + uint32_t actionDependValue; /* Dynamic. Action being taken when the dictionary attack + mitigation logic is active. E.g., when actionAtThreshold is + TPM_DA_ACTION_TIMEOUT, this is the lockout time remaining in + seconds. */ + TPM_SIZED_BUFFER vendorData; /* Vendor specific data field */ +} TPM_DA_INFO; + +/* 21.8 TPM_DA_INFO_LIMITED rev 100 + + This structure is an output from a TPM_GetCapability -> TPM_CAP_DA_LOGIC request if + TPM_PERMANENT_FLAGS -> disableFullDALogicInfo is TRUE. + + It returns static information describing the TPM response to authorization failures that might + indicate a dictionary attack and dynamic information regarding the current state of the + dictionary attack mitigation logic. This structure omits information that might aid an attacker. +*/ + +typedef struct tdTPM_DA_INFO_LIMITED { +#ifdef TPM_USE_TAG_IN_STRUCTURE + TPM_STRUCTURE_TAG tag; /* MUST be TPM_TAG_DA_INFO_LIMITED */ +#endif + TPM_DA_STATE state; /* Dynamic. The actual state of the dictionary attack mitigation + logic. See 21.9. */ + TPM_DA_ACTION_TYPE actionAtThreshold; /* Static Action of the TPM when currentCount passes + thresholdCount. See 21.10. */ + TPM_SIZED_BUFFER vendorData; /* Vendor specific data field */ +} TPM_DA_INFO_LIMITED; + +#endif + +/* Sanity check the size of the NV file vs. the maximum allocation size + + The multipliers are very conservative +*/ + +#if (TPM_ALLOC_MAX < \ + (4000 + \ + (TPM_OWNER_EVICT_KEY_HANDLES * 2000) + \ + TPM_MAX_NV_DEFINED_SPACE)) +#error "TPM_ALLOC_MAX too small for NV file size" +#endif + +/* Sanity check the size of the volatile file vs. the maximum allocation size + + The multipliers are very conservative +*/ + +#if (TPM_ALLOC_MAX < \ + (4000 + \ + TPM_KEY_HANDLES * 2000 + \ + TPM_MIN_TRANS_SESSIONS * 500 + \ + TPM_MIN_DAA_SESSIONS * 2000 + \ + TPM_MIN_AUTH_SESSIONS * 500)) +#error "TPM_ALLOC_MAX too small for volatile file size" +#endif diff --git a/src/tpm_svnrevision.c b/src/tpm_svnrevision.c new file mode 100644 index 00000000..16ee5626 --- /dev/null +++ b/src/tpm_svnrevision.c @@ -0,0 +1 @@ +const unsigned short tpm_svn_revision = 4668; diff --git a/src/tpm_svnrevision.h b/src/tpm_svnrevision.h new file mode 100644 index 00000000..0ed4c4b1 --- /dev/null +++ b/src/tpm_svnrevision.h @@ -0,0 +1,46 @@ +/********************************************************************************/ +/* */ +/* TPM svn revision */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_svnrevision.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_REVISION_H +#define TPM_REVISION_H + +extern const unsigned short tpm_svn_revision; + +#endif + diff --git a/src/tpm_ticks.c b/src/tpm_ticks.c new file mode 100644 index 00000000..c8dc58b1 --- /dev/null +++ b/src/tpm_ticks.c @@ -0,0 +1,913 @@ +/********************************************************************************/ +/* */ +/* Tick Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_ticks.c 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_auth.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_key.h" +#include "tpm_structures.h" +#include "tpm_nonce.h" +#include "tpm_process.h" +#include "tpm_time.h" + +#include "tpm_ticks.h" + +static void TPM_Uint64_ConvertFrom(uint32_t *upper, + uint32_t *lower, + uint32_t sec, + uint32_t usec); +static void TPM_Uint64_ConvertTo(uint32_t *sec, + uint32_t *usec, + uint32_t upper, + uint32_t lower); + +/* + UINT64 for currentTicks + + Internally, the UINT64 is stored as sec || usec. This makes calculations easy since TPM_GetTimeOfDay + returns those structure elements. + + The TPM_Uint64_Store() function, the public interface, converts this to a true 64 bit integer. +*/ + +/* TPM_Uint64_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_Uint64_Init(TPM_UINT64 *tpm_uint64) +{ + printf(" TPM_Uint64_Init:\n"); + tpm_uint64->sec = 0; + tpm_uint64->usec = 0; + return; +} + +/* TPM_Uint64_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + This function does the conversion from a 64 bit usec to sec / usec. +*/ + +TPM_RESULT TPM_Uint64_Load(TPM_UINT64 *tpm_uint64, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + uint32_t upper; + uint32_t lower; + + printf(" TPM_Uint64_Load:\n"); + /* load upper */ + if (rc == 0) { + rc = TPM_Load32(&upper, stream, stream_size); + } + /* load lower */ + if (rc == 0) { + rc = TPM_Load32(&lower, stream, stream_size); + } + /* convert from 64 bit usec to sec, usec */ + if (rc == 0) { + TPM_Uint64_ConvertTo(&(tpm_uint64->sec), + &(tpm_uint64->usec), + upper, + lower); + } + return rc; +} + +/* TPM_Uint64_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes + + This function does the conversion from sec / usec to a 64 bit usec. +*/ + +TPM_RESULT TPM_Uint64_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_UINT64 *tpm_uint64) +{ + TPM_RESULT rc = 0; + uint32_t upper; + uint32_t lower; + + printf(" TPM_Uint64_Store:\n"); + /* store upper */ + if (rc == 0) { + /* convert to 64 bit number */ + TPM_Uint64_ConvertFrom(&upper, &lower, tpm_uint64->sec, tpm_uint64->usec); + rc = TPM_Sbuffer_Append32(sbuffer, upper); + } + /* store lower */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, lower); + } + return rc; +} + +void TPM_Uint64_Copy(TPM_UINT64 *dest, + const TPM_UINT64 *src) +{ + printf(" TPM_Uint64_Copy:\n"); + dest->sec = src->sec; + dest->usec = src->usec; + return; +} + +/* TPM_Uint64_ConvertFrom() does the calculation result = sec * 1000000 + usec and splits the result + into two uint32_t's. + + This may not be portable if the compiler does not support long long. +*/ + +/* TPM_Uint64_ConvertTo() does the calculation uint32_t || uint32_t to sec and usec. + + This may not be portable if the compiler does not support long long. +*/ + +#if defined(TPM_POSIX) || defined(TPM_SYSTEM_P) + +static void TPM_Uint64_ConvertFrom(uint32_t *upper, + uint32_t *lower, + uint32_t sec, + uint32_t usec) +{ + long long result; + + printf(" TPM_Uint64_ConvertFrom: sec %u, usec %u\n", sec, usec); + result = (sec * 1000000LL) + (long long)usec; + printf(" TPM_Uint64_ConvertFrom: Result usec %llu, %llx\n", result, result); + *upper = (result >> 32) & 0xffffffff; + *lower = result & 0xffffffff; + printf(" TPM_Uint64_ConvertFrom: Upper %u, %x\n", *upper, *upper); + printf(" TPM_Uint64_ConvertFrom: Lower %u, %x\n", *lower, *lower); + return; +} + +static void TPM_Uint64_ConvertTo(uint32_t *sec, + uint32_t *usec, + uint32_t upper, + uint32_t lower) +{ + long long result; + + printf(" TPM_Uint64_ConvertTo: Upper %u, %x\n", upper, upper); + printf(" TPM_Uint64_ConvertTo: Lower %u, %x\n", lower, lower); + result = ((long long)upper << 32) | (long long)lower; + printf(" TPM_Uint64_ConvertTo: Result usec %llu, %llx\n", result, result); + *sec = result / 1000000LL; + *usec = result % 1000000LL; + printf(" TPM_Uint64_ConvertTo: sec %u, usec %u\n", *sec, *usec); + return; +} + +#endif + + +TPM_RESULT TPM_Uint64_Test() +{ + TPM_RESULT rc = 0; + TPM_UINT64 uint64In; + TPM_UINT64 uint64Out; + TPM_STORE_BUFFER sbuffer; + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_Uint64_Test\n"); + TPM_Sbuffer_Init(&sbuffer); + uint64In.sec = 12345678; + uint64In.usec = 781234; + + if (rc == 0) { + rc = TPM_Uint64_Store(&sbuffer, &uint64In); + } + if (rc == 0) { + TPM_Sbuffer_Get(&sbuffer, (const unsigned char **)&stream, &stream_size); + rc = TPM_Uint64_Load(&uint64Out, &stream, &stream_size); + } + if (rc == 0) { + if ((uint64In.sec != uint64Out.sec) || + (uint64In.usec != uint64Out.usec)) { + printf("TPM_Uint64_Test: Error (fatal)\n"); + rc = TPM_FAILEDSELFTEST; + } + } + TPM_Sbuffer_Delete(&sbuffer); + return rc; +} + +/* + TPM_CURRENT_TICKS +*/ + +/* TPM_CurrentTicks_Init() initializes the tick structure + +*/ + +void TPM_CurrentTicks_Init(TPM_CURRENT_TICKS *tpm_current_ticks) +{ + printf(" TPM_CurrentTicks_Init:\n"); + TPM_Uint64_Init(&(tpm_current_ticks->currentTicks)); + tpm_current_ticks->tickRate = TPM_TICK_RATE; + TPM_Nonce_Init(tpm_current_ticks->tickNonce); + TPM_Uint64_Init(&(tpm_current_ticks->initialTime)); + return; +} + +/* TPM_CurrentTicks_Start() sets the initialTime member to the + current time of day. + + It assumes TPM_CurrentTicks_Init() has been called +*/ + +TPM_RESULT TPM_CurrentTicks_Start(TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_Start:\n"); + if (rc == 0) { + /* current is relative to the initial value, and is always 0 */ + TPM_Uint64_Init(&(tpm_current_ticks->currentTicks)); + /* save the current time */ + rc = TPM_GetTimeOfDay(&(tpm_current_ticks->initialTime.sec), + &(tpm_current_ticks->initialTime.usec)); + } + if (rc == 0) { + tpm_current_ticks->tickRate = TPM_TICK_RATE; + rc = TPM_Nonce_Generate(tpm_current_ticks->tickNonce); + } + return rc; +} + +/* TPM_CurrentTicks_LoadAll() loads the standard TCG structure plus the SW TPM members + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_CurrentTicks_Init() +*/ + +TPM_RESULT TPM_CurrentTicks_LoadAll(TPM_CURRENT_TICKS *tpm_current_ticks, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_LoadAll:\n"); + /* load tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_CURRENT_TICKS, stream, stream_size); + } + /* load currentTicks */ + if (rc == 0) { + rc = TPM_Uint64_Load(&(tpm_current_ticks->currentTicks), stream, stream_size); + } + /* load tickRate */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_current_ticks->tickRate), stream, stream_size); + } + /* load tickNonce */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_current_ticks->tickNonce, stream, stream_size); + } + /* load initialTime */ + if (rc == 0) { + rc = TPM_Uint64_Load(&(tpm_current_ticks->initialTime), stream, stream_size); + } + return rc; +} + +/* TPM_CurrentTicks_Store() stores the standard TCG structure + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CurrentTicks_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_CURRENT_TICKS); + } + /* store currentTicks */ + if (rc == 0) { + rc = TPM_Uint64_Store(sbuffer, &(tpm_current_ticks->currentTicks)); + } + /* store tickRate */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_current_ticks->tickRate); + } + /* store tickNonce */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_current_ticks->tickNonce); + } + return rc; +} + +/* TPM_CurrentTicks_Store() stores the standard TCG structure plus the SW TPM members + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_CurrentTicks_StoreAll(TPM_STORE_BUFFER *sbuffer, + const TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + + printf(" TPM_CurrentTicks_StoreAll:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_CurrentTicks_Store(sbuffer, tpm_current_ticks); + } + /* store initialTime */ + if (rc == 0) { + rc = TPM_Uint64_Store(sbuffer, &(tpm_current_ticks->initialTime)); + } + return rc; +} + +/* TPM_CurrentTicks_Update() updates the currentTicks member of TPM_CURRENT_TICKS + relative to the initial time + +*/ + +TPM_RESULT TPM_CurrentTicks_Update(TPM_CURRENT_TICKS *tpm_current_ticks) +{ + TPM_RESULT rc = 0; + uint32_t currentTimeSec; + uint32_t currentTimeUsec; + + printf(" TPM_CurrentTicks_Update: Initial %u sec %u usec\n", + tpm_current_ticks->initialTime.sec, tpm_current_ticks->initialTime.usec); + /* get the current time of day */ + if (rc == 0) { + rc = TPM_GetTimeOfDay(¤tTimeSec, ¤tTimeUsec); + } + /* Calculate: + currentTimeSec currentTimeUsec + - initialTimeSec initialTimeUsec + */ + if (rc == 0) { + /* case 1: no borrow */ + if (currentTimeUsec >= tpm_current_ticks->initialTime.usec) { + /* subtract usec */ + tpm_current_ticks->currentTicks.usec = currentTimeUsec - + tpm_current_ticks->initialTime.usec; + + /* check that time went forward */ + if (currentTimeSec >= tpm_current_ticks->initialTime.sec) { + /* subtract sec */ + tpm_current_ticks->currentTicks.sec = currentTimeSec - + tpm_current_ticks->initialTime.sec; + } + else { + printf(" TPM_CurrentTicks_Update: Error (fatal), illegal current time\n"); + rc = TPM_FAIL; + } + } + /* case 2: borrow */ + else { + /* subtract usec with borrow */ + tpm_current_ticks->currentTicks.usec = 1000000 + currentTimeUsec - + tpm_current_ticks->initialTime.usec; + /* check that time went forward, with borrow */ + if ((currentTimeSec - 1) >= tpm_current_ticks->initialTime.sec) { + /* subtract sec */ + tpm_current_ticks->currentTicks.sec = currentTimeSec - 1 - + tpm_current_ticks->initialTime.sec; + } + else { + printf(" TPM_CurrentTicks_Update: Error (fatal), illegal current time\n"); + rc = TPM_FAIL; + } + } + } + if (rc == 0) { + printf(" TPM_CurrentTicks_Update: Ticks %u sec %u usec\n", + tpm_current_ticks->currentTicks.sec, + tpm_current_ticks->currentTicks.usec); + } + return rc; +} + +/* TPM_CurrentTicks_Copy() copies the 'src' to 'dest' + +*/ + +void TPM_CurrentTicks_Copy(TPM_CURRENT_TICKS *dest, + TPM_CURRENT_TICKS *src) +{ + printf(" TPM_CurrentTicks_Copy:\n"); + TPM_Uint64_Copy(&(dest->currentTicks), &(src->currentTicks)); + dest->tickRate = src->tickRate; + TPM_Nonce_Copy(dest->tickNonce, src->tickNonce); + TPM_Uint64_Copy(&(dest->initialTime), &(src->initialTime)); + return; +} + +/* + Processing Functions +*/ + +/* 23. Timing Ticks rev 87 + + 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. + + The setting of the clock type variable is a one time operation that allows the TPM to be + configured to the type of platform that is installed on. + + The ability for the TPM to continue to increment the timer ticks across power cycles of the + platform is a TPM and platform manufacturer decision. +*/ + +/* 23.1 TPM_GetTicks rev 87 + + This command returns the current tick count of the TPM. + + This command returns the current time held in the TPM. It is the responsibility of the external + system to maintain any relation between this time and a UTC value or local real time value. +*/ + +TPM_RESULT TPM_Process_GetTicks(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CURRENT_TICKS *t1CurrentTicks = NULL; /* The current time held in the TPM */ + + printf("TPM_Process_GetTicks: Ordinal Entry\n"); + /* + get inputs + */ + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALLOW_NO_OWNER); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag0(tag); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_GetTicks: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* 1. Set T1 to the internal TPM_CURRENT_TICKS structure */ + t1CurrentTicks = &(tpm_state->tpm_stany_data.currentTicks); + /* update the ticks based on the current time */ + returnCode = TPM_CurrentTicks_Update(t1CurrentTicks); + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_GetTicks: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 2. Return T1 as currentTime. */ + returnCode = TPM_CurrentTicks_Store(response, t1CurrentTicks); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* + cleanup + */ + return rcf; +} + +/* 23.2 TPM_TickStampBlob rev 101 + + 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. + + The function performs a digital signature on the hash of digestToStamp and the current tick + count. + + It is the responsibility of the external system to maintain any relation between tick count and a + UTC value or local real time value. + +*/ + +TPM_RESULT TPM_Process_TickStampBlob(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* The keyHandle identifier of a loaded key that can perform digital + signatures. */ + TPM_NONCE antiReplay; /* Anti replay value added to signature */ + TPM_DIGEST digestToStamp; /* The digest to perform the tick stamp on */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for keyHandle authorization + */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA privAuth; /* The authorization session digest that authorizes the use of + keyHandle. HMAC key: key.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_BOOL authHandleValid = FALSE; + TPM_KEY *sigKey; /* signing key */ + TPM_SECRET *keyUsageAuth; + TPM_SECRET *hmacKey; + TPM_BOOL parentPCRStatus; + TPM_SIGN_INFO h1SignInfo; + TPM_STORE_BUFFER h2Data; + TPM_STORE_BUFFER h1sbuffer; /* serialization of h1SignInfo */ + TPM_DIGEST h3Digest; /* digest to be signed */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CURRENT_TICKS *currentTicks = NULL; /* The current time according to the TPM */ + TPM_SIZED_BUFFER sig; /* The resulting digital signature. */ + + printf("TPM_Process_TickStampBlob: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&sig); /* freed @1 */ + TPM_SignInfo_Init(&h1SignInfo); /* freed @2 */ + TPM_Sbuffer_Init(&h2Data); /* freed @3 */ + TPM_Sbuffer_Init(&h1sbuffer); /* freed @4 */ + /* + get inputs + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay parameter */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: keyHandle %08x\n", keyHandle); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* get digestToStamp parameter */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_TickStampBlob: antiReplay", antiReplay); + returnCode = TPM_Digest_Load(digestToStamp, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_TickStampBlob: digestToStamp", digestToStamp); + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + privAuth, + &command, ¶mSize); + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + printf("TPM_Process_TickStampBlob: authHandle %08x\n", authHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_TickStampBlob: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not read-only */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_TickStampBlob: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 1. The TPM validates the AuthData to use the key pointed to by keyHandle. */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + privAuth); /* Authorization digest for input */ + } + /* 2. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, TPM_KEY_IDENTITY or + TPM_KEY_LEGACY, if not return the error code TPM_INVALID_KEYUSAGE. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Checking key properties\n"); + if ((sigKey->keyUsage != TPM_KEY_SIGNING) && + (sigKey->keyUsage != TPM_KEY_IDENTITY) && + (sigKey->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_TickStampBlob: Error, keyUsage %04hx is invalid\n", + sigKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 3. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or + TPM_SS_RSASSAPKCS1v15_INFO, if not return TPM_INAPPROPRIATE_SIG. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_TickStampBlob: Error, invalid sigKey sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INAPPROPRIATE_SIG; + } + } + /* 4. If TPM_STCLEAR_DATA -> currentTicks is not properly initialized */ + /* a. Initialize the TPM_STCLEAR_DATA -> currentTicks */ + /* NOTE: Always initialized */ + /* 5. Create T1, a TPM_CURRENT_TICKS structure. */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Creating TPM_CURRENT_TICKS structure\n"); + currentTicks = &(tpm_state->tpm_stany_data.currentTicks); + /* update the ticks based on the current time */ + returnCode = TPM_CurrentTicks_Update(currentTicks); + } + if (returnCode == TPM_SUCCESS) { + /* 6. Create H1 a TPM_SIGN_INFO structure and set the structure defaults */ + printf("TPM_Process_TickStampBlob: Creating TPM_SIGN_INFO structure\n"); + /* NOTE: Done by TPM_SignInfo_Init() */ + /* a. Set H1 -> fixed to 'TSTP' */ + memcpy(h1SignInfo.fixed, "TSTP", TPM_SIGN_INFO_FIXED_SIZE); + /* b. Set H1 -> replay to antiReplay */ + TPM_Nonce_Copy(h1SignInfo.replay, antiReplay ); + /* c. Create H2 the concatenation of digestToStamp || T1 */ + /* add digestToStamp */ + returnCode = TPM_Digest_Store(&h2Data, digestToStamp); + } + /* add T1 (currentTicks) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CurrentTicks_Store(&h2Data, currentTicks); + } + /* d. Set H1 -> dataLen to the length of H2 */ + /* e. Set H1 -> data */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_SetFromStore(&(h1SignInfo.data), &h2Data); + } + /* 7. The TPM computes the signature, sig, using the key referenced by keyHandle, using SHA-1 of + H1 as the information to be signed */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Digesting TPM_SIGN_INFO structure\n"); + returnCode = TPM_SHA1_GenerateStructure(h3Digest, &h1SignInfo, + (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_TickStampBlob: Signing TPM_SIGN_INFO digest\n"); + returnCode = TPM_RSASignToSizedBuffer(&sig, /* signature */ + h3Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* input, signing key */ + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_TickStampBlob: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* 7. The TPM returns T1 as currentTicks parameter */ + returnCode = TPM_CurrentTicks_Store(response, currentTicks); + } + /* 6. Return the signature in sig */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SizedBuffer_Store(response, &sig); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&sig); /* @1 */ + TPM_SignInfo_Delete(&h1SignInfo); /* @2 */ + TPM_Sbuffer_Delete(&h2Data); /* @3 */ + TPM_Sbuffer_Delete(&h1sbuffer); /* @4 */ + return rcf; +} + diff --git a/src/tpm_ticks.h b/src/tpm_ticks.h new file mode 100644 index 00000000..bebfdc69 --- /dev/null +++ b/src/tpm_ticks.h @@ -0,0 +1,97 @@ +/********************************************************************************/ +/* */ +/* Tick Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_ticks.h 4114 2010-09-30 22:24:32Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_TICKS_H +#define TPM_TICKS_H + +#include "tpm_types.h" +#include "tpm_global.h" +#include "tpm_structures.h" + +/* + UINT64 +*/ + +void TPM_Uint64_Init(TPM_UINT64 *tpm_uint64); +TPM_RESULT TPM_Uint64_Load(TPM_UINT64 *tpm_uint64, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Uint64_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_UINT64 *tpm_uint64); +void TPM_Uint64_Copy(TPM_UINT64 *dest, + const TPM_UINT64 *src); +TPM_RESULT TPM_Uint64_Test(void); + +/* + TPM_CURRENT_TICKS +*/ + +void TPM_CurrentTicks_Init(TPM_CURRENT_TICKS *tpm_current_ticks); +TPM_RESULT TPM_CurrentTicks_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_CURRENT_TICKS *tpm_current_ticks); +TPM_RESULT TPM_CurrentTicks_LoadAll(TPM_CURRENT_TICKS *tpm_current_ticks, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_CurrentTicks_StoreAll(TPM_STORE_BUFFER *sbuffer, + const TPM_CURRENT_TICKS *tpm_current_ticks); +TPM_RESULT TPM_CurrentTicks_Start(TPM_CURRENT_TICKS *tpm_current_ticks); +TPM_RESULT TPM_CurrentTicks_Update(TPM_CURRENT_TICKS *tpm_current_ticks); +void TPM_CurrentTicks_Copy(TPM_CURRENT_TICKS *dest, + TPM_CURRENT_TICKS *src); + +/* + Processing Functions +*/ + +TPM_RESULT TPM_Process_GetTicks(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_TickStampBlob(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + +#endif diff --git a/src/tpm_time.c b/src/tpm_time.c new file mode 100644 index 00000000..3e747f69 --- /dev/null +++ b/src/tpm_time.c @@ -0,0 +1,80 @@ +/********************************************************************************/ +/* */ +/* Time Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_time.c 4648 2011-10-25 19:22:18Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +/* TPM_GetTimeOfDay() calls platform specific code to get the time in seconds and microseconds + */ + +#include + +#include "tpm_debug.h" +#include "tpm_error.h" + +#include "tpm_time.h" + +/* TPM_GetTimeOfDay() gets the current time of day. + + Must return TPM_FAIL on error, so that the caller knows to shut down the TPM +*/ + +#ifdef TPM_POSIX + +#include + +TPM_RESULT TPM_GetTimeOfDay(uint32_t *tv_sec, uint32_t *tv_usec) +{ + TPM_RESULT rc = 0; + struct timeval tval; + int irc; + + irc = gettimeofday(&tval, NULL ); /* get the time */ + if (irc == 0) { + *tv_sec = tval.tv_sec; + *tv_usec = tval.tv_usec; + printf(" TPM_GetTimeOfDay: %d sec %d usec\n",*tv_sec, *tv_usec); + } + else { + printf("TPM_GetTimeOfDay: Error (fatal) getting time of day\n"); + rc = TPM_FAIL; + } + return rc; +} + +#endif + + diff --git a/src/tpm_time.h b/src/tpm_time.h new file mode 100644 index 00000000..d7015519 --- /dev/null +++ b/src/tpm_time.h @@ -0,0 +1,49 @@ +/********************************************************************************/ +/* */ +/* TPM Time Utilities */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_time.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_TIME_H +#define TPM_TIME_H + +#include "tpm_types.h" + +#define TPM_TICK_RATE 1 /* in usec for Linux */ +TPM_RESULT TPM_GetTimeOfDay(uint32_t *tv_sec, uint32_t *tv_usec); + + +#endif diff --git a/src/tpm_tis.c b/src/tpm_tis.c new file mode 100644 index 00000000..18196686 --- /dev/null +++ b/src/tpm_tis.c @@ -0,0 +1,253 @@ +/********************************************************************************/ +/* */ +/* TPM TIS I/O */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_tis.c 4505 2011-03-20 17:43:27Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2011. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +/* + This file implements the TPM TIS interface out-of-band commands. +*/ + +#include +#include + +#include "tpm_constants.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_digest.h" +#include "tpm_global.h" +#include "tpm_pcr.h" +#include "tpm_permanent.h" +#include "tpm_process.h" +#include "tpm_transport.h" + +#include "tpm_tis.h" + +/* These commands do not test for TPM_ContinueSelfTest: + + The following operations MUST be available after TPM_Init and before a call to + TPM_ContinueSelfTest 1.9. TPM_HASH_START / TPM_HASH_DATA / TPM_HASH_END */ + +/* TPM_IO_Hash_Start() implements the LPC bus TPM_HASH_START command + */ + +TPM_RESULT TPM_IO_Hash_Start() +{ + TPM_RESULT rc = 0; + tpm_state_t *tpm_state = tpm_instances[0]; /* TPM global state */ + TPM_PCRVALUE zeroPCR; + TPM_BOOL altered = FALSE; /* TRUE if the structure has been changed */ + + printf("\nTPM_IO_Hash_Start: Ordinal Entry\n"); + TPM_Digest_Init(zeroPCR); + + /* Prior to receiving the TPM_HASH_START command the TPM must have received a TPM_Startup + command. If the TPM receives a TPM_HASH_START after a TPM_Init but before a startup command, + the TPM treats this as an error */ + if (rc == 0) { + if (tpm_state->tpm_stany_flags.postInitialise) { + printf("TPM_IO_Hash_Start: Error, postInitialise is TRUE\n"); + rc = TPM_INVALID_POSTINIT; + } + } + /* NOTE: Done by caller + (1) If no TPM_ACCESS_x.activeLocality field is set, the TPM MUST set the + TPM_ACCESS_x.activeLocality field to indicate Locality 4. Any currently executing command + MUST be aborted per and subject to Section 11.2.3. */ + /* NOTE: Done by caller + (2) If TPM_ACCESS_x.activeLocality is set, and if the TPM_ACCESS_x.activeLocality field is + not 4, the TPM MUST ignore this command. */ + /* NOTE: Done by caller + (3) The TPM MUST clear the write FIFO. */ + if (rc == 0) { + /* (4) If there is an exclusive transport session, it MUST be invalidated. */ + if (tpm_state->tpm_stany_flags.transportExclusive != 0) { /* active exclusive */ + rc = TPM_TransportSessions_TerminateHandle + (tpm_state->tpm_stclear_data.transSessions, + tpm_state->tpm_stany_flags.transportExclusive, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + } + if (rc == 0) { + /* (5) Set the TPM_PERMANENT_FLAGS->tpmEstablished flag to TRUE (1). Note: see description of + Bit Field: tpmEstablishment in 11.2.11 Access Register. */ + TPM_SetCapability_Flag(&altered, + &(tpm_state->tpm_permanent_flags.tpmEstablished), + TRUE); + } + if (rc == 0) { + /* (6) Set the TPM_STANY_FLAGS->TOSPresent flag to TRUE (1). */ + tpm_state->tpm_stany_flags.TOSPresent = TRUE; + /* (7) Set PCRs per column labeled TPM_HASH_START in Table 5: PCR Initial and Reset Values. + (PCR 17-22 to zero, others unchanged */ + TPM_PCR_Store(tpm_state->tpm_stclear_data.PCRS, 17, zeroPCR); + TPM_PCR_Store(tpm_state->tpm_stclear_data.PCRS, 18, zeroPCR); + TPM_PCR_Store(tpm_state->tpm_stclear_data.PCRS, 19, zeroPCR); + TPM_PCR_Store(tpm_state->tpm_stclear_data.PCRS, 20, zeroPCR); + TPM_PCR_Store(tpm_state->tpm_stclear_data.PCRS, 21, zeroPCR); + TPM_PCR_Store(tpm_state->tpm_stclear_data.PCRS, 22, zeroPCR); + /* (8) Ignore any data component of the TPM_HASH_START LPC command. */ + /* (9) Allocate tempLocation of a size required to perform the SHA-1 operation. */ + /* (10) Initialize tempLocation per SHA-1. */ + rc = TPM_SHA1InitCmd(&(tpm_state->sha1_context_tis)); + } + rc = TPM_PermanentAll_NVStore(tpm_state, + altered, + rc); + /* + 1) Upon any error in the above steps the TPM: + a) MUST enter Failure Mode. + NOTE: Done by caller + b) MUST release locality. + */ + if (rc != 0) { + printf("TPM_IO_Hash_Start: Error, (fatal)\n"); + printf(" TPM_IO_Hash_Start: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return rc; +} + +/* TPM_IO_Hash_Data() implements the LPC bus TPM_HASH_DATA command + */ + +TPM_RESULT TPM_IO_Hash_Data(const unsigned char *data, + uint32_t data_length) +{ + TPM_RESULT rc = 0; + tpm_state_t *tpm_state = tpm_instances[0]; /* TPM global state */ + + printf("\nTPM_IO_Hash_Data: Ordinal Entry\n"); + /* (1) Transform tempLocation per SHA-1 with data received from this command. */ + /* (2) Repeat for each TPM_HASH_DATA LPC command received. */ + if (rc == 0) { + if (tpm_state->sha1_context_tis == NULL) { + printf("TPM_IO_Hash_Data: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + } + if (rc == 0) { + rc = TPM_SHA1UpdateCmd(tpm_state->sha1_context_tis, data, data_length); + } + /* + 1) Upon any error in the above steps the TPM: + a) MUST enter Failure Mode. + NOTE: Done by caller + b) MUST release locality. + */ + if (rc != 0) { + printf("TPM_IO_Hash_Data: Error, (fatal)\n"); + printf(" TPM_IO_Hash_Data: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return rc; +} + +/* TPM_IO_Hash_End() implements the LPC bus TPM_HASH_END command + */ + +TPM_RESULT TPM_IO_Hash_End() +{ + TPM_RESULT rc = 0; + TPM_PCRVALUE zeroPCR; + TPM_DIGEST extendDigest; + tpm_state_t *tpm_state = tpm_instances[0]; /* TPM global state */ + + printf("\nTPM_IO_Hash_End: Ordinal Entry\n"); + if (rc == 0) { + if (tpm_state->sha1_context_tis == NULL) { + printf("TPM_IO_Hash_End: Error, no existing SHA1 thread\n"); + rc = TPM_SHA_THREAD; + } + } + /* (1) Ignore any data sent with the command. */ + /* (2) Perform finalize operation on tempLocation per SHA-1. */ + if (rc == 0) { + rc = TPM_SHA1FinalCmd(extendDigest, tpm_state->sha1_context_tis); + } + /* (3) Perform an “extend” operation, as defined in the TPM_Extend command, of the value within + tempLocation into PCR[Locality 4]. */ + if (rc == 0) { + /* In the previous line above, “PCR[Locality 4]” within and before the SHA-1 function is + TPM_PCRVALUE = 0 (i.e., 20 bytes of all zeros). */ + TPM_Digest_Init(zeroPCR); /* initial PCR value */ + /* PCR[Locality 4] = SHA-1( PCR[Locality 4] || tempLoc) */ + rc = TPM_SHA1(tpm_state->tpm_stclear_data.PCRS[TPM_LOCALITY_4_PCR], + TPM_DIGEST_SIZE, zeroPCR, + TPM_DIGEST_SIZE, extendDigest, + 0, NULL); + } + /* NOTE: Done by caller + (4) Clear TPM_ACCESS_x.activeLocality for Locality 4. */ + /* + 1) Upon any error in the above steps the TPM: + a) MUST enter Failure Mode. + NOTE: Done by caller + b) MUST release locality. + */ + if (rc != 0) { + printf("TPM_IO_Hash_End: Error, (fatal)\n"); + printf(" TPM_IO_Hash_End: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + TPM_SHA1Delete(&(tpm_state->sha1_context_tis)); + return rc; +} + +TPM_RESULT TPM_IO_TpmEstablished_Get(TPM_BOOL *tpmEstablished) +{ + TPM_RESULT rc = 0; + tpm_state_t *tpm_state = tpm_instances[0]; /* TPM global state */ + + if (rc == 0) { + *tpmEstablished = tpm_state->tpm_permanent_flags.tpmEstablished; + } + /* + 1) Upon any error in the above steps the TPM: + a) MUST enter Failure Mode. + NOTE: Done by caller + b) MUST release locality. + */ + if (rc != 0) { + printf("TPM_IO_TpmEstablished_Get: Error, (fatal)\n"); + printf(" TPM_IO_TpmEstablished_Get: Set testState to %u \n", TPM_TEST_STATE_FAILURE); + tpm_state->testState = TPM_TEST_STATE_FAILURE; + } + return 0; +} + diff --git a/src/tpm_transport.c b/src/tpm_transport.c new file mode 100644 index 00000000..8bae54cd --- /dev/null +++ b/src/tpm_transport.c @@ -0,0 +1,2935 @@ +/********************************************************************************/ +/* */ +/* Transport */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_transport.c 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_audit.h" +#include "tpm_auth.h" +#include "tpm_crypto.h" +#include "tpm_cryptoh.h" +#include "tpm_debug.h" +#include "tpm_digest.h" +#include "tpm_error.h" +#include "tpm_init.h" +#include "tpm_key.h" +#include "tpm_memory.h" +#include "tpm_nonce.h" +#include "tpm_process.h" +#include "tpm_secret.h" +#include "tpm_ticks.h" + +#include "tpm_transport.h" + +/* TPM_Transport_CryptMgf1() takes a 'src', a preallocated 'dest', and an MGF1 'pad' of length + 'len'. + + 'size is the total length of 'src' and 'dest'. + 'index' is the start of the encrypt area + 'len' is the length of the encrypt area + + It copies 'src' to 'dest' up to 'index'. + It then copies 'src' XOR'ed with 'pad' for 'len' + It then copies the remainder of 'src' to 'dest' +*/ + +TPM_RESULT TPM_Transport_CryptMgf1(unsigned char *dest, + const unsigned char *src, + const unsigned char *pad, + uint32_t size, + uint32_t index, + uint32_t len) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Transport_CryptMgf1: size %u index %u len %u\n", size, index, len); + /* sanity check the length */ + if (rc == 0) { + if (index + len > size) { + printf("TPM_Transport_CryptMgf1: Error (fatal), bad size\n"); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + if (rc == 0) { + /* leading clear text area */ + memcpy(dest, src, index); + dest += index; + src += index; + /* encrypt area */ + TPM_XOR(dest, pad, src, len); + dest += len; + src += len; + /* trailing clear text area */ + memcpy(dest, src, size - index - len); + } + return rc; +} + +/* TPM_Transport_CryptSymmetric() takes a 'src', a preallocated 'dest', and a 'symmetric_key' + 'pad_in' (CTR or IV) of length 'len'. + + 'size is the total length of 'src' and 'dest'. + 'index' is the start of the encrypt area + 'len' is the length of the encrypt area + + It copies 'src' to 'dest' up to 'index'. + It then encrypts 'src' to 'dest' using 'symmetric_key and 'pad_in' for 'len' + It then copies the remainder of 'src' to 'dest' +*/ + +TPM_RESULT TPM_Transport_CryptSymmetric(unsigned char *dest, + const unsigned char *src, + TPM_ALGORITHM_ID algId, /* algorithm */ + TPM_ENC_SCHEME encScheme, /* mode */ + const unsigned char *symmetric_key, + uint32_t symmetric_key_size, + unsigned char *pad_in, + uint32_t pad_in_size, + uint32_t size, + uint32_t index, + uint32_t len) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Transport_CryptSymmetric: size %u index %u len %u\n", size, index, len); + /* sanity check the length */ + if (rc == 0) { + if (index + len > size) { + printf("TPM_Transport_CryptSymmetric: Error (fatal), bad size\n"); + rc = TPM_FAIL; /* internal error, should never occur */ + } + } + if (rc == 0) { + /* leading clear text area */ + memcpy(dest, src, index); + dest += index; + src += index; + /* encrypt area */ + rc = TPM_SymmetricKeyData_StreamCrypt(dest, /* output */ + src, /* input */ + len, /* input */ + algId, /* algorithm */ + encScheme, /* mode */ + symmetric_key, /* input */ + symmetric_key_size, /* input */ + pad_in, /* input */ + pad_in_size); /* input */ + } + if (rc == 0) { + dest += len; + src += len; + /* trailing clear text area */ + memcpy(dest, src, size - index - len); + } + return rc; +} + +/* + Transport Sessions (the entire array) +*/ + +void TPM_TransportSessions_Init(TPM_TRANSPORT_INTERNAL *transSessions) +{ + size_t i; + + printf(" TPM_TransportSessions_Init:\n"); + for (i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) { + TPM_TransportInternal_Init(&(transSessions[i])); + } + return; +} + +/* TPM_TransportSessions_Load() reads a count of the number of stored sessions and then loads those + sessions. + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_TransportSessions_Init() + After use, call TPM_TransportSessions_Delete() to free memory +*/ + +TPM_RESULT TPM_TransportSessions_Load(TPM_TRANSPORT_INTERNAL *transSessions, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t activeCount; + + printf(" TPM_TransportSessions_Load:\n"); + /* load active count */ + if (rc == 0) { + rc = TPM_Load32(&activeCount, stream, stream_size); + } + if (rc == 0) { + if (activeCount > TPM_MIN_TRANS_SESSIONS) { + printf("TPM_TransportSessions_Load: Error (fatal) %u sessions, %u slots\n", + activeCount, TPM_MIN_TRANS_SESSIONS); + rc = TPM_FAIL; + } + } + if (rc == 0) { + printf(" TPM_TransportSessions_Load: Loading %u sessions\n", activeCount); + } + for (i = 0 ; (rc == 0) && (i < activeCount) ; i++) { + rc = TPM_TransportInternal_Load(&(transSessions[i]), stream, stream_size); + } + return rc; +} + +/* TPM_TransportSessions_Store() stores a count of the active sessions, followed by the sessions. + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_TRANSPORT_INTERNAL *transSessions) +{ + TPM_RESULT rc = 0; + size_t i; + uint32_t space; /* free transport session slots */ + uint32_t activeCount; /* used transport session slots */ + + /* store active count */ + if (rc == 0) { + TPM_TransportSessions_GetSpace(&space, transSessions); + activeCount = TPM_MIN_TRANS_SESSIONS - space; + printf(" TPM_TransSessions_Store: Storing %u sessions\n", activeCount); + rc = TPM_Sbuffer_Append32(sbuffer, activeCount); + } + /* store transport sessions */ + for (i = 0 ; (rc == 0) && (i < TPM_MIN_TRANS_SESSIONS) ; i++) { + if ((transSessions[i]).valid) { /* if the session is active */ + rc = TPM_TransportInternal_Store(sbuffer, &(transSessions[i])); + } + } + return rc; +} + +/* TPM_TransportSessions_Delete() terminates all sessions + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportSessions_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportSessions_Delete(TPM_TRANSPORT_INTERNAL *transSessions) +{ + size_t i; + + printf(" TPM_TransportSessions_Delete:\n"); + for (i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) { + TPM_TransportInternal_Delete(&(transSessions[i])); + } + return; +} + +/* TPM_TransportSessions_IsSpace() returns 'isSpace' TRUE if an entry is available, FALSE if not. + + If TRUE, 'index' holds the first free position. +*/ + +void TPM_TransportSessions_IsSpace(TPM_BOOL *isSpace, uint32_t *index, + TPM_TRANSPORT_INTERNAL *transSessions) +{ + printf(" TPM_TransportSessions_IsSpace:\n"); + for (*index = 0, *isSpace = FALSE ; *index < TPM_MIN_TRANS_SESSIONS ; (*index)++) { + if (!((transSessions[*index]).valid)) { + printf(" TPM_TransportSessions_IsSpace: Found space at %u\n", *index); + *isSpace = TRUE; + break; + } + } + return; +} + +/* TPM_TransportSessions_GetSpace() returns the number of unused transport sessions. + +*/ + +void TPM_TransportSessions_GetSpace(uint32_t *space, + TPM_TRANSPORT_INTERNAL *transSessions) +{ + uint32_t i; + + printf(" TPM_TransportSessions_GetSpace:\n"); + for (*space = 0 , i = 0 ; i < TPM_MIN_TRANS_SESSIONS ; i++) { + if (!((transSessions[i]).valid)) { + (*space)++; + } + } + return; +} + +/* TPM_TransportSessions_StoreHandles() stores + + - the number of loaded sessions + - a list of session handles +*/ + +TPM_RESULT TPM_TransportSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_TRANSPORT_INTERNAL *transSessions) +{ + TPM_RESULT rc = 0; + uint16_t i; + uint32_t space; + + printf(" TPM_TransportSessions_StoreHandles:\n"); + /* get the number of loaded handles */ + if (rc == 0) { + TPM_TransportSessions_GetSpace(&space, transSessions); + /* store loaded handle count. Cast safe because of TPM_MIN_TRANS_SESSIONS value */ + printf(" TPM_TransportSessions_StoreHandles: %u handles\n", + TPM_MIN_TRANS_SESSIONS - space); + rc = TPM_Sbuffer_Append16(sbuffer, (uint16_t)(TPM_MIN_TRANS_SESSIONS - space)); + } + for (i = 0 ; (rc == 0) && (i < TPM_MIN_TRANS_SESSIONS) ; i++) { + if ((transSessions[i]).valid) { /* if the index is loaded */ + rc = TPM_Sbuffer_Append32(sbuffer, (transSessions[i]).transHandle); /* store it */ + } + } + return rc; +} + +/* TPM_TransportSessions_GetNewHandle() checks for space in the transport sessions table. + + If there is space, it returns a TPM_TRANSPORT_INTERNAL entry in 'tpm_transport_internal'. The + entry is marked 'valid'. + + Returns TPM_RESOURCES if there is no space in the transport sessions table. +*/ + +TPM_RESULT TPM_TransportSessions_GetNewHandle(TPM_TRANSPORT_INTERNAL **tpm_transport_internal, + TPM_TRANSPORT_INTERNAL *transportSessions) +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + TPM_TRANSHANDLE transportHandle = 0; /* no suggested value */ + + printf(" TPM_TransportSessions_GetNewHandle:\n"); + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_TransportSessions_IsSpace(&isSpace, &index, transportSessions); + if (!isSpace) { + printf("TPM_TransportSessions_GetNewHandle: Error, " + "no space in TransportSessions table\n"); + rc = TPM_RESOURCES; + } + } + /* assign transport handle */ + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(&transportHandle, /* I/O */ + transportSessions, /* handle array */ + FALSE, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_TransportSessions_GetEntry); + } + if (rc == 0) { + printf(" TPM_TransportSessions_GetNewHandle: Assigned handle %08x\n", transportHandle); + /* return the TPM_TRANSPORT_INTERNAL */ + *tpm_transport_internal = &(transportSessions[index]); + /* assign the handle */ + (*tpm_transport_internal)->transHandle = transportHandle; + (*tpm_transport_internal)->valid = TRUE; + } + return rc; +} + +/* TPM_TransportSessions_GetEntry() searches all 'transportSessions' entries for the entry matching + the handle, and returns the TPM_TRANSPORT_INTERNAL entry associated with the handle. + + Returns + 0 for success + TPM_INVALID_AUTHHANDLE if the handle is not found +*/ + +TPM_RESULT TPM_TransportSessions_GetEntry(TPM_TRANSPORT_INTERNAL **tpm_transport_internal, + TPM_TRANSPORT_INTERNAL *transportSessions, /* array */ + TPM_TRANSHANDLE transportHandle) /* input */ +{ + TPM_RESULT rc = 0; + size_t i; + TPM_BOOL found; + + printf(" TPM_TransportSessions_GetEntry: transportHandle %08x\n", transportHandle); + for (i = 0, found = FALSE ; (i < TPM_MIN_TRANS_SESSIONS) && !found ; i++) { + if ((transportSessions[i].valid) && + (transportSessions[i].transHandle == transportHandle)) { /* found */ + found = TRUE; + *tpm_transport_internal = &(transportSessions[i]); + } + } + if (!found) { + printf(" TPM_TransportSessions_GetEntry: transport session handle %08x not found\n", + transportHandle); + rc = TPM_INVALID_AUTHHANDLE; + } + return rc; +} + +/* TPM_TransportSessions_AddEntry() adds an TPM_TRANSPORT_INTERNAL object to the list. + + If *tpm_handle == 0, a value is assigned. If *tpm_handle != 0, that value is used if it it not + currently in use. + + The handle is returned in tpm_handle. +*/ + +TPM_RESULT TPM_TransportSessions_AddEntry(TPM_HANDLE *tpm_handle, /* i/o */ + TPM_BOOL keepHandle, /* input */ + TPM_TRANSPORT_INTERNAL *transSessions, /* input */ + TPM_TRANSPORT_INTERNAL *tpm_transport_internal) /* in */ +{ + TPM_RESULT rc = 0; + uint32_t index; + TPM_BOOL isSpace; + + printf(" TPM_TransportSessions_AddEntry: handle %08x, keepHandle %u\n", + *tpm_handle, keepHandle); + /* check for valid TPM_TRANSPORT_INTERNAL */ + if (rc == 0) { + if (tpm_transport_internal == NULL) { /* NOTE: should never occur */ + printf("TPM_TransportSessions_AddEntry: Error (fatal), NULL TPM_TRANSPORT_INTERNAL\n"); + rc = TPM_FAIL; + } + } + /* is there an empty entry, get the location index */ + if (rc == 0) { + TPM_TransportSessions_IsSpace(&isSpace, &index, transSessions); + if (!isSpace) { + printf("TPM_TransportSessions_AddEntry: Error, transport session entries full\n"); + rc = TPM_RESOURCES; + } + } + if (rc == 0) { + rc = TPM_Handle_GenerateHandle(tpm_handle, /* I/O */ + transSessions, /* handle array */ + keepHandle, /* keepHandle */ + FALSE, /* isKeyHandle */ + (TPM_GETENTRY_FUNCTION_T)TPM_TransportSessions_GetEntry); + } + if (rc == 0) { + tpm_transport_internal->transHandle = *tpm_handle; + tpm_transport_internal->valid = TRUE; + TPM_TransportInternal_Copy(&(transSessions[index]), tpm_transport_internal); + printf(" TPM_TransportSessions_AddEntry: Index %u handle %08x\n", + index, transSessions[index].transHandle); + } + return rc; +} + +/* TPM_TransportSessions_TerminateHandle() terminates the session associated with + 'transporthHandle'. + + If the session is exclusive (indicated by a match with TPM_STANY_FLAGS -> transportExclusive), + clear that flag. +*/ + +TPM_RESULT TPM_TransportSessions_TerminateHandle(TPM_TRANSPORT_INTERNAL *transportSessions, + TPM_TRANSHANDLE transportHandle, + TPM_TRANSHANDLE *transportExclusive) +{ + TPM_RESULT rc = 0; + TPM_TRANSPORT_INTERNAL *tpm_transport_internal; + + printf(" TPM_TransportSessions_TerminateHandle: Handle %08x\n", transportHandle); + /* get the TPM_TRANSPORT_INTERNAL associated with the TPM_TRANSHANDLE */ + if (rc == 0) { + rc = TPM_TransportSessions_GetEntry(&tpm_transport_internal, + transportSessions, + transportHandle); + } + /* if the session being terminated is exclusive, reset the flag */ + if (rc == 0) { + if (transportHandle == *transportExclusive) { + printf(" TPM_TransportSessions_TerminateHandle: Is exclusive transport session\n"); + if (!(tpm_transport_internal->transPublic.transAttributes & TPM_TRANSPORT_EXCLUSIVE)) { + printf("TPM_TransportSessions_TerminateHandle: Error (fatal), " + "attribute is not exclusive\n"); + rc = TPM_FAIL; /* internal error, should not occur */ + } + *transportExclusive = 0; + } + } + /* invalidate the valid handle */ + if (rc == 0) { + TPM_TransportInternal_Delete(tpm_transport_internal); + } + return rc; +} + +/* + TPM_TRANSPORT_PUBLIC +*/ + +/* TPM_TransportPublic_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_TransportPublic_Init(TPM_TRANSPORT_PUBLIC *tpm_transport_public) +{ + printf(" TPM_TransportPublic_Init:\n"); + tpm_transport_public->transAttributes = 0; + tpm_transport_public->algId = 0; + tpm_transport_public->encScheme = TPM_ES_NONE; + return; +} + +/* TPM_TransportPublic_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_TransportPublic_Init() + After use, call TPM_TransportPublic_Delete() to free memory +*/ + +TPM_RESULT TPM_TransportPublic_Load(TPM_TRANSPORT_PUBLIC *tpm_transport_public, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportPublic_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_TRANSPORT_PUBLIC, stream, stream_size); + } + /* load transAttributes */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_transport_public->transAttributes ), stream, stream_size); + } + /* load algId */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_transport_public->algId), stream, stream_size); + } + /* load encScheme */ + if (rc == 0) { + rc = TPM_Load16(&(tpm_transport_public->encScheme), stream, stream_size); + } + return rc; +} + +/* TPM_TransportPublic_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportPublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_PUBLIC *tpm_transport_public) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportPublic_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_PUBLIC); + } + /* store transAttributes */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_public->transAttributes); + } + /* store algId */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_public->algId); + } + /* store encScheme */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, tpm_transport_public->encScheme); + } + return rc; +} + +/* TPM_TransportPublic_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportPublic_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportPublic_Delete(TPM_TRANSPORT_PUBLIC *tpm_transport_public) +{ + printf(" TPM_TransportPublic_Delete:\n"); + if (tpm_transport_public != NULL) { + TPM_TransportPublic_Init(tpm_transport_public); + } + return; +} + +/* TPM_TransportPublic_Copy() copies the 'src' to the 'dest' structure + +*/ + +TPM_RESULT TPM_TransportPublic_Copy(TPM_TRANSPORT_PUBLIC *dest, + const TPM_TRANSPORT_PUBLIC *src) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportPublic_Copy:\n"); + /* copy transAttributes */ + dest->transAttributes = src->transAttributes; + /* copy algId */ + dest->algId = src->algId; + /* copy encScheme */ + dest->encScheme = src->encScheme; + return rc; +} + +/* TPM_TransportPublic_CheckAlgId() returns 'supported' TRUE if the transport encryption algorithm + is supported by the TPM + +*/ + +void TPM_TransportPublic_CheckAlgId(TPM_BOOL *supported, + TPM_ALGORITHM_ID algId) +{ + printf(" TPM_TransportPublic_CheckAlgId: %08x\n", algId); + switch (algId) { + /* supported protocols */ + case TPM_ALG_MGF1: + case TPM_ALG_AES128: + *supported = TRUE; + break; + /* unsupported protocols */ + case TPM_ALG_RSA: + case TPM_ALG_SHA: + case TPM_ALG_HMAC: + case TPM_ALG_AES192: + case TPM_ALG_AES256: + default: + *supported = FALSE; + break; + } + return; +} + +/* TPM_TransportPublic_CheckEncScheme() returns success and the blockSize if the transport algId and + encScheme are supported by the TPM. +*/ + +TPM_RESULT TPM_TransportPublic_CheckEncScheme(uint32_t *blockSize, + TPM_ALGORITHM_ID algId, + TPM_ENC_SCHEME encScheme, + TPM_BOOL FIPS) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportPublic_CheckEncScheme: algId %08x encScheme %04hx\n", algId, encScheme); + switch (algId) { + /* supported protocols with no encScheme */ + case TPM_ALG_MGF1: + *blockSize = 0; /* MGF1 does not use blocks */ + if (FIPS) { + printf("TPM_TransportPublic_CheckEncScheme: Error, " + "TPM_ALG_MGF1 not supported in FIPS\n"); + rc = TPM_INAPPROPRIATE_ENC; + } + /* For TPM_ALG_MGF1, TPM_ENC_SCHEME is not used. The TPM MAY validate that TPM_ENC_SCHEME + is TPM_ES_NONE. */ + if (encScheme != TPM_ES_NONE) { + printf("TPM_TransportPublic_CheckEncScheme: Error, " + "TPM_ALG_MGF1 must use TPM_ES_NONE\n"); + rc = TPM_INAPPROPRIATE_ENC; + } + break; + /* protocols with encScheme */ + case TPM_ALG_AES128: + switch(encScheme) { + case TPM_ES_SYM_CTR: /* CTR mode */ + case TPM_ES_SYM_OFB: /* OFB mode */ + *blockSize = 128/8; + break; + default: + printf("TPM_TransportPublic_CheckEncScheme: Error, AES128 encScheme not supported\n"); + rc = TPM_INAPPROPRIATE_ENC; + break; + } + break; + /* unsupported protocols */ + case TPM_ALG_AES192: + case TPM_ALG_AES256: + case TPM_ALG_RSA: + case TPM_ALG_SHA: + case TPM_ALG_HMAC: + case TPM_ALG_XOR: + default: + printf("TPM_TransportPublic_CheckEncScheme: Error, algId not supported\n"); + rc = TPM_BAD_KEY_PROPERTY; + break; + } + return rc; +} + +/* + TPM_TRANSPORT_INTERNAL +*/ + +/* TPM_TransportInternal_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_TransportInternal_Init(TPM_TRANSPORT_INTERNAL *tpm_transport_internal) +{ + printf(" TPM_TransportInternal_Init:\n"); + TPM_Secret_Init(tpm_transport_internal->authData); + TPM_TransportPublic_Init(&(tpm_transport_internal->transPublic)); + tpm_transport_internal->transHandle = 0; + TPM_Nonce_Init(tpm_transport_internal->transNonceEven); + TPM_Digest_Init(tpm_transport_internal->transDigest); + tpm_transport_internal->valid = FALSE; + return; +} + +/* TPM_TransportInternal_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_TransportInternal_Init() + After use, call TPM_TransportInternal_Delete() to free memory +*/ + +TPM_RESULT TPM_TransportInternal_Load(TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportInternal_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_TRANSPORT_INTERNAL, stream, stream_size); + } + /* load authData */ + if (rc == 0) { + rc = TPM_Secret_Load(tpm_transport_internal->authData, stream, stream_size); + } + /* load transPublic */ + if (rc == 0) { + rc = TPM_TransportPublic_Load(&(tpm_transport_internal->transPublic), stream, stream_size); + } + /* load transHandle */ + if (rc == 0) { + rc = TPM_Load32(&(tpm_transport_internal->transHandle), stream, stream_size); + } + /* load transNonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Load(tpm_transport_internal->transNonceEven, stream, stream_size); + } + /* load transDigest */ + if (rc == 0) { + rc = TPM_Digest_Load(tpm_transport_internal->transDigest, stream, stream_size); + } + /* load valid */ + if (rc == 0) { + tpm_transport_internal->valid = TRUE; + } + return rc; +} + +/* TPM_TransportInternal_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportInternal_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_INTERNAL *tpm_transport_internal) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportInternal_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_INTERNAL); + } + /* store authData */ + if (rc == 0) { + rc = TPM_Secret_Store(sbuffer, tpm_transport_internal->authData); + } + /* store transPublic */ + if (rc == 0) { + rc = TPM_TransportPublic_Store(sbuffer, &(tpm_transport_internal->transPublic)); + } + /* store transHandle */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_internal->transHandle); + } + /* store transNonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Store(sbuffer, tpm_transport_internal->transNonceEven); + } + /* store transDigest */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_transport_internal->transDigest); + } + return rc; +} + +/* TPM_TransportInternal_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportInternal_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportInternal_Delete(TPM_TRANSPORT_INTERNAL *tpm_transport_internal) +{ + printf(" TPM_TransportInternal_Delete:\n"); + if (tpm_transport_internal != NULL) { + TPM_TransportPublic_Delete(&(tpm_transport_internal->transPublic)); + TPM_TransportInternal_Init(tpm_transport_internal); + } + return; +} + +/* TPM_TransportInternal_Copy() copies the source to the destination. + +*/ + +void TPM_TransportInternal_Copy(TPM_TRANSPORT_INTERNAL *dest_transport_internal, + TPM_TRANSPORT_INTERNAL *src_transport_internal) +{ + TPM_Secret_Copy(dest_transport_internal->authData, src_transport_internal->authData); + TPM_TransportPublic_Copy(&(dest_transport_internal->transPublic), + &(src_transport_internal->transPublic)); + dest_transport_internal->transHandle = src_transport_internal->transHandle; + TPM_Nonce_Copy(dest_transport_internal->transNonceEven, src_transport_internal->transNonceEven); + TPM_Digest_Copy(dest_transport_internal->transDigest, src_transport_internal->transDigest); + dest_transport_internal->valid = src_transport_internal->valid; +} + +/* TPM_TransportInternal_Check() checks the authorization of a command. + + There is no need to protect against dictionary attacks. The first failure terminates the + transport session. + + Returns TPM_AUTH2FAIL if the TPM_AUTHDATA does not match. +*/ + +TPM_RESULT TPM_TransportInternal_Check(TPM_DIGEST inParamDigest, /* digest of inputs + above line */ + TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + TPM_NONCE transNonceOdd, /* Nonce generated + by system + associated with + transHandle */ + TPM_BOOL continueTransSession, + TPM_AUTHDATA transAuth) /* Authorization + digest for + input */ +{ + TPM_RESULT rc = 0; + TPM_BOOL valid; + + printf(" TPM_TransportInternal_Check:\n"); + if (rc == 0) { + TPM_PrintFour(" TPM_TransportInternal_Check: inParamDigest", inParamDigest); + TPM_PrintFour(" TPM_TransportInternal_Check: usageAuth (key)", + tpm_transport_internal->authData); + TPM_PrintFour(" TPM_TransportInternal_Check: nonceEven", + tpm_transport_internal->transNonceEven); + TPM_PrintFour(" TPM_TransportInternal_Check: nonceOdd", transNonceOdd); + printf (" TPM_TransportInternal_Check: continueSession %02x\n", continueTransSession); + /* HMAC the inParamDigest, transLastNonceEven, transNonceOdd, continueTransSession */ + /* transLastNonceEven is retrieved from internal transport session storage */ + rc = TPM_HMAC_Check(&valid, + transAuth, /* expected, from command */ + tpm_transport_internal->authData, /* key */ + sizeof(TPM_DIGEST), inParamDigest, /* command digest */ + sizeof(TPM_NONCE), tpm_transport_internal->transNonceEven, /* 2H */ + sizeof(TPM_NONCE), transNonceOdd, /* 3H */ + sizeof(TPM_BOOL), &continueTransSession, /* 4H */ + 0, NULL); + } + if (rc == 0) { + if (!valid) { + printf("TPM_TransportInternal_Check: Error, authorization failed\n"); + rc = TPM_AUTH2FAIL; + } + } + return rc; +} + +/* TPM_TransportInternal_Set() sets the transport response transAuth. + + It conditionally generates the next transNonceEven. + + It appends transNonceEven and continueTransSession to the response. + + It generates transAuth using outParamDigest and the standard 'below the line' HMAC rules and + appends it to the response. +*/ + +TPM_RESULT TPM_TransportInternal_Set(TPM_STORE_BUFFER *response, + TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + TPM_DIGEST outParamDigest, + TPM_NONCE transNonceOdd, + TPM_BOOL continueTransSession, + TPM_BOOL generateNonceEven) +{ + TPM_RESULT rc = 0; + TPM_AUTHDATA transAuth; /* The authorization digest for the returned parameters */ + + printf(" TPM_TransportInternal_Set:\n"); + /* generate transNonceEven if not already done by caller */ + if ((rc == 0) && generateNonceEven) { + rc = TPM_Nonce_Generate(tpm_transport_internal->transNonceEven); + } + /* append transNonceEven */ + if (rc == 0) { + rc = TPM_Nonce_Store(response, tpm_transport_internal->transNonceEven); + } + /* append continueTransSession*/ + if (rc == 0) { + rc = TPM_Sbuffer_Append(response, &continueTransSession, sizeof(TPM_BOOL)); + } + /* Calculate transAuth using the transport session authData */ + if (rc == 0) { + rc = TPM_Authdata_Generate(transAuth, /* result */ + tpm_transport_internal->authData, /* HMAC key */ + outParamDigest, /* params */ + tpm_transport_internal->transNonceEven, + transNonceOdd, + continueTransSession); + } + /* append transAuth */ + if (rc == 0) { + rc = TPM_Authdata_Store(response, transAuth); + } + return rc; +} + +/* + TPM_TRANSPORT_LOG_IN +*/ + +/* TPM_TransportLogIn_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_TransportLogIn_Init(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) +{ + printf(" TPM_TransportLogIn_Init:\n"); + TPM_Digest_Init(tpm_transport_log_in->parameters); + TPM_Digest_Init(tpm_transport_log_in->pubKeyHash); + return; +} + +/* TPM_TransportLogIn_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportLogIn_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportLogIn_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_LOG_IN); + } + /* store parameters */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_transport_log_in->parameters); + } + /* store pubKeyHash */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_transport_log_in->pubKeyHash); + } + return rc; +} + +/* TPM_TransportLogIn_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportLogIn_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportLogIn_Delete(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) +{ + printf(" TPM_TransportLogIn_Delete:\n"); + if (tpm_transport_log_in != NULL) { + TPM_TransportLogIn_Init(tpm_transport_log_in); + } + return; +} + +/* TPM_TransportLogIn_Extend() extends 'tpm_digest' + + tpm_digest = SHA-1 (tpm_digest || tpm_transport_log_in) +*/ + +TPM_RESULT TPM_TransportLogIn_Extend(TPM_DIGEST tpm_digest, + TPM_TRANSPORT_LOG_IN *tpm_transport_log_in) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_TransportLogIn_Extend:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize TPM_TRANSPORT_LOG_IN */ + if (rc == 0) { + rc = TPM_TransportLogIn_Store(&sbuffer, tpm_transport_log_in); + } + if (rc == 0) { + /* get the TPM_TRANSPORT_LOG_IN serialization results */ + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + TPM_PrintAll(" TPM_TransportLogIn_Extend: transDigest in", tpm_digest, TPM_DIGEST_SIZE); + TPM_PrintAll(" TPM_TransportLogIn_Extend", buffer, length); + rc = TPM_SHA1(tpm_digest, + TPM_DIGEST_SIZE, tpm_digest, + length, buffer, + 0, NULL); + TPM_PrintAll(" TPM_TransportLogIn_Extend: transDigest out", tpm_digest, TPM_DIGEST_SIZE); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + TPM_TRANSPORT_LOG_OUT +*/ + +/* TPM_TransportLogOut_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_TransportLogOut_Init(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) +{ + printf(" TPM_TransportLogOut_Init:\n"); + TPM_CurrentTicks_Init(&(tpm_transport_log_out->currentTicks)); + TPM_Digest_Init(tpm_transport_log_out->parameters); + tpm_transport_log_out = 0; + return; +} + +/* TPM_TransportLogOut_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportLogOut_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportLogOut_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_LOG_OUT); + } + /* store currentTicks */ + if (rc == 0) { + rc = TPM_CurrentTicks_Store(sbuffer, &(tpm_transport_log_out->currentTicks)); + } + /* store parameters */ + if (rc == 0) { + rc = TPM_Digest_Store(sbuffer, tpm_transport_log_out->parameters); + } + /* store locality */ + if (rc == 0) { + rc = TPM_Sbuffer_Append32(sbuffer, tpm_transport_log_out->locality); + } + return rc; +} + +/* TPM_TransportLogOut_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportLogOut_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportLogOut_Delete(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) +{ + printf(" TPM_TransportLogOut_Delete:\n"); + if (tpm_transport_log_out != NULL) { + TPM_TransportLogOut_Init(tpm_transport_log_out); + } + return; +} + +/* TPM_TransportLogOut_Extend() extends 'tpm_digest' + + tpm_digest = SHA-1 (tpm_digest || tpm_transport_log_out) +*/ + +TPM_RESULT TPM_TransportLogOut_Extend(TPM_DIGEST tpm_digest, + TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out) +{ + TPM_RESULT rc = 0; + TPM_STORE_BUFFER sbuffer; + const unsigned char *buffer; /* serialized buffer */ + uint32_t length; /* serialization length */ + + printf(" TPM_TransportLogOut_Extend:\n"); + TPM_Sbuffer_Init(&sbuffer); /* freed @1 */ + /* serialize TPM_TRANSPORT_LOG_OUT */ + if (rc == 0) { + rc = TPM_TransportLogOut_Store(&sbuffer, tpm_transport_log_out); + } + if (rc == 0) { + /* get the TPM_TRANSPORT_LOG_OUT serialization results */ + TPM_Sbuffer_Get(&sbuffer, &buffer, &length); + TPM_PrintAll(" TPM_TransportLogOut_Extend: transDigest in", tpm_digest, TPM_DIGEST_SIZE); + TPM_PrintAll(" TPM_TransportLogOut_Extend:", buffer, length); + rc = TPM_SHA1(tpm_digest, + TPM_DIGEST_SIZE, tpm_digest, + length, buffer, + 0, NULL); + TPM_PrintAll(" TPM_TransportLogOut_Extend: transDigest out", tpm_digest, TPM_DIGEST_SIZE); + } + TPM_Sbuffer_Delete(&sbuffer); /* @1 */ + return rc; +} + +/* + TPM_TRANSPORT_AUTH +*/ + +/* TPM_TransportAuth_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_TransportAuth_Init(TPM_TRANSPORT_AUTH *tpm_transport_auth) +{ + printf(" TPM_TransportAuth_Init:\n"); + TPM_Secret_Init(tpm_transport_auth->authData); + return; +} + +/* TPM_TransportAuth_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_TransportAuth_Init() + After use, call TPM_TransportAuth_Delete() to free memory +*/ + +TPM_RESULT TPM_TransportAuth_Load(TPM_TRANSPORT_AUTH *tpm_transport_auth, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportAuth_Load:\n"); + /* check tag */ + if (rc == 0) { + rc = TPM_CheckTag(TPM_TAG_TRANSPORT_AUTH, stream, stream_size); + } + /* load authData */ + if (rc == 0) { + TPM_Secret_Load(tpm_transport_auth->authData, stream, stream_size); + } + return rc; +} + +/* TPM_TransportAuth_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_TransportAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_AUTH *tpm_transport_auth) +{ + TPM_RESULT rc = 0; + + printf(" TPM_TransportAuth_Store:\n"); + /* store tag */ + if (rc == 0) { + rc = TPM_Sbuffer_Append16(sbuffer, TPM_TAG_TRANSPORT_AUTH); + } + /* store authData */ + if (rc == 0) { + TPM_Secret_Store(sbuffer, tpm_transport_auth->authData); + } + return rc; +} + +/* TPM_TransportAuth_Delete() + + No-OP if the parameter is NULL, else: + frees memory allocated for the object + sets pointers to NULL + calls TPM_TransportAuth_Init to set members back to default values + The object itself is not freed +*/ + +void TPM_TransportAuth_Delete(TPM_TRANSPORT_AUTH *tpm_transport_auth) +{ + printf(" TPM_TransportAuth_Delete:\n"); + if (tpm_transport_auth != NULL) { + TPM_TransportAuth_Init(tpm_transport_auth); + } + return; +} + +/* TPM_TransportAuth_DecryptSecret() decrypts the secret using the private key. The + result is deserialized and stored in the TPM_TRANSPORT_AUTH structure. +*/ + +TPM_RESULT TPM_TransportAuth_DecryptSecret(TPM_TRANSPORT_AUTH *tpm_transport_auth, /* result */ + TPM_SIZED_BUFFER *secret, /* encrypted input */ + TPM_KEY *tpm_key) /* key for decrypting */ +{ + TPM_RESULT rc = 0; + unsigned char *decryptData = NULL; /* freed @1 */ + uint32_t decryptDataLength = 0; /* actual valid data */ + unsigned char *stream; + uint32_t stream_size; + + printf(" TPM_TransportAuth_DecryptSecret:\n"); + /* allocate space for the decrypted data */ + if (rc == 0) { + rc = TPM_RSAPrivateDecryptMalloc(&decryptData, /* decrypted data */ + &decryptDataLength, /* actual size of decrypted data */ + secret->buffer, /* encrypted data */ + secret->size, /* encrypted data size */ + tpm_key); + } + /* load the TPM_TRANSPORT_AUTH structure from the decrypted data stream */ + if (rc == 0) { + /* use temporary variables, because TPM_TransportAuth_Load() moves the stream */ + stream = decryptData; + stream_size = decryptDataLength; + rc = TPM_TransportAuth_Load(tpm_transport_auth, &stream, &stream_size); + } + free(decryptData); /* @1 */ + return rc; +} + +/* + Processing Functions +*/ + +/* 24.1 TPM_EstablishTransport rev 98 + + This establishes the 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. + + The only restriction on what can happen inside of a transport session is that there is no + "nesting" of sessions. It is permissible to perform operations that delete internal state and + make the TPM inoperable. +*/ + +TPM_RESULT TPM_Process_EstablishTransport(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE encHandle; /* The handle to the key that encrypted the blob */ + TPM_TRANSPORT_PUBLIC transPublic; /* The public information describing the transport + session */ + TPM_SIZED_BUFFER secret; /* The encrypted secret area */ + TPM_AUTHHANDLE authHandle; /* The authorization session handle used for + keyHandle authorization */ + TPM_NONCE nonceOdd; /* Nonce generated by system associated with + authHandle */ + TPM_BOOL continueAuthSession = TRUE; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA keyAuth; /* Authorization. HMAC key: encKey.usageAuth */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for dataAuthHandle */ + TPM_SECRET *hmacKey; + TPM_KEY *encKey = NULL; /* the key specified by encHandle */ + TPM_BOOL parentPCRStatus; + TPM_SECRET *encKeyUsageAuth; + TPM_AUTHDATA *a1AuthData; + TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal; + TPM_TRANSPORT_AUTH k1TransportAuth; + uint32_t blockSize; /* symmetric key block size, not used */ + TPM_TRANSPORT_LOG_IN l1TransportLogIn; + TPM_TRANSPORT_LOG_OUT l2TransportLogOut; + TPM_STORE_BUFFER transPublicSbuffer; /* serialized transPublic */ + const unsigned char *transPublicBuffer; /* serialized buffer */ + uint32_t transPublicLength; /* serialization length */ + TPM_STORE_BUFFER currentTicksSbuffer; /* serialized currentTicks */ + const unsigned char *currentTicksBuffer; /* serialized buffer */ + uint32_t currentTicksLength; /* serialization length */ + TPM_COMMAND_CODE nOrdinal; /* ordinal in nbo */ + uint32_t nSecretSize; /* secretSize in nbo */ + TPM_RESULT nReturnCode; /* returnCode in nbo */ + TPM_MODIFIER_INDICATOR nLocality; /* locality in nbo */ + TPM_BOOL trans_session_added = FALSE; + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CURRENT_TICKS currentTicks; /* The current tick count */ + TPM_NONCE transNonceEven; /* The even nonce in use for subsequent + execute transport */ + + printf("TPM_Process_EstablishTransport: Ordinal Entry\n"); + TPM_TransportPublic_Init(&transPublic); /* freed @1 */ + TPM_SizedBuffer_Init(&secret); /* freed @2 */ + TPM_CurrentTicks_Init(¤tTicks); /* no need to free */ + TPM_TransportAuth_Init(&k1TransportAuth); /* freed @4 */ + TPM_TransportLogIn_Init(&l1TransportLogIn); /* freed @5 */ + TPM_TransportLogOut_Init(&l2TransportLogOut); /* freed @6 */ + TPM_Sbuffer_Init(&transPublicSbuffer); /* freed @7 */ + TPM_Sbuffer_Init(¤tTicksSbuffer); /* freed @8 */ + /* + get inputs + */ + /* get encHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&encHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get transPublic */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EstablishTransport: keyHandle %08x\n", encHandle); + returnCode = TPM_TransportPublic_Load(&transPublic, &command, ¶mSize); + } + /* get secret */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EstablishTransport: transPublic->transAttributes %08x\n", + transPublic.transAttributes); + returnCode = TPM_SizedBuffer_Load(&secret, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag10(tag); + } + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + nonceOdd, + &continueAuthSession, + keyAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_EstablishTransport: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + authHandleValid = FALSE; + } + /* + Processing + */ + if (returnCode == TPM_SUCCESS) { + /* 1. If encHandle is TPM_KH_TRANSPORT then */ + if (encHandle == TPM_KH_TRANSPORT) { + printf("TPM_Process_EstablishTransport: TPM_KH_TRANSPORT clear text secret\n"); + /* a. If tag is NOT TPM_TAG_RQU_COMMAND return TPM_BADTAG */ + if (returnCode == TPM_SUCCESS) { + if (tag != TPM_TAG_RQU_COMMAND) { + printf("TPM_Process_EstablishTransport: Error, " + "TPM_KH_TRANSPORT but not auth-0\n"); + returnCode = TPM_BADTAG; + } + } + /* b. If transPublic -> transAttributes specifies TPM_TRANSPORT_ENCRYPT return + TPM_BAD_SCHEME */ + if (returnCode == TPM_SUCCESS) { + if (transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) { + printf("TPM_Process_EstablishTransport: Error, " + "TPM_KH_TRANSPORT but TPM_TRANSPORT_ENCRYPT\n"); + returnCode = TPM_BAD_SCHEME; + } + } + /* c. If secretSize is not 20 return TPM_BAD_PARAM_SIZE */ + if (returnCode == TPM_SUCCESS) { + if (secret.size != TPM_DIGEST_SIZE) { + printf("TPM_Process_EstablishTransport: Error, secretSize %u not %u\n", + secret.size, TPM_DIGEST_SIZE); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* d. Set A1 to secret */ + if (returnCode == TPM_SUCCESS) { + a1AuthData = (TPM_AUTHDATA *)(secret.buffer); + TPM_PrintFour("TPM_Process_EstablishTransport: transport clear text authData", *a1AuthData); + } + } + /* 2. Else */ + else { + printf("TPM_Process_EstablishTransport: Decrypt secret\n"); + /* get the key corresponding to the encHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&encKey, &parentPCRStatus, tpm_state, + encHandle, + FALSE, /* not r/o, using to encrypt */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* a. encHandle -> keyUsage MUST be TPM_KEY_STORAGE or TPM_KEY_LEGACY return + TPM_INVALID_KEYUSAGE on error */ + if (returnCode == TPM_SUCCESS) { + if ((encKey->keyUsage != TPM_KEY_STORAGE) && + (encKey->keyUsage != TPM_KEY_LEGACY)) { + printf("TPM_Process_EstablishTransport: Error, " + "key keyUsage %04hx must be TPM_KEY_STORAGE or TPM_KEY_LEGACY\n", + encKey->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* b. If encHandle -> authDataUsage does not equal TPM_AUTH_NEVER and tag is NOT + TPM_TAG_RQU_AUTH1_COMMAND return TPM_AUTHFAIL */ + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH1_COMMAND)) { + if (encKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_EstablishTransport: Error, " + "encKey authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get encHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&encKeyUsageAuth, encKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + encKey, + encKeyUsageAuth, /* OIAP */ + encKey->tpm_store_asymkey-> + pubDataDigest); /*OSAP */ + } + /* c. Using encHandle -> usageAuth, validate the AuthData to use the key and the + parameters to the command */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + nonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + keyAuth); /* Authorization digest for input */ + } + /* d. Create K1 a TPM_TRANSPORT_AUTH structure by decrypting secret using the key + pointed to by encHandle */ + /* e. Validate K1 for tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportAuth_DecryptSecret(&k1TransportAuth, + &secret, + encKey); + + } + /* f. Set A1 to K1 -> authData */ + if (returnCode == TPM_SUCCESS) { + a1AuthData = &(k1TransportAuth.authData); + TPM_PrintFour("TPM_Process_EstablishTransport: transport decrypted authData", + *a1AuthData); + } + } + } + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_EstablishTransport: transport authData", *a1AuthData); + } + /* 3. If transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT */ + if ((returnCode == TPM_SUCCESS) && (transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT)) { + printf("TPM_Process_EstablishTransport: Check encrypt attributes\n"); + /* a. If TPM_PERMANENT_FLAGS -> FIPS is true and transPublic -> algId is equal to + TPM_ALG_MGF1 return TPM_INAPPROPRIATE_ENC */ + /* b. Check if the transPublic -> algId is supported, if not return TPM_BAD_KEY_PROPERTY */ + /* c. If transPublic -> algid is TPM_ALG_AESXXX, check that transPublic -> encScheme is + supported, if not return TPM_INAPPROPRIATE_ENC */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportPublic_CheckEncScheme(&blockSize, + transPublic.algId, + transPublic.encScheme, + tpm_state->tpm_permanent_flags.FIPS); + } + /* d. Perform any initializations necessary for the algorithm */ + } + /* 4. Generate transNonceEven from the TPM RNG */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Generate(transNonceEven); + } + /* 5. Create T1 a TPM_TRANSPORT_INTERNAL structure */ + /* NOTE Done by TPM_TransportInternal_Init() */ + /* a. Ensure that the TPM has sufficient internal space to allocate the transport session, + return TPM_RESOURCES on error */ + /* b. Assign a T1 -> transHandle value. This value is assigned by the TPM */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_INTERNAL\n"); + returnCode = + TPM_TransportSessions_GetNewHandle(&t1TpmTransportInternal, + tpm_state->tpm_stclear_data.transSessions); + } + if (returnCode == TPM_SUCCESS) { + /* record that the entry is allocated, for invalidation on error */ + trans_session_added = TRUE; + /* c. Set T1 -> transDigest to NULL */ + TPM_Digest_Init(t1TpmTransportInternal->transDigest); + /* d. Set T1 -> transPublic to transPublic */ + TPM_TransportPublic_Copy(&(t1TpmTransportInternal->transPublic), &transPublic); + /* e. Set T1-> transNonceEven to transNonceEven */ + TPM_Nonce_Copy(t1TpmTransportInternal->transNonceEven , transNonceEven); + /* f. Set T1 -> authData to A1 */ + TPM_Secret_Copy(t1TpmTransportInternal->authData, *a1AuthData); + /* 6. If TPM_STANY_DATA -> currentTicks is not properly initialized */ + /* a. Initialize the TPM_STANY_DATA -> currentTicks */ + returnCode = TPM_CurrentTicks_Update(&(tpm_state->tpm_stany_data.currentTicks)); + } + /* 7. Set currentTicks to TPM_STANY_DATA -> currentTicks */ + if (returnCode == TPM_SUCCESS) { + TPM_CurrentTicks_Copy(¤tTicks, &(tpm_state->tpm_stany_data.currentTicks)); + } + /* 8. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */ + if ((returnCode == TPM_SUCCESS) && + (t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_LOG)) { + + printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_LOG_IN\n"); + /* a. Create L1 a TPM_TRANSPORT_LOG_IN structure */ + /* NOTE Done by TPM_TransportLogIn_Init() */ + /* i. Set L1 -> parameters to SHA-1 (ordinal || transPublic || secretSize || secret) */ + /* serialize transPublic */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportPublic_Store(&transPublicSbuffer, &transPublic); + } + if (returnCode == TPM_SUCCESS) { + /* get the transPublic serialization results */ + TPM_Sbuffer_Get(&transPublicSbuffer, &transPublicBuffer, &transPublicLength); + /* digest the fields */ + nOrdinal = htonl(ordinal); + nSecretSize = htonl(secret.size); + returnCode = TPM_SHA1(l1TransportLogIn.parameters, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + transPublicLength, transPublicBuffer, + sizeof(uint32_t), &nSecretSize, + secret.size, secret.buffer, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + /* ii. Set L1 -> pubKeyHash to NULL */ + /* NOTE Done by TPM_TransportLogIn_Init() */ + /* iii. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || L1) */ + printf("TPM_Process_EstablishTransport: Extend transDigest with input\n"); + returnCode = TPM_TransportLogIn_Extend(t1TpmTransportInternal->transDigest, + &l1TransportLogIn); + } + /* b. Create L2 a TPM_TRANSPORT_LOG_OUT structure */ + /* NOTE Done by TPM_TransportLogOut_Init() */ + /* i. Set L2 -> parameters to SHA-1 (returnCode || ordinal || locality || currentTicks || + transNonceEven) */ + /* serialize currentTicks */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_EstablishTransport: Construct TPM_TRANSPORT_LOG_OUT\n"); + returnCode = TPM_CurrentTicks_Store(¤tTicksSbuffer, ¤tTicks); + } + if (returnCode == TPM_SUCCESS) { + /* get the currentTicks serialization results */ + TPM_Sbuffer_Get(¤tTicksSbuffer, ¤tTicksBuffer, ¤tTicksLength); + nReturnCode = htonl(returnCode); + nLocality = htonl(tpm_state->tpm_stany_flags.localityModifier); + returnCode = TPM_SHA1(l2TransportLogOut.parameters, + sizeof(TPM_RESULT), &nReturnCode, + sizeof(TPM_COMMAND_CODE), &nOrdinal, + sizeof(TPM_MODIFIER_INDICATOR), &nLocality, + currentTicksLength, currentTicksBuffer, + TPM_NONCE_SIZE, transNonceEven, + 0, NULL); + } + if (returnCode == TPM_SUCCESS) { + /* ii. Set L2 -> locality to the locality of this command */ + l2TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier; + /* iii. Set L2 -> currentTicks to currentTicks, this MUST be the same value that is + returned in the currentTicks parameter */ + TPM_CurrentTicks_Copy(&(l2TransportLogOut.currentTicks), ¤tTicks); + /* iv. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || L2) */ + printf("TPM_Process_EstablishTransport: Extend transDigest with output\n"); + returnCode = TPM_TransportLogOut_Extend(t1TpmTransportInternal->transDigest, + &l2TransportLogOut); + } + } + /* 9. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_EXCLUSIVE then + set TPM_STANY_FLAGS -> transportExclusive to TRUE */ + if (returnCode == TPM_SUCCESS) { + if (t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_EXCLUSIVE) { + printf("TPM_Process_EstablishTransport: Session is exclusive\n"); + tpm_state->tpm_stany_flags.transportExclusive = t1TpmTransportInternal->transHandle; + } + } + /* a. Execution of any command other than TPM_ExecuteTransport or TPM_ReleaseTransportSigned + targeting this transport session will cause the abnormal invalidation of this transport + session transHandle */ + /* b. The TPM gives no indication, other than invalidation of transHandle, that the session is + terminated */ + /* NOTE Done by TPM_Process_Preprocess() */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_EstablishTransport: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + /* 10. Return T1 -> transHandle as transHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, t1TpmTransportInternal->transHandle); + } + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return locality */ + returnCode = TPM_Sbuffer_Append32(response, + tpm_state->tpm_stany_flags.localityModifier); + } + /* return currentTicks */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CurrentTicks_Store(response, ¤tTicks); + } + if (returnCode == TPM_SUCCESS) { + /* return transNonceEven */ + returnCode = TPM_Nonce_Store(response, transNonceEven); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH1_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + nonceOdd, + continueAuthSession); + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING))) && + trans_session_added) { + TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, + t1TpmTransportInternal->transHandle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + /* + cleanup + */ + TPM_TransportPublic_Delete(&transPublic); /* @1 */ + TPM_SizedBuffer_Delete(&secret); /* @2 */ + TPM_TransportAuth_Delete(&k1TransportAuth); /* @4 */ + TPM_TransportLogIn_Delete(&l1TransportLogIn); /* @5 */ + TPM_TransportLogOut_Delete(&l2TransportLogOut); /* @6 */ + TPM_Sbuffer_Delete(&transPublicSbuffer); /* @7 */ + TPM_Sbuffer_Delete(¤tTicksSbuffer); /* @8 */ + return rcf; +} + +/* 24.2 TPM_ExecuteTransport rev 117 + + Delivers a wrapped TPM command to the TPM where the TPM unwraps the command and then executes the + command. + + TPM_ExecuteTransport uses the same rolling nonce paradigm as other authorized TPM commands. The + even nonces start in EstablishTransport and change on each invocation of TPM_ExecuteTransport. + + The only restriction on what can happen inside of a transport session is that there is no + "nesting" of sessions. It is permissible to perform operations that delete internal state and + make the TPM inoperable. + + Because, in general, key handles are not logged, a digest of the corresponding public key is + logged. In cases where the key handle is logged (e.g. TPM_OwnerReadInternalPub), the + public key is also logged. + + The wrapped command is audited twice - once according to the actions of TPM_ExecuteTransport and + once within the wrapped command itself according to the special rules for auditing a command + wrapped in an encrypted transport session. +*/ + +TPM_RESULT TPM_Process_ExecuteTransport(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_SIZED_BUFFER wrappedCmd; /* The wrapped command */ + TPM_TRANSHANDLE transHandle; /* The transport session handle */ + TPM_NONCE transNonceOdd; /* Nonce generated by caller */ + TPM_BOOL continueTransSession; /* The continue use flag for the authorization + session handle */ + TPM_AUTHDATA transAuth; /* HMAC for transHandle key: transHandle -> + authData */ + + /* processing parameters */ + /* unsigned char * inParamStart; /\* starting point of inParam's *\/ */ + /* unsigned char * inParamEnd; /\* ending point of inParam's *\/ */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transHandleValid = FALSE; + TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal; + TPM_TRANSPORT_INTERNAL t1TransportCopy; /* because original might be invalidated */ + TPM_BOOL transportWrappable; /* inner command can be wrapped in + transport */ + uint32_t keyHandles; /* number of key handles in ordw */ + uint32_t keyHandle1Index; /* index of key handles in wrapped command */ + uint32_t keyHandle2Index; + TPM_KEY_HANDLE keyHandle1; /* key handles in wrapped command */ + TPM_KEY_HANDLE keyHandle2; + uint32_t blockSize; /* symmetric key block size, if needed */ + TPM_RESOURCE_TYPE wrappedResourceType; /* for key handle special cases */ + TPM_COMMAND_CODE ordw; /* wrapped ORDW */ + uint32_t e1Dataw; /* index into wrapped E1 */ + uint32_t len1; /* wrapped LEN1 */ + unsigned char *g1Mgf1; /* input MGF1 XOR string */ + unsigned char *g2Mgf1; /* output MGF1 XOR string */ + unsigned char *decryptCmd; /* decrypted wrapped command */ + unsigned char *cmdStream; /* temporary for constructing decryptCmd */ + uint32_t cmdStreamSize; + TPM_COMMAND_CODE nOrdw; /* ordinal in nbo */ + TPM_COMMAND_CODE nOrdet; /* ordinal in nbo */ + uint32_t nWrappedCmdSize; /* wrappedCmdSize in nbo */ + TPM_DIGEST h1InWrappedDigest; + TPM_DIGEST h2OutWrappedDigest; + TPM_TRANSPORT_LOG_IN l2TransportLogIn; + TPM_TRANSPORT_LOG_OUT l3TransportLogOut; + TPM_DIGEST k2PubkeyDigest; + TPM_DIGEST k3PubkeyDigest; + TPM_KEY *k2Key; /* wrapped command keys */ + TPM_KEY *k3Key; + TPM_BOOL parentPCRStatus; + TPM_STORE_BUFFER wrappedRspSbuffer; + const unsigned char *wrappedRspStream; + uint32_t wrappedRspStreamSize; + uint32_t s2Dataw; /* index into S2 */ + uint32_t len2; /* length of S2 */ + TPM_RESULT rcw; /* wrapped return code */ + TPM_RESULT nRcw; /* return code in nbo */ + TPM_STORE_BUFFER currentTicksSbuffer; + const unsigned char *currentTicksBuffer; /* serialized buffer */ + uint32_t currentTicksLength; /* serialization length */ + TPM_RESULT nRCet; /* return code in nbo */ + TPM_MODIFIER_INDICATOR nLocality; /* locality in nbo */ + uint32_t nWrappedRspStreamSize; /* wrappedRspStreamSize in nbo */ + unsigned char *encryptRsp; /* encrypted response */ + + /* output parameters */ + TPM_DIGEST outParamDigest; + TPM_UINT64 currentTicks; /* The current ticks when the command was + executed */ + TPM_SIZED_BUFFER wrappedRsp; /* The wrapped response */ + + printf("TPM_Process_ExecuteTransport: Ordinal Entry\n"); + transportInternal = transportInternal; /* TPM_ExecuteTransport cannot be wrapped */ + TPM_SizedBuffer_Init(&wrappedCmd); /* freed @1 */ + TPM_SizedBuffer_Init(&wrappedRsp); /* freed @2 */ + g1Mgf1 = NULL; /* freed @3 */ + decryptCmd = NULL; /* freed @4 */ + TPM_TransportLogIn_Init(&l2TransportLogIn); /* freed @5 */ + TPM_TransportLogOut_Init(&l3TransportLogOut); /* freed @6 */ + TPM_Sbuffer_Init(&wrappedRspSbuffer); /* freed @7 */ + TPM_Sbuffer_Init(¤tTicksSbuffer); /* freed @8 */ + g2Mgf1 = NULL; /* freed @9 */ + TPM_TransportInternal_Init(&t1TransportCopy); /* freed @10 */ + encryptRsp = NULL; /* freed @11 */ + /* + get inputs + */ + if (returnCode == TPM_SUCCESS) { + /* save the starting point of inParam's for authorization and auditing */ + /* inParamStart = command; */ + /* get wrappedCmd */ + returnCode = TPM_SizedBuffer_Load(&wrappedCmd, &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: wrapped command size %u\n", wrappedCmd.size); + /* save the ending point of inParam's for authorization and auditing */ + /* inParamEnd = command; */ + /* NOTE: The common TPM_GetInParamDigest() is not called here, since inParamDigest cannot be + calculated until the wrapped command is decrypted */ + returnCode = TPM_OrdinalAuditStatus_GetAuditStatus(&auditStatus, + ordinal, + &(tpm_state->tpm_permanent_data)); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag1(tag); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&transHandle, + &transHandleValid, + transNonceOdd, + &continueTransSession, + transAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: transHandle %08x\n", transHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ExecuteTransport: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + transHandleValid = FALSE; + } + /* + Processing + */ + /* if there is an active exclusive transport session and it's not this session, terminate it */ + if (returnCode == TPM_SUCCESS) { + if ((tpm_state->tpm_stany_flags.transportExclusive != 0) && + (tpm_state->tpm_stany_flags.transportExclusive != transHandle)) { + returnCode = TPM_TransportSessions_TerminateHandle + (tpm_state->tpm_stclear_data.transSessions, + tpm_state->tpm_stany_flags.transportExclusive, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + } + /* 1. Using transHandle locate the TPM_TRANSPORT_INTERNAL structure T1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportSessions_GetEntry(&t1TpmTransportInternal, + tpm_state->tpm_stclear_data.transSessions, + transHandle); + } + /* For the corner case where the wrapped command invalidates the transport session, make a copy + for the response. */ + if (returnCode == TPM_SUCCESS) { + TPM_TransportInternal_Copy(&t1TransportCopy, + t1TpmTransportInternal); + } + /* 2. Parse wrappedCmd */ + /* a. Set TAGw, LENw, and ORDw to the parameters from wrappedCmd */ + /* b. Set E1 to DATAw */ + /* i. This pointer is ordinal dependent and requires the execute transport command to parse + wrappedCmd */ + /* c. Set LEN1 to the length of DATAw */ + /* i. DATAw always ends at the start of AUTH1w if AUTH1w is present */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_OrdinalTable_ParseWrappedCmd(&e1Dataw, /* index into wrappedCmd */ + &len1, + &keyHandles, + &keyHandle1Index, /* index into key handles */ + &keyHandle2Index, + &ordw, + &transportWrappable, + &wrappedCmd); + if (returnCode != TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Error parsing wrapped command\n"); + } + } + /* 3. If LEN1 is less than 0, or if ORDw is unknown, unimplemented, or cannot be determined + a. Return TPM_BAD_PARAMETER */ + if (returnCode == TPM_SUCCESS) { + if (wrappedCmd.size < e1Dataw + len1) { + printf("TPM_Process_ExecuteTransport: Error (fatal), wrappedCmdSize %u e1 %u len1 %u\n", + wrappedCmd.size, e1Dataw, len1); + returnCode = TPM_FAIL; /* internal error, should never occur */ + } + } + /* allocate memory for the decrypted command, which is always the same length as the encrypted + command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&decryptCmd, wrappedCmd.size); + } + /* 4. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT set then */ + if ((returnCode == TPM_SUCCESS) && + (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) && + (len1 != 0)) { /* some commands have no DATAw area to encrypt */ + /* a. If T1 -> transPublic -> algId is TPM_ALG_MGF1 */ + if (t1TransportCopy.transPublic.algId == TPM_ALG_MGF1) { + printf("TPM_Process_ExecuteTransport: Wrapped command MGF1 encrypted\n"); + /* i. Using the MGF1 function, create string G1 of length LEN1. The inputs to the MGF1 + are transLastNonceEven, transNonceOdd, "in", and T1 -> authData. These four values + concatenated together form the Z value that is the seed for the MGF1. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_MGF1_GenerateArray(&g1Mgf1, /* G1 MGF1 array */ + len1, /* G1 length */ + + TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("in") - 1 + + TPM_AUTHDATA_SIZE, /* seed length */ + + TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, + TPM_NONCE_SIZE, transNonceOdd, + sizeof("in") - 1, "in", + TPM_AUTHDATA_SIZE, t1TransportCopy.authData, + 0, NULL); + } + /* ii. Create C1 by performing an XOR of G1 and wrappedCmd starting at E1. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Transport_CryptMgf1(decryptCmd, /* output */ + wrappedCmd.buffer, /* input */ + g1Mgf1, /* XOR pad */ + wrappedCmd.size, /* total size of buffers */ + e1Dataw, /* start of encrypted part */ + len1); /* length of encrypted part */ + } + } + /* b. If the encryption algorithm requires an IV or CTR calculate the IV or CTR value */ + else { + printf("TPM_Process_ExecuteTransport: " + "Wrapped command algId %08x encScheme %04hx encrypted\n", + t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme); + /* This function call should not fail, as the parameters were checked at + TPM_EstablishTransport. The call is used here to get the block size. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_TransportPublic_CheckEncScheme(&blockSize, + t1TransportCopy.transPublic.algId, + t1TransportCopy.transPublic.encScheme, + tpm_state->tpm_permanent_flags.FIPS); + } + /* i. Using the MGF1 function, create string IV1 or CTR1 with a length set by the block + size of the encryption algorithm. The inputs to the MGF1 are transLastNonceEven, + transNonceOdd, and "in". These three values concatenated together form the Z value + that is the seed for the MGF1. Note that any terminating characters within the string + "in" are ignored, so a total of 42 bytes are hashed. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_MGF1_GenerateArray(&g1Mgf1, /* G1 MGF1 array */ + blockSize, /* G1 length */ + + TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("in") - 1, + /* seed length */ + + TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, + TPM_NONCE_SIZE, transNonceOdd, + sizeof("in") - 1, "in", + 0, NULL); + } + /* ii. The symmetric key is taken from the first bytes of T1 -> authData. */ + /* iii. Decrypt DATAw and replace the DATAw area of E1 creating C1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Transport_CryptSymmetric(decryptCmd, /* output */ + wrappedCmd.buffer, /* input */ + t1TransportCopy.transPublic.algId, + t1TransportCopy.transPublic.encScheme, + t1TransportCopy.authData, /* key */ + TPM_AUTHDATA_SIZE, /* key size */ + g1Mgf1, /* pad, IV or CTR */ + blockSize, + wrappedCmd.size, /* total size of buffers */ + e1Dataw, /* start of encrypted part */ + len1); /* length of encrypted part */ + } + } + /* 4.c. TPM_OSAP, TPM_OIAP have no parameters encrypted */ + /* NOTE Handled by len1 = 0 */ + /* 4.d. TPM_DSAP has special rules for parameter encryption */ + /* NOTE Handled by setting inputHandleSize to all but entityValue */ + } + /* 5. Else (no encryption) */ + else if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Wrapped command not encrypted\n"); + /* a. Set C1 to the DATAw area E1 of wrappedCmd */ + memcpy(decryptCmd, wrappedCmd.buffer, wrappedCmd.size); + } + + /* Now that the wrapped command is decrypted, handle the special cases (e.g., TPM_FlushSpecific + and TPM_SaveContext) where the handle may or may not be a key handle, dependent on the value + of resourceType */ + if ((returnCode == TPM_SUCCESS) && (keyHandles == 0xffffffff)) { + printf("TPM_Process_ExecuteTransport: key handles special case\n"); + + /* point to the resourceType in the decrypted stream, directly after the key handle */ + cmdStream = decryptCmd + keyHandle1Index + sizeof(TPM_KEY_HANDLE); + cmdStreamSize = wrappedCmd.size - keyHandle1Index - sizeof(TPM_KEY_HANDLE); + returnCode = TPM_Load32(&wrappedResourceType, &cmdStream , &cmdStreamSize ); + } + /* ii. If the resourceType is TPM_RT_KEY, then the public key MUST be logged */ + if ((returnCode == TPM_SUCCESS) && (keyHandles == 0xffffffff)) { + printf("TPM_Process_ExecuteTransport: special case resource type %08x\n", + wrappedResourceType); + if (wrappedResourceType == TPM_RT_KEY) { + printf("TPM_Process_ExecuteTransport: Special case, 1 key handle\n"); + keyHandles = 1; + } + else { + keyHandles = 0; + } + } + + /* 6. Create H1 the SHA-1 of (ORDw || C1). */ + /* a. C1 MUST point at the decrypted DATAw area of E1 */ + /* b. The TPM MAY use this calculation for both execute transport authorization, authorization + of the wrapped command and transport log creation */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_ExecuteTransport: DATAw decrypted", decryptCmd); + printf("TPM_Process_ExecuteTransport: Create H1\n"); + nOrdw = htonl(ordw); + returnCode = TPM_SHA1(h1InWrappedDigest, + sizeof(TPM_COMMAND_CODE), &nOrdw, + len1, decryptCmd + e1Dataw, + 0, NULL); + } + /* 7. Validate the incoming transport session authorization */ + /* a. Set inParamDigest to SHA-1 (ORDet || wrappedCmdSize || H1) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Validate AUTHet\n"); + nOrdet = htonl(ordinal); + nWrappedCmdSize = htonl(wrappedCmd.size); + returnCode = TPM_SHA1(inParamDigest, + sizeof(TPM_COMMAND_CODE), &nOrdet, + sizeof(uint32_t), &nWrappedCmdSize, + TPM_DIGEST_SIZE, h1InWrappedDigest, + 0, NULL); + } + /* b. Calculate the HMAC of (inParamDigest || transLastNonceEven || transNonceOdd || + continueTransSession) using T1 -> authData as the HMAC key */ + /* c. Validate transAuth, on errors return TPM_AUTHFAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_TransportInternal_Check(inParamDigest, + &t1TransportCopy, /* transport session */ + transNonceOdd, /* Nonce generated by system + associated with authHandle */ + continueTransSession, + transAuth); /* Authorization digest for input */ + } + /* 8. If TPM_ExecuteTransport requires auditing */ + /* a. Create TPM_AUDIT_EVENT_IN using H1 */ + /* NOTE: Done during response */ + /* 9. If ORDw is from the list of following commands return TPM_NO_WRAP_TRANSPORT */ + /* a. TPM_EstablishTransport */ + /* b. TPM_ExecuteTransport */ + /* c. TPM_ReleaseTransportSigned */ + if (returnCode == TPM_SUCCESS) { + if (!transportWrappable) { + printf("TPM_Process_ExecuteTransport: Error, ordinal %08x cannot be wrapped\n", + ordw); + returnCode = TPM_NO_WRAP_TRANSPORT; + } + } + /* 10. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */ + if ((returnCode == TPM_SUCCESS) && + (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_LOG)) { + printf("TPM_Process_ExecuteTransport: Create transport log\n"); + /* a. Create L2 a TPM_TRANSPORT_LOG_IN structure */ + /* NOTE Done by TPM_TransportLogIn_Init() */ + /* b. Set L2 -> parameters to H1 */ + TPM_Digest_Copy(l2TransportLogIn.parameters, h1InWrappedDigest); + /* c. If ORDw is a command with no key handles */ + /* i. Set L2 -> pubKeyHash to NULL */ + /* NOTE Done by TPM_TransportLogIn_Init() */ + if ((returnCode == TPM_SUCCESS) && ((keyHandles == 1) || (keyHandles == 2))) { + if (returnCode == TPM_SUCCESS) { + /* point to the first key handle in the decrypted stream */ + cmdStream = decryptCmd + keyHandle1Index; + cmdStreamSize = wrappedCmd.size - keyHandle1Index; + /* get the key handle */ + returnCode = TPM_Load32(&keyHandle1, &cmdStream, &cmdStreamSize); + } + /* get the first key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Create pubKeyHash for key 1 handle %08x\n", + keyHandle1); + returnCode = TPM_KeyHandleEntries_GetKey(&k2Key, + &parentPCRStatus, + tpm_state, + keyHandle1, + TRUE, /* read-only */ + FALSE, /* do not ignore PCRs */ + TRUE); /* can use EK */ + } + /* 10.d. If ORDw is a command with one key handle */ + /* 10.i. Create K2 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by + the key handle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_SHA1_GenerateStructure(k2PubkeyDigest, + &(k2Key->pubKey), + (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store); + } + } + if ((returnCode == TPM_SUCCESS) && (keyHandles == 1)) { + printf("TPM_Process_ExecuteTransport: Digesting one public key\n"); + /* 10.ii. Set L2 -> pubKeyHash to SHA-1 (K2) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(l2TransportLogIn.pubKeyHash, + TPM_DIGEST_SIZE, k2PubkeyDigest, + 0, NULL); + } + } + /* 10.e. If ORDw is a command with two key handles */ + if ((returnCode == TPM_SUCCESS) && (keyHandles == 2)) { + printf("TPM_Process_ExecuteTransport: Digesting two public keys\n"); + /* i. Create K2 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by the + first key handle. */ + /* NOTE Done above for 1 or 2 key case */ + if (returnCode == TPM_SUCCESS) { + /* point to the second key handle in the decrypted stream */ + cmdStream = decryptCmd + keyHandle2Index; + cmdStreamSize = wrappedCmd.size - keyHandle2Index; + /* get the key handle */ + returnCode = TPM_Load32(&keyHandle2, &cmdStream, &cmdStreamSize); + } + /* get the second key */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Create pubKeyHash for key 2 handle %08x\n", + keyHandle2); + returnCode = TPM_KeyHandleEntries_GetKey(&k3Key, + &parentPCRStatus, + tpm_state, + keyHandle2, + TRUE, /* read-only */ + FALSE, /* do not ignore PCRs */ + TRUE); /* can use EK */ + } + /* ii. Create K3 the hash of the TPM_STORE_PUBKEY structure of the key pointed to by the + second key handle. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_SHA1_GenerateStructure(k3PubkeyDigest, + &(k3Key->pubKey), + (TPM_STORE_FUNCTION_T)TPM_SizedBuffer_Store); + } + /* 10.iii. Set L2 -> pubKeyHash to SHA-1 (K2 || K3) */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1(l2TransportLogIn.pubKeyHash, + TPM_DIGEST_SIZE, k2PubkeyDigest, + TPM_DIGEST_SIZE, k3PubkeyDigest, + 0, NULL); + } + } + /* 10.f. Set T1 -> transDigest to the SHA-1 (T1 -> transDigest || L2) */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Extend transDigest with input\n"); + returnCode = TPM_TransportLogIn_Extend(t1TransportCopy.transDigest, + &l2TransportLogIn); + } + /* 10.g. If ORDw is a command with key handles, and the key is not loaded, return + TPM_INVALID_KEYHANDLE. */ + /* NOTE Done by TPM_KeyHandleEntries_GetKey() */ + } + /* 11. Send the wrapped command to the normal TPM command parser, the output is C2 and the + return code is RCw */ + /* a. If ORDw is a command that is audited then the TPM MUST perform the input and output audit + of the command as part of this action */ + /* b. The TPM MAY use H1 as the data value in the authorization and audit calculations during + the execution of C1 */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Call wrapped command\n"); + returnCode = TPM_Process_Wrapped(&wrappedRspSbuffer, /* response buffer */ + decryptCmd, /* complete command array */ + wrappedCmd.size, /* actual bytes in command */ + tpm_state, + &t1TransportCopy); /* TPM_ExecuteTransport */ + printf("TPM_Process_ExecuteTransport: Completed wrapped command\n"); + } + /* 12. Set CT1 to TPM_STANY_DATA -> currentTicks -> currentTicks and return CT1 in the + currentTicks output parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CurrentTicks_Update(&(tpm_state->tpm_stany_data.currentTicks)); + } + if (returnCode == TPM_SUCCESS) { + TPM_Uint64_Copy(¤tTicks, &(tpm_state->tpm_stany_data.currentTicks.currentTicks)); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Uint64_Store(¤tTicksSbuffer, + &(tpm_state->tpm_stany_data.currentTicks.currentTicks)); + } + /* 13. Calculate S2 the pointer to the DATAw area of C2 */ + /* a. Calculate LEN2 the length of S2 according to the same rules that calculated LEN1 */ + if (returnCode == TPM_SUCCESS) { + /* get the response buffer and length */ + TPM_Sbuffer_Get(&wrappedRspSbuffer, &wrappedRspStream, &wrappedRspStreamSize); + /* parse the three standard input parameters, check paramSize against wrappedRsp->size */ + returnCode = TPM_OrdinalTable_ParseWrappedRsp(&s2Dataw, + &len2, + &rcw, + ordw, + wrappedRspStream, + wrappedRspStreamSize); + } + /* 14. Create H2 the SHA-1 of (RCw || ORDw || S2) */ + /* a. The TPM MAY use this calculation for execute transport authorization and transport log out + creation */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Create H2\n"); + nRcw = htonl(rcw); + /* The TPM_ExecuteTransport input ordinal and output ordinal, currentTicks and locality are + not audited. This was simply an error, and not a deliberate attempt to make + TPM_ExecuteTransport different from other ordinals. */ + returnCode = TPM_SHA1(h2OutWrappedDigest, + sizeof(TPM_RESULT), &nRcw, + sizeof(TPM_COMMAND_CODE), &nOrdw, + len2, wrappedRspStream + s2Dataw, + 0, NULL); + } + /* 15. Calculate the outgoing transport session authorization */ + /* a. Create the new transNonceEven for the output of the command */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Nonce_Generate(t1TransportCopy.transNonceEven); + } + /* b. Set outParamDigest to SHA-1 (RCet || ORDet || TPM_STANY_DATA -> currentTicks -> + currentTicks || locality || wrappedRspSize || H2) */ + if (returnCode == TPM_SUCCESS) { + nRCet = htonl(returnCode); + TPM_Sbuffer_Get(¤tTicksSbuffer, ¤tTicksBuffer, ¤tTicksLength); + nLocality = htonl(tpm_state->tpm_stany_flags.localityModifier); + nWrappedRspStreamSize = htonl(wrappedRspStreamSize); + returnCode = TPM_SHA1(outParamDigest, + sizeof(TPM_RESULT), &nRCet, + sizeof(TPM_COMMAND_CODE), &nOrdet, + currentTicksLength, currentTicksBuffer, + sizeof(TPM_MODIFIER_INDICATOR), &nLocality, + sizeof(uint32_t), &nWrappedRspStreamSize, + TPM_DIGEST_SIZE, h2OutWrappedDigest, + 0, NULL); + } + /* c. Calculate transAuth, the HMAC of (outParamDigest || transNonceEven || transNonceOdd || + continueTransSession) using T1 -> authData as the HMAC key */ + /* NOTE: Done as part of response */ + /* 16. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_LOG set then */ + if ((returnCode == TPM_SUCCESS) && + (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_LOG)) { + /* a. Create L3 a TPM_TRANSPORT_LOG_OUT structure */ + /* NOTE Done by TPM_TransportLogOut_Init() */ + /* b. Set L3 -> parameters to H2 */ + TPM_Digest_Copy(l3TransportLogOut.parameters, h2OutWrappedDigest); + /* c. Set L3 -> currentTicks to TPM_STANY_DATA -> currentTicks */ + TPM_CurrentTicks_Copy(&(l3TransportLogOut.currentTicks), + &(tpm_state->tpm_stany_data.currentTicks)); + /* d. Set L3 -> locality to TPM_STANY_DATA -> localityModifier */ + l3TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier; + /* e. Set T1 -> transDigest to the SHA-1 (T1 -> transDigest || L3) */ + printf("TPM_Process_ExecuteTransport: Extend transDigest with output\n"); + returnCode = TPM_TransportLogOut_Extend(t1TransportCopy.transDigest, + &l3TransportLogOut); + } + /* allocate memory for the encrypted response, which is always the same length as the decrypted + response */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Malloc(&encryptRsp, wrappedRspStreamSize); + } + /* 17. If T1 -> transPublic -> transAttributes has TPM_TRANSPORT_ENCRYPT set then */ + if ((returnCode == TPM_SUCCESS) && + (t1TransportCopy.transPublic.transAttributes & TPM_TRANSPORT_ENCRYPT) && + (len2 != 0)) { /* some commands have no DATAw area to encrypt */ + /* NOTE No TPM_OSAP encryption handled by len2 = 0 */ + /* a. If T1 -> transPublic -> algId is TPM_ALG_MGF1 */ + if (t1TransportCopy.transPublic.algId == TPM_ALG_MGF1) { + printf("TPM_Process_ExecuteTransport: Wrapped response MGF1 encrypted\n"); + /* i. Using the MGF1 function, create string G2 of length LEN2. The inputs to the MGF1 + are transNonceEven, transNonceOdd, "out", and T1 -> authData. These four values + concatenated together form the Z value that is the seed for the MGF1. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_MGF1_GenerateArray(&g2Mgf1, /* G2 MGF1 array */ + len2, /* G2 length */ + + TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("out") - 1 + + TPM_AUTHDATA_SIZE, /* seed length */ + + TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, + TPM_NONCE_SIZE, transNonceOdd, + sizeof("out") - 1, "out", + TPM_AUTHDATA_SIZE, t1TransportCopy.authData, + 0, NULL); + } + /* ii. Create E2 by performing an XOR of G2 and C2 starting at S2. */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Transport_CryptMgf1(encryptRsp, + wrappedRspStream, + g2Mgf1, + wrappedRspStreamSize, + s2Dataw, + len2); + } + } + /* b. Else */ + else { + printf("TPM_Process_ExecuteTransport: " + "Wrapped response algId %08x encScheme %04hx encrypted\n", + t1TransportCopy.transPublic.algId, t1TransportCopy.transPublic.encScheme); + /* This function call should not fail, as the parameters were checked at + TPM_EstablishTransport. The call is used here to get the block size. + + This is a duplicate of the call for the command. However, there are cases where + there is no encrypted command (len1 == 0) so the call was not made. Rather than + keep track of whether blockSize is valid, it's clearer to just call the function + twice in some cases. + */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_TransportPublic_CheckEncScheme(&blockSize, + t1TransportCopy.transPublic.algId, + t1TransportCopy.transPublic.encScheme, + tpm_state->tpm_permanent_flags.FIPS); + } + /* i. Create IV2 or CTR2 using the same algorithm as IV1 or CTR1 with the input values + transNonceEven, transNonceOdd, and "out". Note that any terminating characters within + the string "out" are ignored, so a total of 43 bytes are hashed. */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_MGF1_GenerateArray(&g2Mgf1, /* G2 MGF1 array */ + blockSize, /* G2 length */ + + TPM_NONCE_SIZE + TPM_NONCE_SIZE + sizeof("out") - 1, + /* seed length */ + + TPM_NONCE_SIZE, t1TransportCopy.transNonceEven, + TPM_NONCE_SIZE, transNonceOdd, + sizeof("out") - 1, "out", + 0, NULL); + } + /* ii. The symmetric key is taken from the first bytes of T1 -> authData */ + /* iii. Create E2 by encrypting C2 starting at S2 */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_Transport_CryptSymmetric(encryptRsp, /* output */ + wrappedRspStream, /* input */ + t1TransportCopy.transPublic.algId, + t1TransportCopy.transPublic.encScheme, + t1TransportCopy.authData, /* key */ + TPM_AUTHDATA_SIZE, /* key size */ + g2Mgf1, /* pad, IV or CTR */ + blockSize, + wrappedRspStreamSize, /* total size of buffers */ + s2Dataw, /* start of encrypted part */ + len2); /* length of encrypted part */ + } + } + } + /* 18. Else (no encryption) */ + else if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ExecuteTransport: Wrapped response not encrypted\n"); + /* a. Set E2 to the DATAw area S2 of wrappedRsp */ + memcpy(encryptRsp, wrappedRspStream ,wrappedRspStreamSize); + } + /* 19. If continueTransSession is FALSE */ + /* a. Invalidate all session data related to transHandle */ + /* NOTE: Done after response */ + /* 20. If TPM_ExecuteTranport requires auditing */ + /* a. Create TPM_AUDIT_EVENT_OUT using H2 */ + /* NOTE: Done during response */ + /* 21. Return C2 but with S2 replaced by E2 in the wrappedRsp parameter */ + if (returnCode == TPM_SUCCESS) { + /* if the wrapped command invalidated the transport session, set continueTransSession to + FALSE */ + if (!(t1TpmTransportInternal->valid)) { + continueTransSession = FALSE; + } + /* if the session is still valid, copy the copy back to the original so the log gets + updated */ + else { + TPM_TransportInternal_Copy(t1TpmTransportInternal, &t1TransportCopy); + } + } + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ExecuteTransport: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + /* return currentTicks */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, currentTicksBuffer, currentTicksLength); + } + /* return locality */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, + tpm_state->tpm_stany_flags.localityModifier); + } + /* return wrappedRspSize */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append32(response, wrappedRspStreamSize); + } + /* return wrappedRsp */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Sbuffer_Append(response, encryptRsp, wrappedRspStreamSize); + } + /* non-standard - digest the above the line output parameters, H1 used */ + /* non-standard - calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportInternal_Set(response, + &t1TransportCopy, + outParamDigest, + transNonceOdd, + continueTransSession, + FALSE); /* transNonceEven already generated */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + FALSE, /* transportEncrypt */ + h1InWrappedDigest, + h2OutWrappedDigest, /* exception to normal digest */ + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueTransSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueTransSession) && + transHandleValid) { + TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, + transHandle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&wrappedCmd); /* @1 */ + TPM_SizedBuffer_Delete(&wrappedRsp); /* @2 */ + free(g1Mgf1); /* @3 */ + free (decryptCmd); /* @4 */ + TPM_TransportLogIn_Delete(&l2TransportLogIn); /* @5 */ + TPM_TransportLogOut_Delete(&l3TransportLogOut); /* @6 */ + TPM_Sbuffer_Delete(&wrappedRspSbuffer); /* @7 */ + TPM_Sbuffer_Delete(¤tTicksSbuffer); /* @8 */ + free(g2Mgf1); /* @9 */ + TPM_TransportInternal_Delete(&t1TransportCopy); /* @10 */ + free(encryptRsp); /* @11 */ + return rcf; +} + +/* 24.3 TPM_ReleaseTransportSigned rev 101 + + This command completes the transport session. If logging for this session is turned on, then this + command returns a hash of all operations performed during the session along with a digital + signature of the hash. + + This command serves no purpose if logging is turned off, and results in an error if attempted. + + This command uses two authorization sessions, the key that will sign the log and the + authorization from the session. Having the session authorization proves that the requester that + is signing the log is the owner of the session. If this restriction is not put in then an + attacker can close the log and sign using their own key. + + The hash of the session log includes the information associated with the input phase of execution + of the TPM_ReleaseTransportSigned command. It cannot include the output phase information. +*/ + +TPM_RESULT TPM_Process_ReleaseTransportSigned(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal) +{ + TPM_RESULT rcf = 0; /* fatal error precluding response */ + TPM_RESULT returnCode = TPM_SUCCESS; /* command return code */ + + /* input parameters */ + TPM_KEY_HANDLE keyHandle; /* Handle of a loaded key that will perform the signing */ + TPM_NONCE antiReplay; /* Value provided by caller for anti-replay protection */ + TPM_AUTHHANDLE authHandle; /* The authorization session to use key */ + TPM_NONCE authNonceOdd; /* Nonce generated by system associated with authHandle */ + TPM_BOOL continueAuthSession; /* The continue use flag for the authorization session + handle */ + TPM_AUTHDATA keyAuth; /* The authorization session digest that authorizes the use + of key. HMAC key: key -> usageAuth */ + TPM_TRANSHANDLE transHandle; /* The transport session handle */ + TPM_NONCE transNonceOdd; /* Nonce supplied by caller for transport session */ + TPM_BOOL continueTransSession = TRUE; /* The continue use flag for the + authorization session handle */ + TPM_AUTHDATA transAuth; /* HMAC for transport session key: tranHandle -> authData */ + + /* processing parameters */ + unsigned char * inParamStart; /* starting point of inParam's */ + unsigned char * inParamEnd; /* ending point of inParam's */ + TPM_DIGEST inParamDigest; + TPM_BOOL auditStatus; /* audit the ordinal */ + TPM_BOOL transportEncrypt; /* wrapped in encrypted transport session */ + TPM_BOOL authHandleValid = FALSE; + TPM_BOOL transHandleValid = FALSE; + TPM_AUTH_SESSION_DATA *auth_session_data = NULL; /* session data for authHandle */ + TPM_TRANSPORT_INTERNAL *t1TpmTransportInternal; + TPM_SECRET *hmacKey; + TPM_KEY *sigKey = NULL; /* the key specified by keyHandle */ + TPM_BOOL parentPCRStatus; + TPM_SECRET *keyUsageAuth; + TPM_TRANSPORT_LOG_OUT a1TransportLogOut; + TPM_SIGN_INFO h1SignInfo; + TPM_DIGEST h1Digest; /* digest of h1SignInfo */ + + /* output parameters */ + uint32_t outParamStart; /* starting point of outParam's */ + uint32_t outParamEnd; /* ending point of outParam's */ + TPM_DIGEST outParamDigest; + TPM_CURRENT_TICKS *currentTicks = NULL; /* The current time according to the TPM */ + TPM_SIZED_BUFFER signature; /* The signature of the digest */ + + printf("TPM_Process_ReleaseTransportSigned: Ordinal Entry\n"); + TPM_SizedBuffer_Init(&signature); /* freed @1 */ + TPM_TransportLogOut_Init(&a1TransportLogOut); /* freed @2 */ + TPM_SignInfo_Init(&h1SignInfo); /* freed @3 */ + /* + get inputs + + */ + /* get keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_Load32(&keyHandle, &command, ¶mSize); + } + /* save the starting point of inParam's for authorization and auditing */ + inParamStart = command; + /* get antiReplay */ + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReleaseTransportSigned: keyHandle %08x\n", keyHandle ); + returnCode = TPM_Nonce_Load(antiReplay, &command, ¶mSize); + } + /* save the ending point of inParam's for authorization and auditing */ + inParamEnd = command; + /* digest the input parameters */ + if (returnCode == TPM_SUCCESS) { + TPM_PrintFour("TPM_Process_ReleaseTransportSigned: antiReplay", antiReplay); + returnCode = TPM_GetInParamDigest(inParamDigest, /* output */ + &auditStatus, /* output */ + &transportEncrypt, /* output */ + tpm_state, + tag, + ordinal, + inParamStart, + inParamEnd, + transportInternal); + } + /* check state */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckState(tpm_state, tag, TPM_CHECK_ALL); + } + /* check tag */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CheckRequestTag21(tag); + } + + /* get the optional 'below the line' authorization parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Get(&authHandle, + &authHandleValid, + authNonceOdd, + &continueAuthSession, + keyAuth, + &command, ¶mSize); + printf("TPM_Process_ReleaseTransportSigned: authHandle %08x\n", authHandle); + } + /* get the 'below the line' authorization parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_AuthParams_Get(&transHandle, + &transHandleValid, + transNonceOdd, + &continueTransSession, + transAuth, + &command, ¶mSize); + } + if (returnCode == TPM_SUCCESS) { + printf("TPM_Process_ReleaseTransportSigned: transHandle %08x\n", transHandle); + } + if (returnCode == TPM_SUCCESS) { + if (paramSize != 0) { + printf("TPM_Process_ReleaseTransportSigned: Error, command has %u extra bytes\n", + paramSize); + returnCode = TPM_BAD_PARAM_SIZE; + } + } + /* do not terminate sessions if the command did not parse correctly */ + if (returnCode != TPM_SUCCESS) { + transHandleValid = FALSE; + } + /* + Processing + */ + /* if there is an active exclusive transport session and it's not this session, terminate it */ + if (returnCode == TPM_SUCCESS) { + if ((tpm_state->tpm_stany_flags.transportExclusive != 0) && + (tpm_state->tpm_stany_flags.transportExclusive != transHandle)) { + returnCode = + TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, + tpm_state->tpm_stany_flags.transportExclusive, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + } + /* 1. Using transHandle locate the TPM_TRANSPORT_INTERNAL structure T1 */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportSessions_GetEntry(&t1TpmTransportInternal, + tpm_state->tpm_stclear_data.transSessions, + transHandle); + } + /* get the key corresponding to the keyHandle parameter */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_KeyHandleEntries_GetKey(&sigKey, &parentPCRStatus, tpm_state, keyHandle, + FALSE, /* not r/o, used to sign */ + FALSE, /* do not ignore PCRs */ + FALSE); /* cannot use EK */ + } + /* 2. Validate that keyHandle -> sigScheme is TPM_SS_RSASSAPKCS1v15_SHA1 or + TPM_SS_RSASSAPKCS1v15_INFO, if not return TPM_INAPPROPRIATE_SIG. */ + if (returnCode == TPM_SUCCESS) { + if ((sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_SHA1) && + (sigKey->algorithmParms.sigScheme != TPM_SS_RSASSAPKCS1v15_INFO)) { + printf("TPM_Process_ReleaseTransportSigned: Error, invalid sigKey sigScheme %04hx\n", + sigKey->algorithmParms.sigScheme); + returnCode = TPM_INAPPROPRIATE_SIG; + } + } + if ((returnCode == TPM_SUCCESS) && (tag != TPM_TAG_RQU_AUTH2_COMMAND)) { + if (sigKey->authDataUsage != TPM_AUTH_NEVER) { + printf("TPM_Process_ReleaseTransportSigned: Error, authorization required\n"); + returnCode = TPM_AUTHFAIL; + } + } + /* get keyHandle -> usageAuth */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Key_GetUsageAuth(&keyUsageAuth, sigKey); + } + /* get the session data */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthSessions_GetData(&auth_session_data, + &hmacKey, + tpm_state, + authHandle, + TPM_PID_NONE, + TPM_ET_KEYHANDLE, + ordinal, + sigKey, + keyUsageAuth, /* OIAP */ + sigKey->tpm_store_asymkey->pubDataDigest); /* OSAP */ + } + /* 3. Validate that keyHandle -> keyUsage is TPM_KEY_SIGNING, if not return + TPM_INVALID_KEYUSAGE */ + if (returnCode == TPM_SUCCESS) { + if (sigKey ->keyUsage != TPM_KEY_SIGNING) { + printf("TPM_Process_ReleaseTransportSigned: Error, keyUsage %04hx is invalid\n", + sigKey ->keyUsage); + returnCode = TPM_INVALID_KEYUSAGE; + } + } + /* 4. Using key -> authData validate the command and parameters, on error return TPM_AUTHFAIL */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_Authdata_Check(tpm_state, + *hmacKey, /* HMAC key */ + inParamDigest, + auth_session_data, /* authorization session */ + authNonceOdd, /* Nonce generated by system + associated with authHandle */ + continueAuthSession, + keyAuth); /* Authorization digest for input */ + } + /* 5. Using transHandle -> authData validate the command and parameters, on error return + TPM_AUTH2FAIL */ + if (returnCode == TPM_SUCCESS) { + returnCode = + TPM_TransportInternal_Check(inParamDigest, + t1TpmTransportInternal, /* transport session */ + transNonceOdd, /* Nonce generated by system + associated with authHandle */ + continueTransSession, + transAuth); /* Authorization digest for input */ + } + /* 7. Else */ + if (returnCode == TPM_SUCCESS) { + if (!(t1TpmTransportInternal->transPublic.transAttributes & TPM_TRANSPORT_LOG)) { + /* a. Return TPM_BAD_MODE */ + printf("TPM_Process_ReleaseTransportSigned: Error, TPM_TRANSPORT_LOG not set\n"); + returnCode = TPM_BAD_MODE; + } + } + /* 6. If T1 -> transAttributes has TPM_TRANSPORT_LOG set then update the current ticks + structure */ + if (returnCode == TPM_SUCCESS) { + currentTicks = &(tpm_state->tpm_stany_data.currentTicks); + /* update the ticks based on the current time */ + returnCode = TPM_CurrentTicks_Update(currentTicks); + } + if (returnCode == TPM_SUCCESS) { + /* a. Create A1 a TPM_TRANSPORT_LOG_OUT structure */ + /* NOTE Done by TPM_TransportLogOut_Init() */ + /* b. Set A1 -> parameters to the SHA-1 (ordinal || antiReplay) */ + TPM_Digest_Copy(a1TransportLogOut.parameters, inParamDigest); + /* c. Set A1 -> currentTicks to TPM_STANY_DATA -> currentTicks */ + TPM_CurrentTicks_Copy(&(a1TransportLogOut.currentTicks), currentTicks); + /* d. Set A1 -> locality to the locality modifier for this command */ + a1TransportLogOut.locality = tpm_state->tpm_stany_flags.localityModifier; + /* e. Set T1 -> transDigest to SHA-1 (T1 -> transDigest || A1) */ + printf("TPM_Process_ReleaseTransportSigned: Extend transDigest with output\n"); + returnCode = TPM_TransportLogOut_Extend(t1TpmTransportInternal->transDigest, + &a1TransportLogOut); + } + if (returnCode == TPM_SUCCESS) { + /* 8. Create H1 a TPM_SIGN_INFO structure and set the structure defaults */ + /* NOTE: Done by TPM_SignInfo_Init() */ + /* a. Set H1 -> fixed to "TRAN" */ + memcpy(h1SignInfo.fixed, "TRAN", TPM_SIGN_INFO_FIXED_SIZE); + /* b. Set H1 -> replay to antiReplay */ + TPM_Nonce_Copy(h1SignInfo.replay, antiReplay); + /* c. Set H1 -> data to T1 -> transDigest */ + returnCode = TPM_SizedBuffer_Set(&(h1SignInfo.data), + TPM_DIGEST_SIZE, + t1TpmTransportInternal->transDigest); + } + /* d. Sign SHA-1 hash of H1 using the key pointed to by keyHandle */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_SHA1_GenerateStructure(h1Digest, &h1SignInfo, + (TPM_STORE_FUNCTION_T)TPM_SignInfo_Store); + TPM_PrintAll("TPM_Process_ReleaseTransportSigned: h1Digest", h1Digest, TPM_DIGEST_SIZE); + } + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_RSASignToSizedBuffer(&signature, /* signature */ + h1Digest, /* message */ + TPM_DIGEST_SIZE, /* message size */ + sigKey); /* input, signing key */ + } + /* 9. Invalidate all session data related to T1 */ + /* NOTE Done after response */ + /* 10. Set continueTransSession to FALSE */ + if (returnCode == TPM_SUCCESS) { + continueTransSession = FALSE; + } + /* 11. Return TPM_SUCCESS */ + /* + response + */ + /* standard response: tag, (dummy) paramSize, returnCode. Failure is fatal. */ + if (rcf == 0) { + printf("TPM_Process_ReleaseTransportSigned: Ordinal returnCode %08x %u\n", + returnCode, returnCode); + rcf = TPM_Sbuffer_StoreInitialResponse(response, tag, returnCode); + } + /* success response, append the rest of the parameters. */ + if (rcf == 0) { + if (returnCode == TPM_SUCCESS) { + /* checkpoint the beginning of the outParam's */ + outParamStart = response->buffer_current - response->buffer; + /* return locality */ + returnCode = TPM_Sbuffer_Append32(response, + tpm_state->tpm_stany_flags.localityModifier); + } + /* return currentTicks */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_CurrentTicks_Store(response, currentTicks); + } + if (returnCode == TPM_SUCCESS) { + /* return signature */ + returnCode = TPM_SizedBuffer_Store(response, &signature); + /* checkpoint the end of the outParam's */ + outParamEnd = response->buffer_current - response->buffer; + } + /* digest the above the line output parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_GetOutParamDigest(outParamDigest, /* output */ + auditStatus, /* input audit status */ + transportEncrypt, + tag, + returnCode, + ordinal, /* command ordinal */ + response->buffer + outParamStart, /* start */ + outParamEnd - outParamStart); /* length */ + } + /* calculate and set the optional below the line parameters */ + if ((returnCode == TPM_SUCCESS) && (tag == TPM_TAG_RQU_AUTH2_COMMAND)) { + returnCode = TPM_AuthParams_Set(response, + *hmacKey, /* owner HMAC key */ + auth_session_data, + outParamDigest, + authNonceOdd, + continueAuthSession); + } + /* calculate and set the below the line parameters */ + if (returnCode == TPM_SUCCESS) { + returnCode = TPM_TransportInternal_Set(response, + t1TpmTransportInternal, + outParamDigest, + transNonceOdd, + continueTransSession, + TRUE); /* generate transNonceEven */ + } + /* audit if required */ + if ((returnCode == TPM_SUCCESS) && auditStatus) { + returnCode = TPM_ProcessAudit(tpm_state, + transportEncrypt, + inParamDigest, + outParamDigest, + ordinal); + } + /* adjust the initial response */ + rcf = TPM_Sbuffer_StoreFinalResponse(response, returnCode, tpm_state); + } + /* if there was an error, or continueTransSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueTransSession) && + transHandleValid) { + TPM_TransportSessions_TerminateHandle(tpm_state->tpm_stclear_data.transSessions, + transHandle, + &(tpm_state->tpm_stany_flags.transportExclusive)); + } + /* if there was an error, or continueAuthSession is FALSE, terminate the session */ + if (((rcf != 0) || + ((returnCode != TPM_SUCCESS) && (returnCode != TPM_DEFEND_LOCK_RUNNING)) || + !continueAuthSession) && + authHandleValid) { + TPM_AuthSessions_TerminateHandle(tpm_state->tpm_stclear_data.authSessions, authHandle); + } + /* + cleanup + */ + TPM_SizedBuffer_Delete(&signature); /* @1 */ + TPM_TransportLogOut_Delete(&a1TransportLogOut); /* @2 */ + TPM_SignInfo_Delete(&h1SignInfo); /* @3 */ + return rcf; +} diff --git a/src/tpm_transport.h b/src/tpm_transport.h new file mode 100644 index 00000000..1bb70f74 --- /dev/null +++ b/src/tpm_transport.h @@ -0,0 +1,211 @@ +/********************************************************************************/ +/* */ +/* Transport */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_transport.h 4526 2011-03-24 21:14:42Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_TRANSPORT_H +#define TPM_TRANSPORT_H + +#include "tpm_global.h" + +/* + Transport Encryption for wrapped commands and responses +*/ + +TPM_RESULT TPM_Transport_CryptMgf1(unsigned char *dest, + const unsigned char *src, + const unsigned char *pad, + uint32_t size, + uint32_t index, + uint32_t len); + +TPM_RESULT TPM_Transport_CryptSymmetric(unsigned char *dest, + const unsigned char *src, + TPM_ALGORITHM_ID algId, + TPM_ENC_SCHEME encScheme, + const unsigned char *symmetric_key, + uint32_t symmetric_key_size, + unsigned char *pad_in, + uint32_t pad_in_size, + uint32_t size, + uint32_t index, + uint32_t len); + +/* + Transport Sessions (the entire array) +*/ + +void TPM_TransportSessions_Init(TPM_TRANSPORT_INTERNAL *transSessions); +TPM_RESULT TPM_TransportSessions_Load(TPM_TRANSPORT_INTERNAL *transSessions, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_TransportSessions_Store(TPM_STORE_BUFFER *sbuffer, + TPM_TRANSPORT_INTERNAL *transSessions); +void TPM_TransportSessions_Delete(TPM_TRANSPORT_INTERNAL *transSessions); + +void TPM_TransportSessions_IsSpace(TPM_BOOL *isSpace, uint32_t *index, + TPM_TRANSPORT_INTERNAL *transSessions); +void TPM_TransportSessions_GetSpace(uint32_t *space, + TPM_TRANSPORT_INTERNAL *transSessions); +TPM_RESULT TPM_TransportSessions_StoreHandles(TPM_STORE_BUFFER *sbuffer, + TPM_TRANSPORT_INTERNAL *transSessions); +TPM_RESULT TPM_TransportSessions_GetNewHandle(TPM_TRANSPORT_INTERNAL **tpm_transport_internal, + TPM_TRANSPORT_INTERNAL *transportSessions); +TPM_RESULT TPM_TransportSessions_GetEntry(TPM_TRANSPORT_INTERNAL **tpm_transport_internal , + TPM_TRANSPORT_INTERNAL *transportSessions, + TPM_TRANSHANDLE transportHandle); +TPM_RESULT TPM_TransportSessions_AddEntry(TPM_HANDLE *tpm_handle, + TPM_BOOL keepHandle, + TPM_TRANSPORT_INTERNAL *transSessions, + TPM_TRANSPORT_INTERNAL *tpm_transport_internal); +TPM_RESULT TPM_TransportSessions_TerminateHandle(TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + TPM_TRANSHANDLE transportHandle, + TPM_TRANSHANDLE *transportExclusive); + +/* + TPM_TRANSPORT_PUBLIC +*/ + +void TPM_TransportPublic_Init(TPM_TRANSPORT_PUBLIC *tpm_transport_public); +TPM_RESULT TPM_TransportPublic_Load(TPM_TRANSPORT_PUBLIC *tpm_transport_public, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_TransportPublic_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_PUBLIC *tpm_transport_public); +void TPM_TransportPublic_Delete(TPM_TRANSPORT_PUBLIC *tpm_transport_public); + +TPM_RESULT TPM_TransportPublic_Copy(TPM_TRANSPORT_PUBLIC *dest, + const TPM_TRANSPORT_PUBLIC *src); +void TPM_TransportPublic_CheckAlgId(TPM_BOOL *supported, + TPM_ALGORITHM_ID algId); +TPM_RESULT TPM_TransportPublic_CheckEncScheme(uint32_t *blockSize, + TPM_ALGORITHM_ID algId, + TPM_ENC_SCHEME encScheme, + TPM_BOOL FIPS); + +/* + TPM_TRANSPORT_INTERNAL +*/ + +void TPM_TransportInternal_Init(TPM_TRANSPORT_INTERNAL *tpm_transport_internal); +TPM_RESULT TPM_TransportInternal_Load(TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_TransportInternal_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_INTERNAL *tpm_transport_internal); +void TPM_TransportInternal_Delete(TPM_TRANSPORT_INTERNAL *tpm_transport_internal); + +void TPM_TransportInternal_Copy(TPM_TRANSPORT_INTERNAL *dest_transport_internal, + TPM_TRANSPORT_INTERNAL *src_transport_internal); +TPM_RESULT TPM_TransportInternal_Check(TPM_DIGEST inParamDigest, + TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + TPM_NONCE transNonceOdd, + TPM_BOOL continueTransSession, + TPM_AUTHDATA transAuth); +TPM_RESULT TPM_TransportInternal_Set(TPM_STORE_BUFFER *response, + TPM_TRANSPORT_INTERNAL *tpm_transport_internal, + TPM_DIGEST outParamDigest, + TPM_NONCE transNonceOdd, + TPM_BOOL continueTransSession, + TPM_BOOL generateNonceEven); + +/* + TPM_TRANSPORT_LOG_IN +*/ + +void TPM_TransportLogIn_Init(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in); +TPM_RESULT TPM_TransportLogIn_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_LOG_IN *tpm_transport_log_in); +void TPM_TransportLogIn_Delete(TPM_TRANSPORT_LOG_IN *tpm_transport_log_in); + +TPM_RESULT TPM_TransportLogIn_Extend(TPM_DIGEST tpm_digest, + TPM_TRANSPORT_LOG_IN *tpm_transport_log_in); + +/* + TPM_TRANSPORT_LOG_OUT +*/ + +void TPM_TransportLogOut_Init(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out); +TPM_RESULT TPM_TransportLogOut_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out); +void TPM_TransportLogOut_Delete(TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out); + +TPM_RESULT TPM_TransportLogOut_Extend(TPM_DIGEST tpm_digest, + TPM_TRANSPORT_LOG_OUT *tpm_transport_log_out); + +/* + TPM_TRANSPORT_AUTH +*/ + +void TPM_TransportAuth_Init(TPM_TRANSPORT_AUTH *tpm_transport_auth); +TPM_RESULT TPM_TransportAuth_Load(TPM_TRANSPORT_AUTH *tpm_transport_auth, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_TransportAuth_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_TRANSPORT_AUTH *tpm_transport_auth); +void TPM_TransportAuth_Delete(TPM_TRANSPORT_AUTH *tpm_transport_auth); + +TPM_RESULT TPM_TransportAuth_DecryptSecret(TPM_TRANSPORT_AUTH *tpm_transport_auth, + TPM_SIZED_BUFFER *secret, + TPM_KEY *tpm_key); + +/* Command Processing Functions */ + +TPM_RESULT TPM_Process_EstablishTransport(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ExecuteTransport(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); +TPM_RESULT TPM_Process_ReleaseTransportSigned(tpm_state_t *tpm_state, + TPM_STORE_BUFFER *response, + TPM_TAG tag, + uint32_t paramSize, + TPM_COMMAND_CODE ordinal, + unsigned char *command, + TPM_TRANSPORT_INTERNAL *transportInternal); + + +#endif diff --git a/src/tpm_ver.c b/src/tpm_ver.c new file mode 100644 index 00000000..0152b492 --- /dev/null +++ b/src/tpm_ver.c @@ -0,0 +1,271 @@ +/********************************************************************************/ +/* */ +/* Ver Structure Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_ver.c 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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 "tpm_debug.h" +#include "tpm_error.h" +#include "tpm_structures.h" + +#include "tpm_ver.h" + +/* + TPM_STRUCT_VER + + This indicates the version of the structure. + + Version 1.2 deprecates the use of this structure in all other structures. The structure is not + deprecated as many of the structures that contain this structure are not deprecated. + + The rationale behind keeping this structure and adding the new version structure is that in + version 1.1 this structure was in use for two purposes. The first was to indicate the structure + version, and in that mode the revMajor and revMinor were supposed to be set to 0. The second use + was in TPM_GetCapability and the structure would then return the correct revMajor and + revMinor. This use model caused problems in keeping track of when the revs were or were not set + and how software used the information. Version 1.2 went to structure tags. Some structures did not + change and the TPM_STRUCT_VER is still in use. To avoid the problems from 1.1 this structure now + is a fixed value and only remains for backwards compatibility. Structure versioning comes from the + tag on the structure and the TPM_GetCapability response for TPM versioning uses TPM_VERSION. +*/ + +/* TPM_StructVer_Init() + + sets members to default values + sets all pointers to NULL and sizes to 0 + always succeeds - no return code +*/ + +void TPM_StructVer_Init(TPM_STRUCT_VER *tpm_struct_ver) +{ + printf(" TPM_StructVer_Init:\n"); + tpm_struct_ver->major = 0x01; + tpm_struct_ver->minor = 0x01; + tpm_struct_ver->revMajor = 0x00; + tpm_struct_ver->revMinor = 0x00; + return; +} + +/* TPM_StructVer_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes +*/ + +TPM_RESULT TPM_StructVer_Load(TPM_STRUCT_VER *tpm_struct_ver, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StructVer_Load:\n"); + if (rc == 0) { + rc = TPM_Load8(&(tpm_struct_ver->major), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Load8(&(tpm_struct_ver->minor), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Load8(&(tpm_struct_ver->revMajor), stream, stream_size); + } + if (rc == 0) { + rc = TPM_Load8(&(tpm_struct_ver->revMinor), stream, stream_size); + } + return rc; +} + + +/* TPM_StructVer_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_StructVer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STRUCT_VER *tpm_struct_ver) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StructVer_Store:\n"); + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_struct_ver->major), sizeof(BYTE)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_struct_ver->minor), sizeof(BYTE)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_struct_ver->revMajor), sizeof(BYTE)); + } + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_struct_ver->revMinor), sizeof(BYTE)); + } + return rc; +} + +/* TPM_StructVer_Copy() copies the src to the destination. */ + +void TPM_StructVer_Copy(TPM_STRUCT_VER *tpm_struct_ver_dest, + TPM_STRUCT_VER *tpm_struct_ver_src) +{ + printf(" TPM_StructVer_Copy:\n"); + tpm_struct_ver_dest->major = tpm_struct_ver_src->major; + tpm_struct_ver_dest->minor = tpm_struct_ver_src->minor; + tpm_struct_ver_dest->revMajor = tpm_struct_ver_src->revMajor; + tpm_struct_ver_dest->revMinor = tpm_struct_ver_src->revMinor; + return; +} + +/* TPM_StructVer_CheckVer() checks that the major and minor version are 0x01, 0x01 */ + +TPM_RESULT TPM_StructVer_CheckVer(TPM_STRUCT_VER *tpm_struct_ver) +{ + TPM_RESULT rc = 0; + + printf(" TPM_StructVer_CheckVer: version %u.%u.%u.%u\n", + tpm_struct_ver->major, + tpm_struct_ver->minor, + tpm_struct_ver->revMajor, + tpm_struct_ver->revMinor); + if ((tpm_struct_ver->major != 0x01) || + (tpm_struct_ver->minor != 0x01)) { + printf("TPM_StructVer_CheckVer: Error checking version\n"); + rc = TPM_BAD_VERSION; + } + return rc; +} + +/* + TPM_VERSION + + 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. +*/ + +void TPM_Version_Init(TPM_VERSION *tpm_version) +{ + printf(" TPM_Version_Init:\n"); + tpm_version->major = 0; + tpm_version->minor = 0; + tpm_version->revMajor = 0; + tpm_version->revMinor = 0; + return; +} + +void TPM_Version_Set(TPM_VERSION *tpm_version, + TPM_PERMANENT_DATA *tpm_permanent_data) +{ + printf(" TPM_Version_Set:\n"); + /* This SHALL indicate the major version of the TPM, mostSigVer MUST be 0x01, leastSigVer MUST + be 0x00 */ + tpm_version->major = TPM_MAJOR; + /* This SHALL indicate the minor version of the TPM, mostSigVer MUST be 0x01 or 0x02, + leastSigVer MUST be 0x00 */ + tpm_version->minor = TPM_MINOR; + /* This SHALL be the value of the TPM_PERMANENT_DATA -> revMajor */ + tpm_version->revMajor = tpm_permanent_data->revMajor; + /* This SHALL be the value of the TPM_PERMANENT_DATA -> revMinor */ + tpm_version->revMinor = tpm_permanent_data->revMinor; + return; +} + +/* TPM_Version_Load() + + deserialize the structure from a 'stream' + 'stream_size' is checked for sufficient data + returns 0 or error codes + + Before use, call TPM_Version_Init() +*/ + +TPM_RESULT TPM_Version_Load(TPM_VERSION *tpm_version, + unsigned char **stream, + uint32_t *stream_size) +{ + TPM_RESULT rc = 0; + + printf(" TPM_Version_Load:\n"); + /* load major */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_version->major), stream, stream_size); + } + /* load minor */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_version->minor), stream, stream_size); + } + /* load revMajor */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_version->revMajor), stream, stream_size); + } + /* load revMinor */ + if (rc == 0) { + rc = TPM_Load8(&(tpm_version->revMinor), stream, stream_size); + } + return rc; +} +/* TPM_Version_Store() + + serialize the structure to a stream contained in 'sbuffer' + returns 0 or error codes +*/ + +TPM_RESULT TPM_Version_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_VERSION *tpm_version) + +{ + TPM_RESULT rc = 0; + + printf(" TPM_Version_Store:\n"); + /* store major */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_version->major), sizeof(BYTE)); + } + /* store minor */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_version->minor), sizeof(BYTE)); + } + /* store revMajor */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_version->revMajor), sizeof(BYTE)); + } + /* store revMinor */ + if (rc == 0) { + rc = TPM_Sbuffer_Append(sbuffer, &(tpm_version->revMinor), sizeof(BYTE)); + } + return rc; +} diff --git a/src/tpm_ver.h b/src/tpm_ver.h new file mode 100644 index 00000000..3f797275 --- /dev/null +++ b/src/tpm_ver.h @@ -0,0 +1,74 @@ +/********************************************************************************/ +/* */ +/* Ver Structure Handler */ +/* Written by Ken Goldman */ +/* IBM Thomas J. Watson Research Center */ +/* $Id: tpm_ver.h 4071 2010-04-29 19:26:45Z kgoldman $ */ +/* */ +/* (c) Copyright IBM Corporation 2006, 2010. */ +/* */ +/* All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* */ +/* Redistributions of source code must retain the above copyright notice, */ +/* this list of conditions and the following disclaimer. */ +/* */ +/* 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. */ +/* */ +/* Neither the names of the IBM Corporation nor the names of its */ +/* contributors may be used to endorse or promote products derived from */ +/* this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ +/* "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 COPYRIGHT */ +/* HOLDER OR CONTRIBUTORS 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. */ +/********************************************************************************/ + +#ifndef TPM_VER_H +#define TPM_VER_H + +#include "tpm_types.h" +#include "tpm_store.h" +#include "tpm_structures.h" + +/* TPM_STRUCT_VER */ + +void TPM_StructVer_Init(TPM_STRUCT_VER *tpm_struct_ver); +TPM_RESULT TPM_StructVer_Load(TPM_STRUCT_VER *tpm_struct_ver, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_StructVer_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_STRUCT_VER *tpm_struct_ver); +void TPM_StructVer_Copy(TPM_STRUCT_VER *tpm_struct_ver_dest, + TPM_STRUCT_VER *tpm_struct_ver_src); +TPM_RESULT TPM_StructVer_CheckVer(TPM_STRUCT_VER *tpm_struct_ver); + +/* TPM_VERSION */ + +void TPM_Version_Init(TPM_VERSION *tpm_version); +void TPM_Version_Set(TPM_VERSION *tpm_version, + TPM_PERMANENT_DATA *tpm_permanent_data); +TPM_RESULT TPM_Version_Load(TPM_VERSION *tpm_version, + unsigned char **stream, + uint32_t *stream_size); +TPM_RESULT TPM_Version_Store(TPM_STORE_BUFFER *sbuffer, + const TPM_VERSION *tpm_version); +void TPM_Version_Delete(TPM_VERSION *tpm_version); + + + + +#endif diff --git a/tests/Makefile.am b/tests/Makefile.am new file mode 100644 index 00000000..a8420bf8 --- /dev/null +++ b/tests/Makefile.am @@ -0,0 +1,29 @@ +# +# tests/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# + +check_PROGRAMS = +TESTS = + +if LIBTPMS_USE_FREEBL + +check_PROGRAMS += freebl_sha1flattensize +TESTS += freebl_sha1flattensize + +endif + +freebl_sha1flattensize_SOURCES = \ + freebl_sha1flattensize.c +freebl_sha1flattensize_CFLAGS = \ + $(shell nss-config --cflags) \ + $(shell nspr-config --cflags) \ + -Wall -Werror +freebl_sha1flattensize_LDFLAGS = \ + -lfreebl \ + $(shell nspr-config --libs) \ + $(shell nss-config --libs) + +EXTRA_DIST = \ + freebl_sha1flattensize.c diff --git a/tests/Makefile.in b/tests/Makefile.in new file mode 100644 index 00000000..6f00b3f9 --- /dev/null +++ b/tests/Makefile.in @@ -0,0 +1,648 @@ +# Makefile.in generated by automake 1.11.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software +# Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# tests/Makefile.am +# +# For the license, see the LICENSE file in the root directory. +# +VPATH = @srcdir@ +am__make_dryrun = \ + { \ + am__dry=no; \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ + | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ + *) \ + for am__flg in $$MAKEFLAGS; do \ + case $$am__flg in \ + *=*|--*) ;; \ + *n*) am__dry=yes; break;; \ + esac; \ + done;; \ + esac; \ + test $$am__dry = yes; \ + } +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +check_PROGRAMS = $(am__EXEEXT_1) +TESTS = $(am__EXEEXT_1) +@LIBTPMS_USE_FREEBL_TRUE@am__append_1 = freebl_sha1flattensize +@LIBTPMS_USE_FREEBL_TRUE@am__append_2 = freebl_sha1flattensize +subdir = tests +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \ + $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \ + $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +@LIBTPMS_USE_FREEBL_TRUE@am__EXEEXT_1 = \ +@LIBTPMS_USE_FREEBL_TRUE@ freebl_sha1flattensize$(EXEEXT) +am_freebl_sha1flattensize_OBJECTS = \ + freebl_sha1flattensize-freebl_sha1flattensize.$(OBJEXT) +freebl_sha1flattensize_OBJECTS = $(am_freebl_sha1flattensize_OBJECTS) +freebl_sha1flattensize_LDADD = $(LDADD) +freebl_sha1flattensize_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(freebl_sha1flattensize_CFLAGS) $(CFLAGS) \ + $(freebl_sha1flattensize_LDFLAGS) $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ + --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ + $(LDFLAGS) -o $@ +SOURCES = $(freebl_sha1flattensize_SOURCES) +DIST_SOURCES = $(freebl_sha1flattensize_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEBUG_DEFINES = @DEBUG_DEFINES@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIBTPMS_VERSION = @LIBTPMS_VERSION@ +LIBTPMS_VERSION_INFO = @LIBTPMS_VERSION_INFO@ +LIBTPMS_VER_MAJOR = @LIBTPMS_VER_MAJOR@ +LIBTPMS_VER_MICRO = @LIBTPMS_VER_MICRO@ +LIBTPMS_VER_MINOR = @LIBTPMS_VER_MINOR@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +freebl_sha1flattensize_SOURCES = \ + freebl_sha1flattensize.c + +freebl_sha1flattensize_CFLAGS = \ + $(shell nss-config --cflags) \ + $(shell nspr-config --cflags) \ + -Wall -Werror + +freebl_sha1flattensize_LDFLAGS = \ + -lfreebl \ + $(shell nspr-config --libs) \ + $(shell nss-config --libs) + +EXTRA_DIST = \ + freebl_sha1flattensize.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign tests/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +freebl_sha1flattensize$(EXEEXT): $(freebl_sha1flattensize_OBJECTS) $(freebl_sha1flattensize_DEPENDENCIES) $(EXTRA_freebl_sha1flattensize_DEPENDENCIES) + @rm -f freebl_sha1flattensize$(EXEEXT) + $(freebl_sha1flattensize_LINK) $(freebl_sha1flattensize_OBJECTS) $(freebl_sha1flattensize_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/freebl_sha1flattensize-freebl_sha1flattensize.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +freebl_sha1flattensize-freebl_sha1flattensize.o: freebl_sha1flattensize.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(freebl_sha1flattensize_CFLAGS) $(CFLAGS) -MT freebl_sha1flattensize-freebl_sha1flattensize.o -MD -MP -MF $(DEPDIR)/freebl_sha1flattensize-freebl_sha1flattensize.Tpo -c -o freebl_sha1flattensize-freebl_sha1flattensize.o `test -f 'freebl_sha1flattensize.c' || echo '$(srcdir)/'`freebl_sha1flattensize.c +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/freebl_sha1flattensize-freebl_sha1flattensize.Tpo $(DEPDIR)/freebl_sha1flattensize-freebl_sha1flattensize.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='freebl_sha1flattensize.c' object='freebl_sha1flattensize-freebl_sha1flattensize.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(freebl_sha1flattensize_CFLAGS) $(CFLAGS) -c -o freebl_sha1flattensize-freebl_sha1flattensize.o `test -f 'freebl_sha1flattensize.c' || echo '$(srcdir)/'`freebl_sha1flattensize.c + +freebl_sha1flattensize-freebl_sha1flattensize.obj: freebl_sha1flattensize.c +@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(freebl_sha1flattensize_CFLAGS) $(CFLAGS) -MT freebl_sha1flattensize-freebl_sha1flattensize.obj -MD -MP -MF $(DEPDIR)/freebl_sha1flattensize-freebl_sha1flattensize.Tpo -c -o freebl_sha1flattensize-freebl_sha1flattensize.obj `if test -f 'freebl_sha1flattensize.c'; then $(CYGPATH_W) 'freebl_sha1flattensize.c'; else $(CYGPATH_W) '$(srcdir)/freebl_sha1flattensize.c'; fi` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/freebl_sha1flattensize-freebl_sha1flattensize.Tpo $(DEPDIR)/freebl_sha1flattensize-freebl_sha1flattensize.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='freebl_sha1flattensize.c' object='freebl_sha1flattensize-freebl_sha1flattensize.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(freebl_sha1flattensize_CFLAGS) $(CFLAGS) -c -o freebl_sha1flattensize-freebl_sha1flattensize.obj `if test -f 'freebl_sha1flattensize.c'; then $(CYGPATH_W) 'freebl_sha1flattensize.c'; else $(CYGPATH_W) '$(srcdir)/freebl_sha1flattensize.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +check-TESTS: $(TESTS) + @failed=0; all=0; xfail=0; xpass=0; skip=0; \ + srcdir=$(srcdir); export srcdir; \ + list=' $(TESTS) '; \ + $(am__tty_colors); \ + if test -n "$$list"; then \ + for tst in $$list; do \ + if test -f ./$$tst; then dir=./; \ + elif test -f $$tst; then dir=; \ + else dir="$(srcdir)/"; fi; \ + if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xpass=`expr $$xpass + 1`; \ + failed=`expr $$failed + 1`; \ + col=$$red; res=XPASS; \ + ;; \ + *) \ + col=$$grn; res=PASS; \ + ;; \ + esac; \ + elif test $$? -ne 77; then \ + all=`expr $$all + 1`; \ + case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$tst[\ \ ]*) \ + xfail=`expr $$xfail + 1`; \ + col=$$lgn; res=XFAIL; \ + ;; \ + *) \ + failed=`expr $$failed + 1`; \ + col=$$red; res=FAIL; \ + ;; \ + esac; \ + else \ + skip=`expr $$skip + 1`; \ + col=$$blu; res=SKIP; \ + fi; \ + echo "$${col}$$res$${std}: $$tst"; \ + done; \ + if test "$$all" -eq 1; then \ + tests="test"; \ + All=""; \ + else \ + tests="tests"; \ + All="All "; \ + fi; \ + if test "$$failed" -eq 0; then \ + if test "$$xfail" -eq 0; then \ + banner="$$All$$all $$tests passed"; \ + else \ + if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ + banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ + fi; \ + else \ + if test "$$xpass" -eq 0; then \ + banner="$$failed of $$all $$tests failed"; \ + else \ + if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ + banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ + fi; \ + fi; \ + dashes="$$banner"; \ + skipped=""; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + skipped="($$skip test was not run)"; \ + else \ + skipped="($$skip tests were not run)"; \ + fi; \ + test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$skipped"; \ + fi; \ + report=""; \ + if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ + report="Please report to $(PACKAGE_BUGREPORT)"; \ + test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ + dashes="$$report"; \ + fi; \ + dashes=`echo "$$dashes" | sed s/./=/g`; \ + if test "$$failed" -eq 0; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + fi; \ + echo "$${col}$$dashes$${std}"; \ + echo "$${col}$$banner$${std}"; \ + test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ + test -z "$$report" || echo "$${col}$$report$${std}"; \ + echo "$${col}$$dashes$${std}"; \ + test "$$failed" -eq 0; \ + else :; fi + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-am +all-am: Makefile +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: check-am install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \ + clean-checkPROGRAMS clean-generic clean-libtool ctags \ + distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/tests/freebl_sha1flattensize.c b/tests/freebl_sha1flattensize.c new file mode 100644 index 00000000..6fb3d571 --- /dev/null +++ b/tests/freebl_sha1flattensize.c @@ -0,0 +1,50 @@ +#include +#include + +#include + + +#if defined (__x86_64__) || \ + defined (__amd64__) || \ + defined (__ia64__) || \ + defined (__powerpc64__) || \ + defined (__s390x__) || \ + (defined (__sparc__) && defined(__arch64__)) + +#define EXPECTED_LIB_FLATTENSIZE 248 + +#elif defined (__i386__) || \ + defined (__powerpc__) || \ + defined (__s390__) || \ + defined (__sparc__) || \ + defined (__arm__) + +#define EXPECTED_LIB_FLATTENSIZE 160 + +#else + +#error Undefined architecture type + +#endif + +int main(void) +{ + SHA1Context *context; + uint32_t libFlattenSize; + + context = SHA1_NewContext(); + if (!context) { + printf("Could not create SHA1 context.\n"); + return EXIT_FAILURE; + } + SHA1_Begin(context); + + libFlattenSize = SHA1_FlattenSize(context); + if (libFlattenSize != EXPECTED_LIB_FLATTENSIZE) { + printf("SHA1 flatten size is %d, expected %d\n", + libFlattenSize, + EXPECTED_LIB_FLATTENSIZE); + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +}