This commit is contained in:
Marc-Andre Lureau 2026-02-27 22:26:47 -08:00 committed by GitHub
commit 8198362ab0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 596 additions and 1 deletions

View File

@ -72,3 +72,21 @@ jobs:
exit 0
env:
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}
meson-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y meson ninja-build pkg-config openssl libssl-dev
- name: meson build
run: |
meson setup build --prefix=/usr
meson compile -C build
meson test -C build
meson dist -C build
tar -tf build/meson-dist/*.tar.xz

25
README
View File

@ -74,6 +74,31 @@ For patch submissions, please use a Signed-off-by: <your email> to indicate
agreement to the DCO1.1.txt.
Building
--------
There are two build systems available for libtpms: autotools and meson.
The GitHub CI runs builds using both build systems.
### Autotools
To build with autotools, run the following commands:
$ ./autogen.sh --with-openssl --prefix=/usr --with-tpm2
$ make
$ make check
$ sudo make install
### Meson
To build with meson, run the following commands:
$ meson setup build --prefix=/usr
$ meson compile -C build
$ meson test -C build
$ sudo meson install -C build
Fuzzing
-------
Initial fuzzing is possible with clang & libfuzzer.

View File

@ -0,0 +1,15 @@
tpm_library_h = configure_file(
input: 'tpm_library.h.in',
output: 'tpm_library.h',
configuration: conf_data,
)
install_headers(
'tpm_error.h',
'tpm_memory.h',
'tpm_nvfilename.h',
'tpm_tis.h',
'tpm_types.h',
tpm_library_h,
subdir: 'libtpms'
)

1
include/meson.build Normal file
View File

@ -0,0 +1 @@
subdir('libtpms')

37
man/man3/meson.build Normal file
View File

@ -0,0 +1,37 @@
pod_files = [
'TPM_IO_Hash_Start.pod',
'TPM_IO_TpmEstablished_Get.pod',
'TPM_Malloc.pod',
'TPMLIB_CancelCommand.pod',
'TPMLIB_ChooseTPMVersion.pod',
'TPMLIB_DecodeBlob.pod',
'TPMLIB_GetInfo.pod',
'TPMLIB_GetTPMProperty.pod',
'TPMLIB_GetVersion.pod',
'TPMLIB_MainInit.pod',
'TPMLIB_Process.pod',
'TPMLIB_RegisterCallbacks.pod',
'TPMLIB_SetBufferSize.pod',
'TPMLIB_SetDebugFD.pod',
'TPMLIB_SetProfile.pod',
'TPMLIB_SetState.pod',
'TPMLIB_ValidateState.pod',
'TPMLIB_VolatileAll_Store.pod',
'TPMLIB_WasManufactured.pod',
]
pod2man = find_program('pod2man', required: true)
foreach pod : pod_files
base_name = pod.split('.')[0]
target_name = base_name + '.3'
custom_target(target_name,
input: pod,
output: target_name,
command: [pod2man, '-r', 'libtpms', '-c', '""', '-n', base_name, '--section=3', '@INPUT@', '@OUTPUT@'],
capture: false,
install: true,
install_dir: get_option('mandir') / 'man3'
)
endforeach

1
man/meson.build Normal file
View File

@ -0,0 +1 @@
subdir('man3')

97
meson.build Normal file
View File

@ -0,0 +1,97 @@
project(
'libtpms', ['c', 'cpp'],
version: '0.11.0',
license: 'BSD-3-Clause AND LicenseRef-TCGL',
default_options: ['c_std=c99', 'warning_level=1', 'werror=true'],
meson_version: '>=1.1',
)
c_compiler = meson.get_compiler('c')
# Add an include directory that points to the build directory.
add_project_arguments('-I' + meson.current_build_dir(), language: 'c')
# Add common warning flags
warning_flags = [
'-Wshadow',
'-Wreturn-type',
'-Wsign-compare',
'-Wno-self-assign',
'-Wmissing-prototypes'
]
supported_warning_flags = c_compiler.get_supported_arguments(warning_flags)
add_project_arguments(supported_warning_flags, language: 'c')
# Get build options
with_tpm1 = get_option('tpm1')
with_tpm2 = get_option('tpm2')
crypto_backend = get_option('crypto_backend')
if crypto_backend == 'openssl'
add_project_arguments(['-DUSE_OPENSSL_CRYPTO_LIBRARY=1'], language: 'c')
else
add_project_arguments(['-DUSE_FREEBL_CRYPTO_LIBRARY=1'], language: 'c')
endif
# Add hardening flags for non-plain build types
if get_option('buildtype') != 'plain'
hardening_c_flags = []
# Stack protector
if c_compiler.has_argument('-fstack-protector-strong')
hardening_c_flags += '-fstack-protector-strong'
elif c_compiler.has_argument('-fstack-protector')
hardening_c_flags += '-fstack-protector'
endif
# Fortify source only works with optimization
if get_option('optimization') != '0'
if c_compiler.has_argument('-D_FORTIFY_SOURCE=2')
hardening_c_flags += '-D_FORTIFY_SOURCE=2'
endif
endif
add_project_arguments(hardening_c_flags, language: 'c')
hardening_ld_flags = []
# Linker hardening
if c_compiler.has_link_argument('-Wl,-z,relro')
hardening_ld_flags += '-Wl,-z,relro'
endif
if c_compiler.has_link_argument('-Wl,-z,now')
hardening_ld_flags += '-Wl,-z,now'
endif
add_project_link_arguments(hardening_ld_flags, language: 'c')
endif
# Versioning
libtpms_version = meson.project_version()
libtpms_version_arr = libtpms_version.split('.')
libtpms_ver_major = libtpms_version_arr[0].to_int()
libtpms_ver_minor = libtpms_version_arr[1].to_int()
libtpms_ver_micro = libtpms_version_arr[2].to_int()
# Create a configuration header file
conf_data = configuration_data()
conf_data.set('PACKAGE_VERSION', '"' + meson.project_version() + '"')
conf_data.set('LIBTPMS_VER_MAJOR', libtpms_ver_major)
conf_data.set('LIBTPMS_VER_MINOR', libtpms_ver_minor)
conf_data.set('LIBTPMS_VER_MICRO', libtpms_ver_micro)
# config.h could be dropped if when autotools is removed
configure_file(
output: 'config.h',
configuration: conf_data
)
# Add subdirectories to the build
subdir('include')
subdir('src')
subdir('man')
subdir('tests')
summary_info = {}
summary_info += {'Build directory': meson.current_build_dir()}
summary_info += {'Source path': meson.current_source_dir()}
summary_info += {'TPM1': with_tpm1}
summary_info += {'TPM2': with_tpm2}
summary_info += {'Crypto backend': crypto_backend}
summary(summary_info, bool_yn: true, section: 'Build configuration')

6
meson.options Normal file
View File

@ -0,0 +1,6 @@
option('tpm1', type: 'boolean', value: true, description: 'Build with TPM 1.2 support.')
option('tpm2', type: 'boolean', value: true, description: 'Build with TPM 2.0 support.')
option('crypto_backend', type: 'combo', choices: ['openssl', 'freebl'], value: 'openssl', description: 'Choose the cryptographic backend.')
option('use_openssl_functions', type: 'boolean', value: true, description: 'Use OpenSSL functions for crypto instead of internal code.')
option('fuzzing_engine', type: 'boolean', value: false, description: 'Build with fuzzing engine')

327
src/meson.build Normal file
View File

@ -0,0 +1,327 @@
current = libtpms_ver_major + libtpms_ver_minor
age = libtpms_ver_minor
soversion = '@0@'.format(current - age)
# TPM2 requires OpenSSL in this build configuration
if with_tpm2 and crypto_backend != 'openssl'
error('TPM2 support currently requires the openssl crypto backend.')
endif
# --- Crypto Dependencies and Flags ---
crypto_deps = []
tpm1_crypto_sources = []
freebl_inc = []
crypto_flags = []
if crypto_backend == 'openssl'
crypto_deps += dependency('openssl', version: '>=1.1.0', required: true)
if with_tpm1
tpm1_crypto_sources += 'tpm12/tpm_crypto.c'
endif
if get_option('use_openssl_functions')
crypto_flags += [
'-DUSE_OPENSSL_FUNCTIONS_SYMMETRIC=1',
'-DUSE_OPENSSL_FUNCTIONS_EC=1',
'-DUSE_OPENSSL_FUNCTIONS_ECDSA=1',
'-DUSE_OPENSSL_FUNCTIONS_RSA=1',
'-DUSE_OPENSSL_FUNCTIONS_SSKDF=1'
]
else
crypto_flags += [
'-DUSE_OPENSSL_FUNCTIONS_SYMMETRIC=0',
'-DUSE_OPENSSL_FUNCTIONS_EC=0',
'-DUSE_OPENSSL_FUNCTIONS_ECDSA=0',
'-DUSE_OPENSSL_FUNCTIONS_RSA=0',
'-DUSE_OPENSSL_FUNCTIONS_SSKDF=0'
]
endif
else # freebl
nss_dep = dependency('nss')
nspr_dep = dependency('nspr')
gmp_dep = dependency('gmp')
crypto_deps += [nss_dep, nspr_dep, gmp_dep]
crypto_deps += meson.get_compiler('c').find_library('freebl', required: true)
freebl_inc += include_directories(nss_dep.get_variable(pkgconfig: 'includedir'))
freebl_inc += include_directories(nspr_dep.get_variable(pkgconfig: 'includedir'))
if with_tpm1
tpm1_crypto_sources += 'tpm12/tpm_crypto_freebl.c'
endif
endif
# --- Library Definitions ---
# Include directory for the library's own public headers
lib_inc = include_directories('../include/libtpms')
# Common source files
common_sources = files(
'tpm_debug.c',
'tpm_library.c',
'tpm_memory.c',
'tpm_nvfile.c',
'disabled_interface.c'
)
link_with_libs = []
extra_deps = []
# Common c_args for all libraries
common_c_args = [
'-DTPM_NV_DISK',
'-DTPM_LIBTPMS_CALLBACKS',
'-DOPENSSL_SUPPRESS_DEPRECATED',
'-include', 'tpm_library_conf.h'
]
if with_tpm1
common_c_args += ['-DWITH_TPM1']
tpm1_sources = files(
'tpm12/tpm_admin.c',
'tpm12/tpm_audit.c',
'tpm12/tpm_auth.c',
'tpm12/tpm_counter.c',
'tpm12/tpm_cryptoh.c',
'tpm12/tpm_daa.c',
'tpm12/tpm_delegate.c',
'tpm12/tpm_digest.c',
'tpm12/tpm_error.c',
'tpm12/tpm_global.c',
'tpm12/tpm_identity.c',
'tpm12/tpm_init.c',
'tpm12/tpm_key.c',
'tpm12/tpm_libtpms_io.c',
'tpm12/tpm_load.c',
'tpm12/tpm_maint.c',
'tpm12/tpm_migration.c',
'tpm12/tpm_nonce.c',
'tpm12/tpm_nvram.c',
'tpm12/tpm_openssl_helpers.c',
'tpm12/tpm_owner.c',
'tpm12/tpm_pcr.c',
'tpm12/tpm_permanent.c',
'tpm12/tpm_platform.c',
'tpm12/tpm_process.c',
'tpm12/tpm_secret.c',
'tpm12/tpm_session.c',
'tpm12/tpm_sizedbuffer.c',
'tpm12/tpm_startup.c',
'tpm12/tpm_storage.c',
'tpm12/tpm_store.c',
'tpm12/tpm_svnrevision.c',
'tpm12/tpm_ticks.c',
'tpm12/tpm_time.c',
'tpm12/tpm_transport.c',
'tpm12/tpm_ver.c',
'tpm_tpm12_interface.c',
'tpm_tpm12_tis.c',
tpm1_crypto_sources
)
tpm1_lib = static_library('tpms_tpm12', tpm1_sources,
c_args: common_c_args + crypto_flags + [
'-DTPM_V12',
'-DTPM_PCCLIENT',
'-DTPM_POSIX',
'-DTPM_AES',
'-DTPM_NOMAINTENANCE_COMMANDS',
'-DTPM_ENABLE_ACTIVATE',
'-DTPM_VOLATILE_LOAD',
],
include_directories: [lib_inc] + freebl_inc,
)
link_with_libs += tpm1_lib
endif
if with_tpm2
common_c_args += ['-DWITH_TPM2']
rt_dep = meson.get_compiler('c').find_library('rt', required: false)
extra_deps += rt_dep
tpm2_sources = files(
'tpm2/ACTCommands.c',
'tpm2/ACT_spt.c',
'tpm2/AlgorithmCap.c',
'tpm2/AlgorithmTests.c',
'tpm2/AsymmetricCommands.c',
'tpm2/Attest_spt.c',
'tpm2/AttestationCommands.c',
'tpm2/AuditCommands.c',
'tpm2/Bits.c',
'tpm2/BnConvert.c',
'tpm2/BnEccConstants.c',
'tpm2/BnMath.c',
'tpm2/BnMemory.c',
'tpm2/Cancel.c',
'tpm2/CapabilityCommands.c',
'tpm2/Clock.c',
'tpm2/ClockCommands.c',
'tpm2/CommandAudit.c',
'tpm2/CommandCodeAttributes.c',
'tpm2/CommandDispatcher.c',
'tpm2/ContextCommands.c',
'tpm2/Context_spt.c',
'tpm2/CryptEccData.c',
'tpm2/CryptSelfTest.c',
'tpm2/CryptUtil.c',
'tpm2/DA.c',
'tpm2/DebugHelpers.c',
'tpm2/DictionaryCommands.c',
'tpm2/DuplicationCommands.c',
'tpm2/EACommands.c',
'tpm2/EncryptDecrypt_spt.c',
'tpm2/Entity.c',
'tpm2/Entropy.c',
'tpm2/EphemeralCommands.c',
'tpm2/ExecCommand.c',
'tpm2/ExtraData.c',
'tpm2/Global.c',
'tpm2/Handle.c',
'tpm2/HashCommands.c',
'tpm2/Hierarchy.c',
'tpm2/HierarchyCommands.c',
'tpm2/IntegrityCommands.c',
'tpm2/IoBuffers.c',
'tpm2/Locality.c',
'tpm2/LocalityPlat.c',
'tpm2/ManagementCommands.c',
'tpm2/Manufacture.c',
'tpm2/Marshal.c',
'tpm2/MathOnByteBuffers.c',
'tpm2/Memory.c',
'tpm2/NVCommands.c',
'tpm2/NVMem.c',
'tpm2/NV_spt.c',
'tpm2/NvDynamic.c',
'tpm2/NvReserved.c',
'tpm2/Object.c',
'tpm2/ObjectCommands.c',
'tpm2/Object_spt.c',
'tpm2/PCR.c',
'tpm2/PP.c',
'tpm2/PPPlat.c',
'tpm2/PlatformACT.c',
'tpm2/PlatformData.c',
'tpm2/PlatformPCR.c',
'tpm2/Policy_spt.c',
'tpm2/Power.c',
'tpm2/PowerPlat.c',
'tpm2/PrimeData.c',
'tpm2/PropertyCap.c',
'tpm2/RandomCommands.c',
'tpm2/Response.c',
'tpm2/ResponseCodeProcessing.c',
'tpm2/RunCommand.c',
'tpm2/Session.c',
'tpm2/SessionCommands.c',
'tpm2/SessionProcess.c',
'tpm2/SigningCommands.c',
'tpm2/StartupCommands.c',
'tpm2/SymmetricCommands.c',
'tpm2/TPMCmdp.c',
'tpm2/TestingCommands.c',
'tpm2/Ticket.c',
'tpm2/Time.c',
'tpm2/TpmASN1.c',
'tpm2/TpmBigNumThunks.c',
'tpm2/TpmEcc_Signature_ECDAA.c',
'tpm2/TpmEcc_Signature_ECDSA.c',
'tpm2/TpmEcc_Signature_SM2.c',
'tpm2/TpmEcc_Signature_Schnorr.c',
'tpm2/TpmEcc_Signature_Util.c',
'tpm2/TpmEcc_Util.c',
'tpm2/TpmFail.c',
'tpm2/TpmMath_Debug.c',
'tpm2/TpmMath_Util.c',
'tpm2/TpmSizeChecks.c',
'tpm2/Unique.c',
'tpm2/Unmarshal.c',
'tpm2/VendorInfo.c',
'tpm2/Vendor_TCG_Test.c',
'tpm2/X509_ECC.c',
'tpm2/X509_RSA.c',
'tpm2/X509_spt.c',
'tpm2/crypto/openssl/BnToOsslMath.c',
'tpm2/crypto/openssl/CryptCmac.c',
'tpm2/crypto/openssl/CryptDes.c',
'tpm2/crypto/openssl/CryptEccCrypt.c',
'tpm2/crypto/openssl/CryptEccKeyExchange.c',
'tpm2/crypto/openssl/CryptEccMain.c',
'tpm2/crypto/openssl/CryptEccSignature.c',
'tpm2/crypto/openssl/CryptHash.c',
'tpm2/crypto/openssl/CryptPrime.c',
'tpm2/crypto/openssl/CryptPrimeSieve.c',
'tpm2/crypto/openssl/CryptRand.c',
'tpm2/crypto/openssl/CryptRsa.c',
'tpm2/crypto/openssl/CryptSmac.c',
'tpm2/crypto/openssl/CryptSym.c',
'tpm2/crypto/openssl/ExpDCache.c',
'tpm2/crypto/openssl/Helpers.c',
'tpm2/crypto/openssl/TpmToOsslDesSupport.c',
'tpm2/crypto/openssl/TpmToOsslSupport.c',
'tpm_tpm2_interface.c',
'tpm_tpm2_tis.c',
)
# files specific to libtpms
tpm2_sources += files(
'tpm2/BackwardsCompatibilityBitArray.c',
'tpm2/BackwardsCompatibilityObject.c',
'tpm2/LibtpmsCallbacks.c',
'tpm2/NVMarshal.c',
'tpm2/RuntimeAlgorithm.c',
'tpm2/RuntimeAttributes.c',
'tpm2/RuntimeCommands.c',
'tpm2/RuntimeProfile.c',
'tpm2/StateMarshal.c',
'tpm2/Volatile.c',
)
tpm2_lib = static_library('tpms_tpm2', tpm2_sources,
c_args: common_c_args + crypto_flags + [
'-D_POSIX_C_SOURCE=200809L',
'-DTPM_POSIX',
],
include_directories: [
lib_inc,
'.',
'tpm2',
'tpm2/crypto',
'tpm2/crypto/openssl'
],
)
link_with_libs += tpm2_lib
endif
# Define the final shared library
libtpms = both_libraries('tpms',
common_sources,
c_args: common_c_args,
link_with: link_with_libs,
dependencies: crypto_deps + extra_deps,
include_directories: [lib_inc],
install: true,
version: libtpms_version,
soversion: soversion,
darwin_versions: [soversion, libtpms_version],
vs_module_defs: 'libtpms.syms',
link_args: ['-Wl,--version-script,@0@'.format(meson.current_source_dir() / 'libtpms.syms')],
)
libtpms_dep = declare_dependency(
link_with: libtpms,
include_directories: [lib_inc],
dependencies: crypto_deps + extra_deps,
)
# Pkg-config generation
pkg = import('pkgconfig')
pkg.generate(
name: 'libtpms',
description: 'A library for TPM emulation.',
version: meson.project_version(),
variables: [
'with_tpm1=@0@'.format(with_tpm1 ? '1' : '0'),
'with_tpm2=@0@'.format(with_tpm2 ? '1' : '0'),
'cryptolib=@0@'.format(crypto_backend),
],
libraries: libtpms
)

68
tests/meson.build Normal file
View File

@ -0,0 +1,68 @@
test_env = {
'abs_top_srcdir': meson.project_source_root(),
'abs_top_builddir': meson.project_build_root(),
'abs_top_testdir': meson.project_source_root() / 'tests',
}
sh = find_program('sh')
exe = executable('base64decode', files('base64decode.c'), dependencies: [libtpms_dep])
test('base64decode.sh', sh, args: files('base64decode.sh'), depends: exe, workdir: meson.current_build_dir())
src_inc = [
'../include/libtpms',
'../src',
'../src/tpm2',
'../src/tpm2/crypto',
'../src/tpm2/crypto/openssl',
]
if get_option('tpm2')
exe = executable('nvram_offsets', 'nvram_offsets.c',
dependencies: [libtpms_dep],
include_directories: src_inc,
c_args: ['-DTPM_POSIX', '-D_POSIX_C_SOURCE=200809L'],
)
test('nvram_offsets', exe, env: test_env)
exe = executable('tpm2_createprimary', files('tpm2_createprimary.c'), dependencies: [libtpms_dep])
test('tpm2_createprimary.sh', sh, args: files('tpm2_createprimary.sh'), depends: exe, workdir: meson.current_build_dir())
exe = executable('tpm2_cve-2023-1017', files('tpm2_cve-2023-1017.c'), dependencies: [libtpms_dep])
test('tpm2_cve-2023-1017.sh', sh, args: files('tpm2_cve-2023-1017.sh'), depends: exe, workdir: meson.current_build_dir())
exe = executable('tpm2_cve-2023-1018', files('tpm2_cve-2023-1018.c'), dependencies: [libtpms_dep])
test('tpm2_cve-2023-1018.sh', sh, args: files('tpm2_cve-2023-1018.sh'), depends: exe, workdir: meson.current_build_dir())
exe = executable('tpm2_selftest', files('tpm2_selftest.c'), dependencies: [libtpms_dep])
test('tpm2_selftest.sh', sh, args: files('tpm2_selftest.sh'), depends: exe, workdir: meson.current_build_dir())
exe = executable('tpm2_pcr_read', files('tpm2_pcr_read.c'), dependencies: [libtpms_dep])
test('tpm2_pcr_read.sh', sh, args: files('tpm2_pcr_read.sh'), depends: exe, workdir: meson.current_build_dir())
exe = executable('tpm2_setprofile', files('tpm2_setprofile.c'), dependencies: [libtpms_dep])
test('tpm2_setprofile.sh', sh, args: files('tpm2_setprofile.sh'), depends: exe, workdir: meson.current_build_dir())
fuzz_sources = ['fuzz.cc']
if not get_option('fuzzing_engine')
fuzz_sources += 'fuzz-main.c'
endif
exe = executable('fuzz', fuzz_sources, dependencies: [libtpms_dep], c_args: ['-DTPM_POSIX', '-D_POSIX_C_SOURCE=200809L'])
test('fuzz.sh', sh, args: files('fuzz.sh'), depends: exe, workdir: meson.current_build_dir())
exe = executable('object_size', files('object_size.c'),
link_with: libtpms.get_static_lib(),
include_directories: src_inc,
c_args: ['-static', '-DTPM_POSIX', '-D_POSIX_C_SOURCE=200809L'],
)
test('object_size', exe, env: test_env)
endif
if crypto_backend == 'freebl'
exe = executable('freebl_sha1flattensize', 'freebl_sha1flattensize.c',
dependencies: [libtpms_dep, nss_dep, nspr_dep],
link_args: ['-lfreebl']
)
# FIXME: test fails
# test('freebl_sha1flattensize', exe, env: test_env)
endif

View File

@ -77,7 +77,7 @@ int main(void)
},
.seedCompatLevel = 1,
};
#pragma GCC diagnostics pop
#pragma GCC diagnostic pop
static const size_t exp_sizes[7] = {
0, 3284, 3284, 3284, 3284, 3284, 3288,
};