commit a0098eda2de970a7604985e5b2e242fd97ec879d Author: Corey Bryant Date: Fri Sep 27 10:42:51 2013 -0500 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 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; +}