mirror of
https://git.code.sf.net/p/linux-ima/ima-evm-utils
synced 2025-07-03 22:23:16 +02:00
Compare commits
89 Commits
Author | SHA1 | Date | |
---|---|---|---|
318a3e6b2d | |||
f9b805fabc | |||
1a9472a09c | |||
4dab8558fc | |||
9171c1ce43 | |||
ba366f0b41 | |||
3328f6efed | |||
80bb310152 | |||
5356b0487a | |||
ebcdbfe91e | |||
e5b3097821 | |||
4a977c8d23 | |||
6350e014a8 | |||
3b32acbc7d | |||
1de1e3c8ce | |||
29aa7465d5 | |||
47510a1050 | |||
6fbb2a305b | |||
fa2ba9a6e9 | |||
b1818c1113 | |||
e52fc1d330 | |||
efacc1f396 | |||
2a7658bf0e | |||
a5f5dd7c8e | |||
40621b2259 | |||
0e7a00e26b | |||
51b694bfea | |||
6ecb883528 | |||
6cdbd2d49f | |||
84a423d5a1 | |||
ad1d5e3f67 | |||
996435d2d6 | |||
79ff634f7e | |||
58a84044fd | |||
aef36466c9 | |||
a7dd075ef7 | |||
fd40ff5dd5 | |||
a5a03d5454 | |||
75b65e8618 | |||
3f806e1100 | |||
309d3369bb | |||
3feccd45a8 | |||
d22cf0b005 | |||
3a28dd2721 | |||
837591b81b | |||
161a4a5026 | |||
81478c5667 | |||
487a078cd3 | |||
28dd7d4b06 | |||
8e0b3f00be | |||
6287cb76d1 | |||
74ea78d4f2 | |||
8cbf05fcde | |||
d80b6d5a7d | |||
9473e3c887 | |||
cbbe31e1ca | |||
056a7d284c | |||
57f0ffd8d9 | |||
097c81a1a5 | |||
f4b901d081 | |||
00a0e66a14 | |||
155c139d30 | |||
2d03bdbdde | |||
f3fb7c5de0 | |||
54d07e3aaf | |||
0ecfd590c2 | |||
05c03be98b | |||
9980149f95 | |||
2fb79b9c3e | |||
2b2a3623c1 | |||
19b77c8667 | |||
7fd8c13b64 | |||
f831508297 | |||
6c78911350 | |||
851f8c7907 | |||
ccbac508b5 | |||
83e7925cbe | |||
60e1535438 | |||
5b764057f3 | |||
4a67103e9d | |||
9620d8b70d | |||
3b70893edf | |||
b51487be67 | |||
1b5146db99 | |||
3ff5d99edc | |||
f2fe592907 | |||
9cd7edf1e0 | |||
d5aed92be4 | |||
fbd96c98c5 |
137
.github/workflows/ci.yml
vendored
Normal file
137
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
# Copyright (c) 2021 Petr Vorel <pvorel@suse.cz>
|
||||||
|
name: "distros"
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
job:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# 32bit build
|
||||||
|
- container: "debian:stable"
|
||||||
|
env:
|
||||||
|
CC: gcc
|
||||||
|
ARCH: i386
|
||||||
|
TSS: tpm2-tss
|
||||||
|
VARIANT: i386
|
||||||
|
COMPILE_SSL: openssl-3.0.0-beta1
|
||||||
|
|
||||||
|
# cross compilation builds
|
||||||
|
- container: "debian:stable"
|
||||||
|
env:
|
||||||
|
ARCH: ppc64el
|
||||||
|
CC: powerpc64le-linux-gnu-gcc
|
||||||
|
TSS: ibmtss
|
||||||
|
VARIANT: cross-compile
|
||||||
|
|
||||||
|
- container: "debian:stable"
|
||||||
|
env:
|
||||||
|
ARCH: arm64
|
||||||
|
CC: aarch64-linux-gnu-gcc
|
||||||
|
TSS: tpm2-tss
|
||||||
|
VARIANT: cross-compile
|
||||||
|
|
||||||
|
- container: "debian:stable"
|
||||||
|
env:
|
||||||
|
ARCH: s390x
|
||||||
|
CC: s390x-linux-gnu-gcc
|
||||||
|
TSS: ibmtss
|
||||||
|
VARIANT: cross-compile
|
||||||
|
|
||||||
|
# musl (native)
|
||||||
|
- container: "alpine:latest"
|
||||||
|
env:
|
||||||
|
CC: gcc
|
||||||
|
TSS: tpm2-tss
|
||||||
|
|
||||||
|
# glibc (gcc/clang)
|
||||||
|
- container: "opensuse/tumbleweed"
|
||||||
|
env:
|
||||||
|
CC: clang
|
||||||
|
TSS: ibmtss
|
||||||
|
COMPILE_SSL: openssl-3.0.0-beta1
|
||||||
|
|
||||||
|
- container: "opensuse/leap"
|
||||||
|
env:
|
||||||
|
CC: gcc
|
||||||
|
TSS: tpm2-tss
|
||||||
|
|
||||||
|
- container: "ubuntu:groovy"
|
||||||
|
env:
|
||||||
|
CC: gcc
|
||||||
|
TSS: ibmtss
|
||||||
|
COMPILE_SSL: openssl-3.0.0-beta1
|
||||||
|
|
||||||
|
- container: "ubuntu:xenial"
|
||||||
|
env:
|
||||||
|
CC: clang
|
||||||
|
TSS: tpm2-tss
|
||||||
|
|
||||||
|
- container: "fedora:latest"
|
||||||
|
env:
|
||||||
|
CC: clang
|
||||||
|
TSS: ibmtss
|
||||||
|
|
||||||
|
- container: "centos:7"
|
||||||
|
env:
|
||||||
|
CC: gcc
|
||||||
|
TSS: tpm2-tss
|
||||||
|
|
||||||
|
- container: "centos:latest"
|
||||||
|
env:
|
||||||
|
CC: gcc
|
||||||
|
TSS: tpm2-tss
|
||||||
|
|
||||||
|
- container: "debian:testing"
|
||||||
|
env:
|
||||||
|
CC: clang
|
||||||
|
TSS: tpm2-tss
|
||||||
|
|
||||||
|
- container: "debian:stable"
|
||||||
|
env:
|
||||||
|
CC: clang
|
||||||
|
TSS: ibmtss
|
||||||
|
|
||||||
|
- container: "alt:sisyphus"
|
||||||
|
env:
|
||||||
|
CC: gcc
|
||||||
|
TSS: libtpm2-tss-devel
|
||||||
|
|
||||||
|
container:
|
||||||
|
image: ${{ matrix.container }}
|
||||||
|
env: ${{ matrix.env }}
|
||||||
|
options: --security-opt seccomp=unconfined
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Show OS
|
||||||
|
run: cat /etc/os-release
|
||||||
|
|
||||||
|
- name: Git checkout
|
||||||
|
uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Install additional packages
|
||||||
|
run: |
|
||||||
|
INSTALL=${{ matrix.container }}
|
||||||
|
INSTALL="${INSTALL%%:*}"
|
||||||
|
INSTALL="${INSTALL%%/*}"
|
||||||
|
if [ "$VARIANT" ]; then ARCH="$ARCH" ./ci/$INSTALL.$VARIANT.sh; fi
|
||||||
|
ARCH="$ARCH" CC="$CC" TSS="$TSS" ./ci/$INSTALL.sh
|
||||||
|
if [ "$COMPILE_SSL" ]; then COMPILE_SSL="$COMPILE_SSL" ./tests/install-openssl3.sh; fi
|
||||||
|
|
||||||
|
- name: Build swtpm
|
||||||
|
run: |
|
||||||
|
if [ ! "$VARIANT" ]; then
|
||||||
|
which tpm_server || which swtpm || \
|
||||||
|
if which tssstartup; then
|
||||||
|
./tests/install-swtpm.sh;
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Compiler version
|
||||||
|
run: $CC --version
|
||||||
|
|
||||||
|
- name: Compile
|
||||||
|
run: CC="$CC" VARIANT="$VARIANT" ./build.sh
|
98
.travis.yml
Normal file
98
.travis.yml
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
# Copyright (c) 2017-2021 Petr Vorel <pvorel@suse.cz>
|
||||||
|
|
||||||
|
dist: bionic
|
||||||
|
language: C
|
||||||
|
services:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
# 32 bit build
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=debian:stable VARIANT=i386 ARCH=i386 TSS=tpm2-tss COMPILE_SSL=openssl-3.0.0-beta1
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
# cross compilation builds
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=debian:stable VARIANT=cross-compile ARCH=ppc64el TSS=ibmtss
|
||||||
|
compiler: powerpc64le-linux-gnu-gcc
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=debian:stable VARIANT=cross-compile ARCH=arm64 TSS=tpm2-tss
|
||||||
|
compiler: aarch64-linux-gnu-gcc
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=debian:stable VARIANT=cross-compile ARCH=s390x TSS=ibmtss
|
||||||
|
compiler: s390x-linux-gnu-gcc
|
||||||
|
|
||||||
|
# musl
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=alpine:latest TSS=tpm2-tss CONTAINER=podman CONTAINER_ARGS="--runtime=/usr/bin/crun --network=host"
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
# glibc (gcc/clang)
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=opensuse/tumbleweed TSS=ibmtss CONTAINER=podman CONTAINER_ARGS="--runtime=/usr/bin/crun --network=host" COMPILE_SSL=openssl-3.0.0-beta1
|
||||||
|
compiler: clang
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=opensuse/leap TSS=tpm2-tss
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=ubuntu:groovy TSS=ibmtss COMPILE_SSL=openssl-3.0.0-beta1
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=ubuntu:xenial TSS=tpm2-tss
|
||||||
|
compiler: clang
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=fedora:latest TSS=ibmtss CONTAINER=podman CONTAINER_ARGS="--runtime=/usr/bin/crun --network=host"
|
||||||
|
compiler: clang
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=centos:7 TSS=tpm2-tss
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=centos:latest TSS=tpm2-tss
|
||||||
|
compiler: clang
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=debian:testing TSS=tpm2-tss
|
||||||
|
compiler: clang
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: DISTRO=debian:stable TSS=ibmtss
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
- os: linux
|
||||||
|
env: REPO="docker.io/library/" DISTRO=${REPO}alt:sisyphus TSS=libtpm2-tss-devel CONTAINER=podman CONTAINER_ARGS="--runtime=/usr/bin/crun --network=host"
|
||||||
|
compiler: gcc
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
# Tumbleweed requires podman due docker incompatible with glibc 2.33
|
||||||
|
# (faccessat2) and crun (for clone3).
|
||||||
|
- CONTAINER="${CONTAINER:-docker}"
|
||||||
|
- >
|
||||||
|
if [ "$CONTAINER" = "podman" ]; then
|
||||||
|
# podman
|
||||||
|
. /etc/os-release
|
||||||
|
sudo sh -c "echo 'deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list"
|
||||||
|
wget -nv https://download.opensuse.org/repositories/devel:kubic:libcontainers:stable/xUbuntu_${VERSION_ID}/Release.key -O- | sudo apt-key add -
|
||||||
|
sudo apt update
|
||||||
|
sudo apt -y install podman slirp4netns crun
|
||||||
|
fi
|
||||||
|
- $CONTAINER info
|
||||||
|
|
||||||
|
- DIR="/usr/src/ima-evm-utils"
|
||||||
|
- printf "FROM $DISTRO\nRUN mkdir -p $DIR\nWORKDIR $DIR\nCOPY . $DIR\n" > Dockerfile
|
||||||
|
- cat Dockerfile
|
||||||
|
- $CONTAINER build $CONTAINER_ARGS -t ima-evm-utils .
|
||||||
|
|
||||||
|
script:
|
||||||
|
- INSTALL="${DISTRO#${REPO}}"
|
||||||
|
- INSTALL="${INSTALL%%:*}"
|
||||||
|
- INSTALL="${INSTALL%%/*}"
|
||||||
|
- $CONTAINER run $CONTAINER_ARGS -t ima-evm-utils /bin/sh -c "if [ \"$VARIANT\" ]; then ARCH=\"$ARCH\" ./ci/$INSTALL.$VARIANT.sh; fi && ARCH=\"$ARCH\" CC=\"$CC\" TSS=\"$TSS\" ./ci/$INSTALL.sh && if [ "$COMPILE_SSL" ]; then COMPILE_SSL="$COMPILE_SSL" ./tests/install-openssl3.sh; fi && if [ ! \"$VARIANT\" ]; then which tpm_server || which swtpm || if which tssstartup; then ./tests/install-swtpm.sh; fi; fi && CC=\"$CC\" VARIANT=\"$VARIANT\" ./build.sh"
|
27
INSTALL
27
INSTALL
@ -9,10 +9,33 @@ are permitted in any medium without royalty provided the copyright
|
|||||||
notice and this notice are preserved. This file is offered as-is,
|
notice and this notice are preserved. This file is offered as-is,
|
||||||
without warranty of any kind.
|
without warranty of any kind.
|
||||||
|
|
||||||
|
Prerequisites
|
||||||
|
=============
|
||||||
|
|
||||||
|
This project has the following prerequisites:
|
||||||
|
|
||||||
|
(Ubuntu package names)
|
||||||
|
libkeyutils-dev
|
||||||
|
libtasn1-dev
|
||||||
|
libgmp-dev
|
||||||
|
libnspr4-dev
|
||||||
|
libnss3-dev
|
||||||
|
|
||||||
|
These software TPMs are supported:
|
||||||
|
https://sourceforge.net/projects/ibmswtpm2/
|
||||||
|
https://github.com/stefanberger/swtpm
|
||||||
|
|
||||||
|
swtpm depends upon
|
||||||
|
https://github.com/stefanberger/libtpms
|
||||||
|
|
||||||
|
Supported TSSes include these. Both are included in some distros.
|
||||||
|
IBM TSS https://sourceforge.net/projects/ibmtpm20tss/
|
||||||
|
Intel TSS
|
||||||
|
|
||||||
Basic Installation
|
Basic Installation
|
||||||
==================
|
==================
|
||||||
|
|
||||||
Briefly, the shell commands `./configure; make; make install' should
|
Briefly, the shell commands `autoreconf -i; ./configure; make; make install' should
|
||||||
configure, build, and install this package. The following
|
configure, build, and install this package. The following
|
||||||
more-detailed instructions are generic; see the `README' file for
|
more-detailed instructions are generic; see the `README' file for
|
||||||
instructions specific to this package. Some packages provide this
|
instructions specific to this package. Some packages provide this
|
||||||
@ -51,7 +74,7 @@ of `autoconf'.
|
|||||||
The simplest way to compile this package is:
|
The simplest way to compile this package is:
|
||||||
|
|
||||||
1. `cd' to the directory containing the package's source code and type
|
1. `cd' to the directory containing the package's source code and type
|
||||||
`./configure' to configure the package for your system.
|
`autoreconf -i' and then `./configure' to configure the package for your system.
|
||||||
|
|
||||||
Running `configure' might take a while. While running, it prints
|
Running `configure' might take a while. While running, it prints
|
||||||
some messages telling which features it is checking for.
|
some messages telling which features it is checking for.
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
SUBDIRS = src tests
|
SUBDIRS = src tests
|
||||||
|
if MANPAGE_DOCBOOK_XSL
|
||||||
dist_man_MANS = evmctl.1
|
dist_man_MANS = evmctl.1
|
||||||
|
endif
|
||||||
|
|
||||||
doc_DATA = examples/ima-genkey-self.sh examples/ima-genkey.sh examples/ima-gen-local-ca.sh
|
doc_DATA = examples/ima-genkey-self.sh examples/ima-genkey.sh examples/ima-gen-local-ca.sh
|
||||||
EXTRA_DIST = autogen.sh $(doc_DATA)
|
EXTRA_DIST = autogen.sh $(doc_DATA)
|
||||||
@ -23,6 +25,7 @@ rpm: $(tarname)
|
|||||||
cp $(tarname) $(SRCS)/
|
cp $(tarname) $(SRCS)/
|
||||||
rpmbuild -ba --nodeps $(SPEC)
|
rpmbuild -ba --nodeps $(SPEC)
|
||||||
|
|
||||||
|
if MANPAGE_DOCBOOK_XSL
|
||||||
evmctl.1.html: README
|
evmctl.1.html: README
|
||||||
@asciidoc -o $@ $<
|
@asciidoc -o $@ $<
|
||||||
|
|
||||||
@ -35,5 +38,6 @@ rmman:
|
|||||||
rm -f evmctl.1
|
rm -f evmctl.1
|
||||||
|
|
||||||
doc: evmctl.1.html rmman evmctl.1
|
doc: evmctl.1.html rmman evmctl.1
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: $(tarname)
|
.PHONY: $(tarname)
|
||||||
|
29
NEWS
29
NEWS
@ -1,3 +1,32 @@
|
|||||||
|
2021-10-22 Mimi Zohar <zohar@linux.ibm.com>
|
||||||
|
|
||||||
|
version 1.4:
|
||||||
|
* Elliptic curve support and tests
|
||||||
|
* PKCS11 support and tests
|
||||||
|
* Ability to manually specify the keyid included in the IMA xattr
|
||||||
|
* Improve IMA measurement list per TPM bank verification
|
||||||
|
* Linking with IBM TSS
|
||||||
|
* Set default hash algorithm in package configuration
|
||||||
|
* (Minimal) support and test EVM portable signatures
|
||||||
|
* CI testing:
|
||||||
|
* Refresh and include new distros
|
||||||
|
* Podman support
|
||||||
|
* GitHub Actions
|
||||||
|
* Limit "sudo" usage
|
||||||
|
* Misc bug fixes and code cleanup
|
||||||
|
* Fix static analysis bug reports, memory leaks
|
||||||
|
* Remove experimental code that was never upstreamed in the kernel
|
||||||
|
* Use unsigned variable, remove unused variables, etc
|
||||||
|
|
||||||
|
2020-10-28 Mimi Zohar <zohar@linux.ibm.com>
|
||||||
|
|
||||||
|
version 1.3.2:
|
||||||
|
* Bugfixes: importing keys
|
||||||
|
* NEW: Docker based travis distro testing
|
||||||
|
* Travis bugfixes, code cleanup, software version update,
|
||||||
|
and script removal
|
||||||
|
* Initial travis testing
|
||||||
|
|
||||||
2020-08-11 Mimi Zohar <zohar@linux.ibm.com>
|
2020-08-11 Mimi Zohar <zohar@linux.ibm.com>
|
||||||
|
|
||||||
version 1.3.1:
|
version 1.3.1:
|
||||||
|
16
README
16
README
@ -28,6 +28,7 @@ COMMANDS
|
|||||||
import [--rsa] pubkey keyring
|
import [--rsa] pubkey keyring
|
||||||
sign [-r] [--imahash | --imasig ] [--portable] [--key key] [--pass password] file
|
sign [-r] [--imahash | --imasig ] [--portable] [--key key] [--pass password] file
|
||||||
verify file
|
verify file
|
||||||
|
ima_boot_aggregate [--pcrs hash-algorithm,file] [TPM 1.2 BIOS event log]
|
||||||
ima_sign [--sigfile] [--key key] [--pass password] file
|
ima_sign [--sigfile] [--key key] [--pass password] file
|
||||||
ima_verify file
|
ima_verify file
|
||||||
ima_hash file
|
ima_hash file
|
||||||
@ -40,17 +41,21 @@ COMMANDS
|
|||||||
OPTIONS
|
OPTIONS
|
||||||
-------
|
-------
|
||||||
|
|
||||||
-a, --hashalgo sha1 (default), sha224, sha256, sha384, sha512
|
-a, --hashalgo sha1, sha224, sha256, sha384, sha512
|
||||||
-s, --imasig make IMA signature
|
-s, --imasig make IMA signature
|
||||||
-d, --imahash make IMA hash
|
-d, --imahash make IMA hash
|
||||||
-f, --sigfile store IMA signature in .sig file instead of xattr
|
-f, --sigfile store IMA signature in .sig file instead of xattr
|
||||||
--xattr-user store xattrs in user namespace (for testing purposes)
|
--xattr-user store xattrs in user namespace (for testing purposes)
|
||||||
--rsa use RSA key type and signing scheme v1
|
--rsa use RSA key type and signing scheme v1
|
||||||
-k, --key path to signing key (default: /etc/keys/{privkey,pubkey}_evm.pem)
|
-k, --key path to signing key (default: /etc/keys/{privkey,pubkey}_evm.pem)
|
||||||
|
or a pkcs11 URI
|
||||||
|
--keyid n overwrite signature keyid with a 32-bit value in hex (for signing)
|
||||||
|
--keyid-from-cert file
|
||||||
|
read keyid value from SKID of a x509 cert file
|
||||||
-o, --portable generate portable EVM signatures
|
-o, --portable generate portable EVM signatures
|
||||||
-p, --pass password for encrypted signing key
|
-p, --pass password for encrypted signing key
|
||||||
-r, --recursive recurse into directories (sign)
|
-r, --recursive recurse into directories (sign)
|
||||||
-t, --type file types to fix 'fdsxm' (f: file, d: directory, s: block/char/symlink)
|
-t, --type file types to fix 'fxm' (f: file)
|
||||||
x - skip fixing if both ima and evm xattrs exist (use with caution)
|
x - skip fixing if both ima and evm xattrs exist (use with caution)
|
||||||
m - stay on the same filesystem (like 'find -xdev')
|
m - stay on the same filesystem (like 'find -xdev')
|
||||||
-n print result to stdout instead of setting xattr
|
-n print result to stdout instead of setting xattr
|
||||||
@ -66,6 +71,10 @@ OPTIONS
|
|||||||
-v increase verbosity level
|
-v increase verbosity level
|
||||||
-h, --help display this help and exit
|
-h, --help display this help and exit
|
||||||
|
|
||||||
|
Environment variables:
|
||||||
|
|
||||||
|
EVMCTL_KEY_PASSWORD : Private key password to use; do not use --pass option
|
||||||
|
|
||||||
|
|
||||||
INTRODUCTION
|
INTRODUCTION
|
||||||
------------
|
------------
|
||||||
@ -124,6 +133,9 @@ for signing and importing the key.
|
|||||||
Second key format uses X509 DER encoded public key certificates and uses asymmetric key support
|
Second key format uses X509 DER encoded public key certificates and uses asymmetric key support
|
||||||
in the kernel (since kernel 3.9). CONFIG_INTEGRITY_ASYMMETRIC_KEYS must be enabled (default).
|
in the kernel (since kernel 3.9). CONFIG_INTEGRITY_ASYMMETRIC_KEYS must be enabled (default).
|
||||||
|
|
||||||
|
For v2 signatures x509 certificate (containing the public key) could be appended to the
|
||||||
|
private key (they both are in PEM format) to automatically extract keyid from its Subject
|
||||||
|
Key Identifier (SKID).
|
||||||
|
|
||||||
Integrity keyrings
|
Integrity keyrings
|
||||||
----------------
|
----------------
|
||||||
|
14
autogen.sh
14
autogen.sh
@ -1,16 +1,4 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# new way
|
autoreconf -i
|
||||||
# strange, but need this for Makefile.am, because it has -I m4
|
|
||||||
test -d m4 || mkdir m4
|
|
||||||
autoreconf -f -i
|
|
||||||
|
|
||||||
# old way
|
|
||||||
#libtoolize --automake --copy --force
|
|
||||||
#aclocal
|
|
||||||
#autoconf --force
|
|
||||||
#autoheader --force
|
|
||||||
#automake --add-missing --copy --force-missing --gnu
|
|
||||||
|
|
||||||
|
105
build.sh
Executable file
105
build.sh
Executable file
@ -0,0 +1,105 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CC="${CC:-gcc}"
|
||||||
|
CFLAGS="${CFLAGS:--Wformat -Werror=format-security -Werror=implicit-function-declaration -Werror=return-type -fno-common}"
|
||||||
|
PREFIX="${PREFIX:-$HOME/ima-evm-utils-install}"
|
||||||
|
|
||||||
|
export LD_LIBRARY_PATH="$PREFIX/lib64:$PREFIX/lib:/usr/local/lib64:/usr/local/lib"
|
||||||
|
export PATH="$PREFIX/bin:/usr/local/bin:$PATH"
|
||||||
|
|
||||||
|
title()
|
||||||
|
{
|
||||||
|
echo "===== $1 ====="
|
||||||
|
}
|
||||||
|
|
||||||
|
log_exit()
|
||||||
|
{
|
||||||
|
local ret="${3:-$?}"
|
||||||
|
local log="$1"
|
||||||
|
local msg="$2"
|
||||||
|
local prefix
|
||||||
|
|
||||||
|
echo "=== $log ==="
|
||||||
|
[ $ret -eq 0 ] || prefix="FAIL: "
|
||||||
|
cat $log
|
||||||
|
echo
|
||||||
|
echo "$prefix$msg, see output of $log above"
|
||||||
|
exit $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
cd `dirname $0`
|
||||||
|
|
||||||
|
case "$VARIANT" in
|
||||||
|
i386)
|
||||||
|
echo "32-bit compilation"
|
||||||
|
export CFLAGS="-m32 $CFLAGS" LDFLAGS="-m32 $LDFLAGS"
|
||||||
|
export PKG_CONFIG_LIBDIR=/usr/lib/i386-linux-gnu/pkgconfig
|
||||||
|
;;
|
||||||
|
cross-compile)
|
||||||
|
host="${CC%-gcc}"
|
||||||
|
export CROSS_COMPILE="${host}-"
|
||||||
|
host="--host=$host"
|
||||||
|
echo "cross compilation: $host"
|
||||||
|
echo "CROSS_COMPILE: '$CROSS_COMPILE'"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [ "$VARIANT" ]; then
|
||||||
|
echo "Wrong VARIANT: '$VARIANT'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "native build"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
title "compiler version"
|
||||||
|
$CC --version
|
||||||
|
echo "CFLAGS: '$CFLAGS'"
|
||||||
|
echo "LDFLAGS: '$LDFLAGS'"
|
||||||
|
echo "PREFIX: '$PREFIX'"
|
||||||
|
|
||||||
|
title "configure"
|
||||||
|
./autogen.sh
|
||||||
|
./configure --prefix=$PREFIX $host || log_exit config.log "configure failed"
|
||||||
|
|
||||||
|
title "make"
|
||||||
|
make -j$(nproc)
|
||||||
|
make install
|
||||||
|
|
||||||
|
title "test"
|
||||||
|
if [ "$VARIANT" = "cross-compile" ]; then
|
||||||
|
echo "skip make check on cross compilation"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
ret=0
|
||||||
|
VERBOSE=1 make check || ret=$?
|
||||||
|
|
||||||
|
title "logs"
|
||||||
|
if [ $ret -eq 0 ]; then
|
||||||
|
if [ -f tests/ima_hash.log ]; then
|
||||||
|
tail -3 tests/ima_hash.log
|
||||||
|
grep "skipped" tests/ima_hash.log && \
|
||||||
|
grep "skipped" tests/ima_hash.log | wc -l
|
||||||
|
fi
|
||||||
|
if [ -f tests/sign_verify.log ]; then
|
||||||
|
tail -3 tests/sign_verify.log
|
||||||
|
grep "skipped" tests/sign_verify.log && \
|
||||||
|
grep "skipped" tests/sign_verify.log | wc -l
|
||||||
|
fi
|
||||||
|
tail -20 tests/boot_aggregate.log
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat tests/test-suite.log
|
||||||
|
|
||||||
|
if [ $ret -eq 77 ]; then
|
||||||
|
msg="WARN: some tests skipped"
|
||||||
|
ret=0
|
||||||
|
else
|
||||||
|
msg="FAIL: tests exited: $ret"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log_exit tests/test-suite.log "$msg" $ret
|
50
ci/alpine.sh
Executable file
50
ci/alpine.sh
Executable file
@ -0,0 +1,50 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
if [ -z "$CC" ]; then
|
||||||
|
echo "missing \$CC!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$TSS" in
|
||||||
|
ibmtss) echo "No IBM TSS package, will be installed from git" >&2; TSS=;;
|
||||||
|
tpm2-tss) TSS="tpm2-tss-dev";;
|
||||||
|
'') echo "Missing TSS!" >&2; exit 1;;
|
||||||
|
*) echo "Unsupported TSS: '$TSS'!" >&2; exit 1;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# ibmswtpm2 requires gcc
|
||||||
|
[ "$CC" = "gcc" ] || CC="gcc $CC"
|
||||||
|
|
||||||
|
apk update
|
||||||
|
|
||||||
|
apk add \
|
||||||
|
$CC $TSS \
|
||||||
|
asciidoc \
|
||||||
|
attr \
|
||||||
|
attr-dev \
|
||||||
|
autoconf \
|
||||||
|
automake \
|
||||||
|
diffutils \
|
||||||
|
docbook-xml \
|
||||||
|
docbook-xsl \
|
||||||
|
keyutils-dev \
|
||||||
|
libtool \
|
||||||
|
libxslt \
|
||||||
|
linux-headers \
|
||||||
|
make \
|
||||||
|
musl-dev \
|
||||||
|
openssl \
|
||||||
|
openssl-dev \
|
||||||
|
pkgconfig \
|
||||||
|
procps \
|
||||||
|
sudo \
|
||||||
|
wget \
|
||||||
|
which \
|
||||||
|
xxd
|
||||||
|
|
||||||
|
if [ ! "$TSS" ]; then
|
||||||
|
apk add git
|
||||||
|
../tests/install-tss.sh
|
||||||
|
fi
|
27
ci/alt.sh
Executable file
27
ci/alt.sh
Executable file
@ -0,0 +1,27 @@
|
|||||||
|
#!/bin/sh -ex
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#
|
||||||
|
# Install build env for ALT Linux
|
||||||
|
|
||||||
|
apt-get update -y
|
||||||
|
|
||||||
|
# rpm-build brings basic build environment with gcc, make, autotools, etc.
|
||||||
|
apt-get install -y \
|
||||||
|
$CC \
|
||||||
|
$TSS \
|
||||||
|
asciidoc \
|
||||||
|
attr \
|
||||||
|
docbook-style-xsl \
|
||||||
|
gnutls-utils \
|
||||||
|
libattr-devel \
|
||||||
|
libkeyutils-devel \
|
||||||
|
libp11 \
|
||||||
|
libssl-devel \
|
||||||
|
openssl \
|
||||||
|
openssl-gost-engine \
|
||||||
|
rpm-build \
|
||||||
|
softhsm \
|
||||||
|
wget \
|
||||||
|
xsltproc \
|
||||||
|
xxd \
|
||||||
|
&& control openssl-gost enabled
|
1
ci/centos.sh
Symbolic link
1
ci/centos.sh
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
fedora.sh
|
23
ci/debian.cross-compile.sh
Executable file
23
ci/debian.cross-compile.sh
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
if [ -z "$ARCH" ]; then
|
||||||
|
echo "missing \$ARCH!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$ARCH" in
|
||||||
|
arm64) gcc_arch="aarch64";;
|
||||||
|
ppc64el) gcc_arch="powerpc64le";;
|
||||||
|
s390x) gcc_arch="$ARCH";;
|
||||||
|
*) echo "unsupported arch: '$ARCH'!" >&2; exit 1;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
dpkg --add-architecture $ARCH
|
||||||
|
apt update
|
||||||
|
|
||||||
|
apt install -y --no-install-recommends \
|
||||||
|
dpkg-dev \
|
||||||
|
gcc-${gcc_arch}-linux-gnu \
|
||||||
|
libc6-dev-${ARCH}-cross
|
11
ci/debian.i386.sh
Executable file
11
ci/debian.i386.sh
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
dpkg --add-architecture i386
|
||||||
|
apt update
|
||||||
|
|
||||||
|
apt install -y --no-install-recommends \
|
||||||
|
linux-libc-dev:i386 \
|
||||||
|
gcc-multilib \
|
||||||
|
pkg-config:i386
|
55
ci/debian.sh
Executable file
55
ci/debian.sh
Executable file
@ -0,0 +1,55 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
if [ -z "$CC" ]; then
|
||||||
|
echo "missing \$CC!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# debian.*.sh must be run first
|
||||||
|
if [ "$ARCH" ]; then
|
||||||
|
ARCH=":$ARCH"
|
||||||
|
unset CC
|
||||||
|
else
|
||||||
|
apt update
|
||||||
|
fi
|
||||||
|
|
||||||
|
# ibmswtpm2 requires gcc
|
||||||
|
[ "$CC" = "gcc" ] || CC="gcc $CC"
|
||||||
|
|
||||||
|
case "$TSS" in
|
||||||
|
ibmtss) TSS="libtss-dev";;
|
||||||
|
tpm2-tss) TSS="libtss2-dev";;
|
||||||
|
'') echo "Missing TSS!" >&2; exit 1;;
|
||||||
|
*) [ "$TSS" ] && echo "Unsupported TSS: '$TSS'!" >&2; exit 1;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
apt="apt install -y --no-install-recommends"
|
||||||
|
|
||||||
|
$apt \
|
||||||
|
$CC $TSS \
|
||||||
|
asciidoc \
|
||||||
|
attr \
|
||||||
|
autoconf \
|
||||||
|
automake \
|
||||||
|
diffutils \
|
||||||
|
debianutils \
|
||||||
|
docbook-xml \
|
||||||
|
docbook-xsl \
|
||||||
|
gzip \
|
||||||
|
libattr1-dev$ARCH \
|
||||||
|
libkeyutils-dev$ARCH \
|
||||||
|
libssl-dev$ARCH \
|
||||||
|
libtool \
|
||||||
|
make \
|
||||||
|
openssl \
|
||||||
|
pkg-config \
|
||||||
|
procps \
|
||||||
|
sudo \
|
||||||
|
wget \
|
||||||
|
xsltproc
|
||||||
|
|
||||||
|
$apt xxd || $apt vim-common
|
||||||
|
$apt libengine-gost-openssl1.1$ARCH || true
|
||||||
|
$apt softhsm gnutls-bin libengine-pkcs11-openssl1.1$ARCH || true
|
52
ci/fedora.sh
Executable file
52
ci/fedora.sh
Executable file
@ -0,0 +1,52 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$CC" ]; then
|
||||||
|
echo "missing \$CC!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$TSS" in
|
||||||
|
ibmtss) TSS="tss2-devel";;
|
||||||
|
tpm2-tss) TSS="tpm2-tss-devel";;
|
||||||
|
'') echo "Missing TSS!" >&2; exit 1;;
|
||||||
|
*) echo "Unsupported TSS: '$TSS'!" >&2; exit 1;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# ibmswtpm2 requires gcc
|
||||||
|
[ "$CC" = "gcc" ] || CC="gcc $CC"
|
||||||
|
|
||||||
|
yum -y install \
|
||||||
|
$CC $TSS \
|
||||||
|
asciidoc \
|
||||||
|
attr \
|
||||||
|
autoconf \
|
||||||
|
automake \
|
||||||
|
diffutils \
|
||||||
|
docbook-xsl \
|
||||||
|
gnutls-utils \
|
||||||
|
gzip \
|
||||||
|
keyutils-libs-devel \
|
||||||
|
libattr-devel \
|
||||||
|
libtool \
|
||||||
|
libxslt \
|
||||||
|
make \
|
||||||
|
openssl \
|
||||||
|
openssl-devel \
|
||||||
|
openssl-pkcs11 \
|
||||||
|
pkg-config \
|
||||||
|
procps \
|
||||||
|
sudo \
|
||||||
|
vim-common \
|
||||||
|
wget \
|
||||||
|
which
|
||||||
|
|
||||||
|
yum -y install docbook5-style-xsl || true
|
||||||
|
yum -y install swtpm || true
|
||||||
|
|
||||||
|
# SoftHSM is available via EPEL on CentOS
|
||||||
|
if [ -f /etc/centos-release ]; then
|
||||||
|
yum -y install epel-release
|
||||||
|
fi
|
||||||
|
yum -y install softhsm || true
|
1
ci/opensuse.sh
Symbolic link
1
ci/opensuse.sh
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
tumbleweed.sh
|
50
ci/tumbleweed.sh
Executable file
50
ci/tumbleweed.sh
Executable file
@ -0,0 +1,50 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright (c) 2020 Petr Vorel <pvorel@suse.cz>
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
if [ -z "$CC" ]; then
|
||||||
|
echo "missing \$CC!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$TSS" in
|
||||||
|
ibmtss) TSS="ibmtss-devel";;
|
||||||
|
tpm2-tss) TSS="tpm2-0-tss-devel";;
|
||||||
|
'') echo "Missing TSS!" >&2; exit 1;;
|
||||||
|
*) echo "Unsupported TSS: '$TSS'!" >&2; exit 1;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# clang has some gcc dependency
|
||||||
|
[ "$CC" = "gcc" ] || CC="gcc $CC"
|
||||||
|
|
||||||
|
zypper --non-interactive install --force-resolution --no-recommends \
|
||||||
|
$CC $TSS \
|
||||||
|
asciidoc \
|
||||||
|
attr \
|
||||||
|
autoconf \
|
||||||
|
automake \
|
||||||
|
diffutils \
|
||||||
|
docbook_5 \
|
||||||
|
docbook5-xsl-stylesheets \
|
||||||
|
gzip \
|
||||||
|
ibmswtpm2 \
|
||||||
|
keyutils-devel \
|
||||||
|
libattr-devel \
|
||||||
|
libopenssl-devel \
|
||||||
|
libtool \
|
||||||
|
make \
|
||||||
|
openssl \
|
||||||
|
pkg-config \
|
||||||
|
procps \
|
||||||
|
sudo \
|
||||||
|
vim \
|
||||||
|
wget \
|
||||||
|
which \
|
||||||
|
xsltproc
|
||||||
|
|
||||||
|
zypper --non-interactive install --force-resolution --no-recommends \
|
||||||
|
gnutls openssl-engine-libp11 softhsm || true
|
||||||
|
|
||||||
|
if [ -f /usr/lib/ibmtss/tpm_server -a ! -e /usr/local/bin/tpm_server ]; then
|
||||||
|
ln -s /usr/lib/ibmtss/tpm_server /usr/local/bin
|
||||||
|
fi
|
1
ci/ubuntu.sh
Symbolic link
1
ci/ubuntu.sh
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
debian.sh
|
17
configure.ac
17
configure.ac
@ -1,7 +1,7 @@
|
|||||||
# autoconf script
|
# autoconf script
|
||||||
|
|
||||||
AC_PREREQ([2.65])
|
AC_PREREQ([2.65])
|
||||||
AC_INIT(ima-evm-utils, 1.3.1, zohar@linux.ibm.com)
|
AC_INIT(ima-evm-utils, 1.4, zohar@linux.ibm.com)
|
||||||
AM_INIT_AUTOMAKE([foreign])
|
AM_INIT_AUTOMAKE([foreign])
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_MACRO_DIR([m4])
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
@ -30,9 +30,14 @@ AC_SUBST(KERNEL_HEADERS)
|
|||||||
AC_CHECK_HEADER(unistd.h)
|
AC_CHECK_HEADER(unistd.h)
|
||||||
AC_CHECK_HEADERS(openssl/conf.h)
|
AC_CHECK_HEADERS(openssl/conf.h)
|
||||||
|
|
||||||
AC_CHECK_LIB([tss2-esys], [Esys_PCR_Read])
|
# Intel TSS
|
||||||
|
AC_CHECK_LIB([tss2-esys], [Esys_Free])
|
||||||
AC_CHECK_LIB([tss2-rc], [Tss2_RC_Decode])
|
AC_CHECK_LIB([tss2-rc], [Tss2_RC_Decode])
|
||||||
AM_CONDITIONAL([USE_PCRTSS], [test "x$ac_cv_lib_tss2_esys_Esys_PCR_Read" = "xyes"])
|
AM_CONDITIONAL([USE_PCRTSS], [test "x$ac_cv_lib_tss2_esys_Esys_Free" = "xyes"])
|
||||||
|
|
||||||
|
# IBM TSS include files
|
||||||
|
AC_CHECK_HEADER(ibmtss/tss.h, [], [], [[#define TPM_POSIX]])
|
||||||
|
AM_CONDITIONAL([USE_IBMTSS], [test "x$ac_cv_header_ibmtss_tss_h" = "xyes"])
|
||||||
|
|
||||||
AC_CHECK_HEADERS(sys/xattr.h, , [AC_MSG_ERROR([sys/xattr.h header not found. You need the c-library development package.])])
|
AC_CHECK_HEADERS(sys/xattr.h, , [AC_MSG_ERROR([sys/xattr.h header not found. You need the c-library development package.])])
|
||||||
AC_CHECK_HEADERS(keyutils.h, , [AC_MSG_ERROR([keyutils.h header not found. You need the libkeyutils development package.])])
|
AC_CHECK_HEADERS(keyutils.h, , [AC_MSG_ERROR([keyutils.h header not found. You need the libkeyutils development package.])])
|
||||||
@ -57,6 +62,7 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
EVMCTL_MANPAGE_DOCBOOK_XSL
|
EVMCTL_MANPAGE_DOCBOOK_XSL
|
||||||
|
AX_DEFAULT_HASH_ALGO([$KERNEL_HEADERS])
|
||||||
|
|
||||||
# for gcov
|
# for gcov
|
||||||
#CFLAGS="$CFLAGS -Wall -fprofile-arcs -ftest-coverage"
|
#CFLAGS="$CFLAGS -Wall -fprofile-arcs -ftest-coverage"
|
||||||
@ -76,7 +82,10 @@ echo
|
|||||||
echo
|
echo
|
||||||
echo "Configuration:"
|
echo "Configuration:"
|
||||||
echo " debug: $pkg_cv_enable_debug"
|
echo " debug: $pkg_cv_enable_debug"
|
||||||
|
echo " default-hash: $HASH_ALGO"
|
||||||
echo " openssl-conf: $enable_openssl_conf"
|
echo " openssl-conf: $enable_openssl_conf"
|
||||||
echo " tss2-esys: $ac_cv_lib_tss2_esys_Esys_PCR_Read"
|
echo " tss2-esys: $ac_cv_lib_tss2_esys_Esys_Free"
|
||||||
echo " tss2-rc-decode: $ac_cv_lib_tss2_rc_Tss2_RC_Decode"
|
echo " tss2-rc-decode: $ac_cv_lib_tss2_rc_Tss2_RC_Decode"
|
||||||
|
echo " ibmtss: $ac_cv_header_ibmtss_tss_h"
|
||||||
|
echo " doc: $have_doc"
|
||||||
echo
|
echo
|
||||||
|
36
m4/default-hash-algo.m4
Normal file
36
m4/default-hash-algo.m4
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
dnl Copyright (c) 2021 Bruno Meneguele <bmeneg@redhat.com>
|
||||||
|
dnl Check hash algorithm availability in the kernel
|
||||||
|
dnl
|
||||||
|
dnl $1 - $KERNEL_HEADERS
|
||||||
|
|
||||||
|
AC_DEFUN([AX_DEFAULT_HASH_ALGO], [
|
||||||
|
HASH_INFO_HEADER="$1/include/uapi/linux/hash_info.h"
|
||||||
|
|
||||||
|
AC_ARG_WITH([default_hash],
|
||||||
|
AS_HELP_STRING([--with-default-hash=ALGORITHM], [specifies the default hash algorithm to be used]),
|
||||||
|
[HASH_ALGO=$withval],
|
||||||
|
[HASH_ALGO=sha256])
|
||||||
|
|
||||||
|
AC_PROG_SED()
|
||||||
|
HASH_ALGO="$(echo $HASH_ALGO | $SED 's/\(.*\)/\L\1\E/')"
|
||||||
|
|
||||||
|
AC_CHECK_HEADER([$HASH_INFO_HEADER],
|
||||||
|
[HAVE_HASH_INFO_HEADER=yes],
|
||||||
|
[AC_MSG_WARN([$HASH_INFO_HEADER not found.])])
|
||||||
|
|
||||||
|
if test "x$HAVE_HASH_INFO_HEADER" = "x"; then
|
||||||
|
AC_MSG_RESULT([using $HASH_ALGO algorithm as default hash algorith])
|
||||||
|
AC_DEFINE_UNQUOTED(DEFAULT_HASH_ALGO, "$HASH_ALGO", [Define default hash algorithm])
|
||||||
|
else
|
||||||
|
AC_PROG_GREP()
|
||||||
|
$SED -n 's/HASH_ALGO_\(.*\),/\L\1\E/p' $HASH_INFO_HEADER | $GREP -w $HASH_ALGO > /dev/null
|
||||||
|
have_hash=$?
|
||||||
|
|
||||||
|
if test $have_hash -ne 0; then
|
||||||
|
AC_MSG_ERROR([$HASH_ALGO algorithm specified, but not provided by the kernel], 1)
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([using $HASH_ALGO as default hash algorithm])
|
||||||
|
AC_DEFINE_UNQUOTED(DEFAULT_HASH_ALGO, "$HASH_ALGO", [Define default hash algorithm])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
])
|
@ -1,7 +1,10 @@
|
|||||||
dnl Copyright (c) 2018 Petr Vorel <pvorel@suse.cz>
|
dnl Copyright (c) 2018-2020 Petr Vorel <pvorel@suse.cz>
|
||||||
dnl Find docbook manpage stylesheet
|
dnl Find docbook manpage stylesheet
|
||||||
|
|
||||||
AC_DEFUN([EVMCTL_MANPAGE_DOCBOOK_XSL], [
|
AC_DEFUN([EVMCTL_MANPAGE_DOCBOOK_XSL], [
|
||||||
|
DOCBOOK_XSL_URI="http://docbook.sourceforge.net/release/xsl/current"
|
||||||
|
DOCBOOK_XSL_PATH="manpages/docbook.xsl"
|
||||||
|
|
||||||
AC_PATH_PROGS(XMLCATALOG, xmlcatalog)
|
AC_PATH_PROGS(XMLCATALOG, xmlcatalog)
|
||||||
AC_ARG_WITH([xml-catalog],
|
AC_ARG_WITH([xml-catalog],
|
||||||
AC_HELP_STRING([--with-xml-catalog=CATALOG],
|
AC_HELP_STRING([--with-xml-catalog=CATALOG],
|
||||||
@ -9,20 +12,37 @@ AC_DEFUN([EVMCTL_MANPAGE_DOCBOOK_XSL], [
|
|||||||
[with_xml_catalog=/etc/xml/catalog])
|
[with_xml_catalog=/etc/xml/catalog])
|
||||||
XML_CATALOG_FILE="$with_xml_catalog"
|
XML_CATALOG_FILE="$with_xml_catalog"
|
||||||
AC_SUBST([XML_CATALOG_FILE])
|
AC_SUBST([XML_CATALOG_FILE])
|
||||||
|
|
||||||
|
if test "x${XMLCATALOG}" = "x"; then
|
||||||
|
AC_MSG_WARN([xmlcatalog not found, cannot search for $DOCBOOK_XSL_PATH])
|
||||||
|
else
|
||||||
AC_MSG_CHECKING([for XML catalog ($XML_CATALOG_FILE)])
|
AC_MSG_CHECKING([for XML catalog ($XML_CATALOG_FILE)])
|
||||||
if test -f "$XML_CATALOG_FILE"; then
|
if test -f "$XML_CATALOG_FILE"; then
|
||||||
have_xmlcatalog_file=yes
|
have_xmlcatalog_file=yes
|
||||||
AC_MSG_RESULT([found])
|
AC_MSG_RESULT([found])
|
||||||
else
|
else
|
||||||
AC_MSG_RESULT([not found])
|
AC_MSG_RESULT([not found, cannot search for $DOCBOOK_XSL_PATH])
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
if test "x${XMLCATALOG}" != "x" -a "x$have_xmlcatalog_file" = "xyes"; then
|
if test "x${XMLCATALOG}" != "x" -a "x$have_xmlcatalog_file" = "xyes"; then
|
||||||
DOCBOOK_XSL_URI="http://docbook.sourceforge.net/release/xsl/current"
|
MANPAGE_DOCBOOK_XSL=$(${XMLCATALOG} ${XML_CATALOG_FILE} ${DOCBOOK_XSL_URI}/${DOCBOOK_XSL_PATH} | sed 's|^file:/\+|/|')
|
||||||
DOCBOOK_XSL_PATH="manpages/docbook.xsl"
|
|
||||||
MANPAGE_DOCBOOK_XSL=$(${XMLCATALOG} ${XML_CATALOG_FILE} ${DOCBOOK_XSL_URI}/${DOCBOOK_XSL_PATH} | sed -n 's|^file:/\+|/|p;q')
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "x${MANPAGE_DOCBOOK_XSL}" = "x"; then
|
if test "x${MANPAGE_DOCBOOK_XSL}" = "x"; then
|
||||||
MANPAGE_DOCBOOK_XSL="/usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl"
|
MANPAGE_DOCBOOK_XSL="/usr/share/xml/docbook/stylesheet/docbook-xsl/manpages/docbook.xsl"
|
||||||
|
AC_MSG_WARN([trying a default path for $DOCBOOK_XSL_PATH])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test -f "$MANPAGE_DOCBOOK_XSL"; then
|
||||||
|
have_doc=yes
|
||||||
|
AC_MSG_NOTICE([using $MANPAGE_DOCBOOK_XSL for generating doc])
|
||||||
|
else
|
||||||
|
AC_MSG_WARN([$DOCBOOK_XSL_PATH not found, generating doc will be skipped])
|
||||||
|
MANPAGE_DOCBOOK_XSL=
|
||||||
|
have_doc=no
|
||||||
|
fi
|
||||||
|
AM_CONDITIONAL(MANPAGE_DOCBOOK_XSL, test "x$have_doc" = xyes)
|
||||||
|
|
||||||
AC_SUBST(MANPAGE_DOCBOOK_XSL)
|
AC_SUBST(MANPAGE_DOCBOOK_XSL)
|
||||||
])
|
])
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Name: ima-evm-utils
|
Name: ima-evm-utils
|
||||||
Version: 1.3.1
|
Version: 1.4
|
||||||
Release: 1%{?dist}
|
Release: 1%{?dist}
|
||||||
Summary: ima-evm-utils - IMA/EVM control utility
|
Summary: ima-evm-utils - IMA/EVM control utility
|
||||||
Group: System/Libraries
|
Group: System/Libraries
|
||||||
|
1
src/.gitignore
vendored
1
src/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
hash_info.h
|
hash_info.h
|
||||||
|
tmp_hash_info.h
|
||||||
|
@ -4,7 +4,7 @@ libimaevm_la_SOURCES = libimaevm.c
|
|||||||
libimaevm_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCRYPTO_CFLAGS)
|
libimaevm_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCRYPTO_CFLAGS)
|
||||||
# current[:revision[:age]]
|
# current[:revision[:age]]
|
||||||
# result: [current-age].age.revision
|
# result: [current-age].age.revision
|
||||||
libimaevm_la_LDFLAGS = -version-info 2:0:0
|
libimaevm_la_LDFLAGS = -version-info 3:0:0
|
||||||
libimaevm_la_LIBADD = $(LIBCRYPTO_LIBS)
|
libimaevm_la_LIBADD = $(LIBCRYPTO_LIBS)
|
||||||
|
|
||||||
include_HEADERS = imaevm.h
|
include_HEADERS = imaevm.h
|
||||||
@ -22,10 +22,21 @@ evmctl_CPPFLAGS = $(AM_CPPFLAGS) $(LIBCRYPTO_CFLAGS)
|
|||||||
evmctl_LDFLAGS = $(LDFLAGS_READLINE)
|
evmctl_LDFLAGS = $(LDFLAGS_READLINE)
|
||||||
evmctl_LDADD = $(LIBCRYPTO_LIBS) -lkeyutils libimaevm.la
|
evmctl_LDADD = $(LIBCRYPTO_LIBS) -lkeyutils libimaevm.la
|
||||||
|
|
||||||
|
# USE_PCRTSS uses the Intel TSS
|
||||||
if USE_PCRTSS
|
if USE_PCRTSS
|
||||||
evmctl_SOURCES += pcr_tss.c
|
evmctl_SOURCES += pcr_tss.c
|
||||||
|
|
||||||
|
# USE_IBMTSS uses the IBM TSS
|
||||||
|
else
|
||||||
|
if USE_IBMTSS
|
||||||
|
evmctl_SOURCES += pcr_ibmtss.c
|
||||||
|
evmctl_LDADD += -libmtss
|
||||||
|
|
||||||
|
# uses the IBM TSS command line utilities
|
||||||
else
|
else
|
||||||
evmctl_SOURCES += pcr_tsspcrread.c
|
evmctl_SOURCES += pcr_tsspcrread.c
|
||||||
|
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
AM_CPPFLAGS = -I$(top_srcdir) -include config.h
|
AM_CPPFLAGS = -I$(top_srcdir) -include config.h
|
||||||
|
235
src/evmctl.c
235
src/evmctl.c
@ -42,6 +42,7 @@
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -57,12 +58,14 @@
|
|||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include <openssl/asn1.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/hmac.h>
|
#include <openssl/hmac.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
#include <openssl/engine.h>
|
#include <openssl/engine.h>
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
#include "hash_info.h"
|
#include "hash_info.h"
|
||||||
#include "pcr.h"
|
#include "pcr.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
@ -125,6 +128,7 @@ static char *caps_str;
|
|||||||
static char *ima_str;
|
static char *ima_str;
|
||||||
static char *selinux_str;
|
static char *selinux_str;
|
||||||
static char *search_type;
|
static char *search_type;
|
||||||
|
static char *verify_bank;
|
||||||
static int verify_list_sig;
|
static int verify_list_sig;
|
||||||
static int recursive;
|
static int recursive;
|
||||||
static int msize;
|
static int msize;
|
||||||
@ -141,10 +145,6 @@ typedef int (*find_cb_t)(const char *path);
|
|||||||
static int find(const char *path, int dts, find_cb_t func);
|
static int find(const char *path, int dts, find_cb_t func);
|
||||||
|
|
||||||
#define REG_MASK (1 << DT_REG)
|
#define REG_MASK (1 << DT_REG)
|
||||||
#define DIR_MASK (1 << DT_DIR)
|
|
||||||
#define LNK_MASK (1 << DT_LNK)
|
|
||||||
#define CHR_MASK (1 << DT_CHR)
|
|
||||||
#define BLK_MASK (1 << DT_BLK)
|
|
||||||
|
|
||||||
struct command cmds[];
|
struct command cmds[];
|
||||||
static void print_usage(struct command *cmd);
|
static void print_usage(struct command *cmd);
|
||||||
@ -221,7 +221,7 @@ static unsigned char *file2bin(const char *file, const char *ext, int *size)
|
|||||||
fclose(fp);
|
fclose(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (fread(data, len, 1, fp) != len) {
|
if (fread(data, len, 1, fp) != 1) {
|
||||||
log_err("Failed to fread %zu bytes: %s\n", len, name);
|
log_err("Failed to fread %zu bytes: %s\n", len, name);
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
free(data);
|
free(data);
|
||||||
@ -365,9 +365,7 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
|
|||||||
st.st_mode = strtoul(mode_str, NULL, 10);
|
st.st_mode = strtoul(mode_str, NULL, 10);
|
||||||
|
|
||||||
if (!evm_immutable) {
|
if (!evm_immutable) {
|
||||||
if ((S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) && !generation_str) {
|
if (S_ISREG(st.st_mode) && !generation_str) {
|
||||||
/* we cannot at the momement to get generation of
|
|
||||||
special files kernel API does not support it */
|
|
||||||
int fd = open(file, 0);
|
int fd = open(file, 0);
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
@ -404,6 +402,8 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
|
for (xattrname = evm_config_xattrnames; *xattrname != NULL; xattrname++) {
|
||||||
|
int use_xattr_ima = 0;
|
||||||
|
|
||||||
if (!strcmp(*xattrname, XATTR_NAME_SELINUX) && selinux_str) {
|
if (!strcmp(*xattrname, XATTR_NAME_SELINUX) && selinux_str) {
|
||||||
err = strlen(selinux_str) + 1;
|
err = strlen(selinux_str) + 1;
|
||||||
if (err > sizeof(xattr_value)) {
|
if (err > sizeof(xattr_value)) {
|
||||||
@ -420,6 +420,15 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
hex2bin(xattr_value, ima_str, err);
|
hex2bin(xattr_value, ima_str, err);
|
||||||
|
} else if (!strcmp(*xattrname, XATTR_NAME_IMA) && evm_portable){
|
||||||
|
err = lgetxattr(file, xattr_ima, xattr_value,
|
||||||
|
sizeof(xattr_value));
|
||||||
|
if (err < 0) {
|
||||||
|
log_err("EVM portable sig: %s required\n",
|
||||||
|
xattr_ima);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
use_xattr_ima = 1;
|
||||||
} else if (!strcmp(*xattrname, XATTR_NAME_CAPS) && (hmac_flags & HMAC_FLAG_CAPS_SET)) {
|
} else if (!strcmp(*xattrname, XATTR_NAME_CAPS) && (hmac_flags & HMAC_FLAG_CAPS_SET)) {
|
||||||
if (!caps_str)
|
if (!caps_str)
|
||||||
continue;
|
continue;
|
||||||
@ -442,7 +451,8 @@ static int calc_evm_hash(const char *file, unsigned char *hash)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*log_debug("name: %s, value: %s, size: %d\n", *xattrname, xattr_value, err);*/
|
/*log_debug("name: %s, value: %s, size: %d\n", *xattrname, xattr_value, err);*/
|
||||||
log_info("name: %s, size: %d\n", *xattrname, err);
|
log_info("name: %s, size: %d\n",
|
||||||
|
use_xattr_ima ? xattr_ima : *xattrname, err);
|
||||||
log_debug_dump(xattr_value, err);
|
log_debug_dump(xattr_value, err);
|
||||||
err = EVP_DigestUpdate(pctx, xattr_value, err);
|
err = EVP_DigestUpdate(pctx, xattr_value, err);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
@ -655,10 +665,6 @@ static int get_file_type(const char *path, const char *search_type)
|
|||||||
switch (search_type[i]) {
|
switch (search_type[i]) {
|
||||||
case 'f':
|
case 'f':
|
||||||
dts |= REG_MASK; break;
|
dts |= REG_MASK; break;
|
||||||
case 'd':
|
|
||||||
dts |= DIR_MASK; break;
|
|
||||||
case 's':
|
|
||||||
dts |= BLK_MASK | CHR_MASK | LNK_MASK; break;
|
|
||||||
case 'x':
|
case 'x':
|
||||||
check_xattr = true; break;
|
check_xattr = true; break;
|
||||||
case 'm':
|
case 'm':
|
||||||
@ -807,11 +813,20 @@ static int verify_evm(const char *file)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sig[0] != 0x03) {
|
if ((sig[0] != EVM_IMA_XATTR_DIGSIG) &&
|
||||||
|
(sig[0] != EVM_XATTR_PORTABLE_DIGSIG)) {
|
||||||
log_err("%s has no signature\n", xattr_evm);
|
log_err("%s has no signature\n", xattr_evm);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sig[0] == EVM_XATTR_PORTABLE_DIGSIG) {
|
||||||
|
if (sig[1] != DIGSIG_VERSION_2) {
|
||||||
|
log_err("Portable sig: invalid type\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
evm_portable = true;
|
||||||
|
}
|
||||||
|
|
||||||
sig_hash_algo = imaevm_hash_algo_from_sig(sig + 1);
|
sig_hash_algo = imaevm_hash_algo_from_sig(sig + 1);
|
||||||
if (sig_hash_algo < 0) {
|
if (sig_hash_algo < 0) {
|
||||||
log_err("unknown hash algo: %s\n", file);
|
log_err("unknown hash algo: %s\n", file);
|
||||||
@ -1094,6 +1109,7 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
|
|||||||
|
|
||||||
/* EVM key is 128 bytes */
|
/* EVM key is 128 bytes */
|
||||||
memcpy(evmkey, key, keylen);
|
memcpy(evmkey, key, keylen);
|
||||||
|
if (keylen < sizeof(evmkey))
|
||||||
memset(evmkey + keylen, 0, sizeof(evmkey) - keylen);
|
memset(evmkey + keylen, 0, sizeof(evmkey) - keylen);
|
||||||
|
|
||||||
if (lstat(file, &st)) {
|
if (lstat(file, &st)) {
|
||||||
@ -1101,9 +1117,7 @@ static int calc_evm_hmac(const char *file, const char *keyfile, unsigned char *h
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) {
|
if (S_ISREG(st.st_mode)) {
|
||||||
/* we cannot at the momement to get generation of special files..
|
|
||||||
* kernel API does not support it */
|
|
||||||
int fd = open(file, 0);
|
int fd = open(file, 0);
|
||||||
|
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
@ -1349,9 +1363,6 @@ static int find(const char *path, int dts, find_cb_t func)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dts & DIR_MASK)
|
|
||||||
func(path);
|
|
||||||
|
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1594,10 +1605,15 @@ static struct tpm_bank_info *init_tpm_banks(int *num_banks)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Compare the calculated TPM PCR banks against the PCR values read.
|
* Compare the calculated TPM PCR banks against the PCR values read.
|
||||||
|
* The banks_mask parameter allows to select which banks to consider.
|
||||||
|
* A banks_maks of 0x3 would consider banks 1 and 2, 0x2 would only
|
||||||
|
* consider the 2nd bank, ~0 would consider all banks.
|
||||||
|
*
|
||||||
* On failure to match any TPM bank, fail comparison.
|
* On failure to match any TPM bank, fail comparison.
|
||||||
*/
|
*/
|
||||||
static int compare_tpm_banks(int num_banks, struct tpm_bank_info *bank,
|
static int compare_tpm_banks(int num_banks, struct tpm_bank_info *bank,
|
||||||
struct tpm_bank_info *tpm_bank)
|
struct tpm_bank_info *tpm_bank,
|
||||||
|
unsigned int banks_mask, unsigned long entry_num)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -1605,6 +1621,9 @@ static int compare_tpm_banks(int num_banks, struct tpm_bank_info *bank,
|
|||||||
for (i = 0; i < num_banks; i++) {
|
for (i = 0; i < num_banks; i++) {
|
||||||
if (!bank[i].supported || !tpm_bank[i].supported)
|
if (!bank[i].supported || !tpm_bank[i].supported)
|
||||||
continue;
|
continue;
|
||||||
|
/* do we need to look at the n-th bank ? */
|
||||||
|
if ((banks_mask & (1 << i)) == 0)
|
||||||
|
continue;
|
||||||
for (j = 0; j < NUM_PCRS; j++) {
|
for (j = 0; j < NUM_PCRS; j++) {
|
||||||
if (memcmp(bank[i].pcr[j], zero, bank[i].digest_size)
|
if (memcmp(bank[i].pcr[j], zero, bank[i].digest_size)
|
||||||
== 0)
|
== 0)
|
||||||
@ -1625,8 +1644,8 @@ static int compare_tpm_banks(int num_banks, struct tpm_bank_info *bank,
|
|||||||
log_dump(tpm_bank[i].pcr[j], tpm_bank[i].digest_size);
|
log_dump(tpm_bank[i].pcr[j], tpm_bank[i].digest_size);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
log_info("%s PCR-%d: succeed\n",
|
log_info("%s PCR-%d: succeed at entry %lu\n",
|
||||||
bank[i].algo_name, j);
|
bank[i].algo_name, j, entry_num);
|
||||||
else
|
else
|
||||||
log_info("%s: PCRAgg %d does not match TPM PCR-%d\n",
|
log_info("%s: PCRAgg %d does not match TPM PCR-%d\n",
|
||||||
bank[i].algo_name, j, j);
|
bank[i].algo_name, j, j);
|
||||||
@ -1895,7 +1914,8 @@ static int read_tpm_banks(int num_banks, struct tpm_bank_info *bank)
|
|||||||
{
|
{
|
||||||
int tpm_enabled = 0;
|
int tpm_enabled = 0;
|
||||||
char *errmsg = NULL;
|
char *errmsg = NULL;
|
||||||
int i, j;
|
int i;
|
||||||
|
uint32_t pcr_handle;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* If --pcrs was specified, read only from the specified file(s) */
|
/* If --pcrs was specified, read only from the specified file(s) */
|
||||||
@ -1915,9 +1935,12 @@ static int read_tpm_banks(int num_banks, struct tpm_bank_info *bank)
|
|||||||
/* Read PCRs from multiple TPM 2.0 banks */
|
/* Read PCRs from multiple TPM 2.0 banks */
|
||||||
for (i = 0; i < num_banks; i++) {
|
for (i = 0; i < num_banks; i++) {
|
||||||
err = 0;
|
err = 0;
|
||||||
for (j = 0; j < NUM_PCRS && !err; j++) {
|
for (pcr_handle = 0;
|
||||||
err = tpm2_pcr_read(bank[i].algo_name, j,
|
pcr_handle < NUM_PCRS && !err;
|
||||||
bank[i].pcr[j], bank[i].digest_size,
|
pcr_handle++) {
|
||||||
|
err = tpm2_pcr_read(bank[i].algo_name, pcr_handle,
|
||||||
|
bank[i].pcr[pcr_handle],
|
||||||
|
bank[i].digest_size,
|
||||||
&errmsg);
|
&errmsg);
|
||||||
if (err) {
|
if (err) {
|
||||||
log_debug("Failed to read %s PCRs: (%s)\n",
|
log_debug("Failed to read %s PCRs: (%s)\n",
|
||||||
@ -1941,6 +1964,9 @@ static int ima_measurement(const char *file)
|
|||||||
int num_banks = 0;
|
int num_banks = 0;
|
||||||
int tpmbanks = 1;
|
int tpmbanks = 1;
|
||||||
int first_record = 1;
|
int first_record = 1;
|
||||||
|
unsigned int pseudo_padded_banks_mask, pseudo_banks_mask;
|
||||||
|
unsigned long entry_num = 0;
|
||||||
|
int c;
|
||||||
|
|
||||||
struct template_entry entry = { .template = 0 };
|
struct template_entry entry = { .template = 0 };
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@ -1974,7 +2000,27 @@ static int ima_measurement(const char *file)
|
|||||||
if (read_tpm_banks(num_banks, tpm_banks) != 0)
|
if (read_tpm_banks(num_banks, tpm_banks) != 0)
|
||||||
tpmbanks = 0;
|
tpmbanks = 0;
|
||||||
|
|
||||||
while (fread(&entry.header, sizeof(entry.header), 1, fp)) {
|
/* A mask where each bit represents the banks to check against */
|
||||||
|
pseudo_banks_mask = (1 << num_banks) - 1;
|
||||||
|
pseudo_padded_banks_mask = pseudo_banks_mask;
|
||||||
|
|
||||||
|
/* Instead of verifying all the banks, only verify a single bank */
|
||||||
|
for (c = 0; c < num_banks; c++) {
|
||||||
|
if (verify_bank
|
||||||
|
&& strcmp(pseudo_padded_banks[c].algo_name, verify_bank)) {
|
||||||
|
pseudo_banks_mask ^= (1 << c);
|
||||||
|
pseudo_padded_banks_mask ^= (1 << c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fread(&entry.header, sizeof(entry.header), 1, fp) == 1) {
|
||||||
|
entry_num++;
|
||||||
|
if (entry.header.pcr >= NUM_PCRS) {
|
||||||
|
log_err("Invalid PCR %d.\n", entry.header.pcr);
|
||||||
|
fclose(fp);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
if (entry.header.name_len > TCG_EVENT_NAME_LEN_MAX) {
|
if (entry.header.name_len > TCG_EVENT_NAME_LEN_MAX) {
|
||||||
log_err("%d ERROR: event name too long!\n",
|
log_err("%d ERROR: event name too long!\n",
|
||||||
entry.header.name_len);
|
entry.header.name_len);
|
||||||
@ -2086,18 +2132,33 @@ static int ima_measurement(const char *file)
|
|||||||
if (!tpmbanks)
|
if (!tpmbanks)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
for (c = 0; c < num_banks; c++) {
|
||||||
|
if ((pseudo_banks_mask & (1 << c)) == 0)
|
||||||
|
continue;
|
||||||
/* The measurement list might contain too many entries,
|
/* The measurement list might contain too many entries,
|
||||||
* compare the re-calculated TPM PCR values after each
|
* compare the re-calculated TPM PCR values after each
|
||||||
* extend.
|
* extend.
|
||||||
*/
|
*/
|
||||||
err = compare_tpm_banks(num_banks, pseudo_banks, tpm_banks);
|
err = compare_tpm_banks(num_banks, pseudo_banks,
|
||||||
|
tpm_banks, 1 << c, entry_num);
|
||||||
if (!err)
|
if (!err)
|
||||||
|
pseudo_banks_mask ^= (1 << c);
|
||||||
|
}
|
||||||
|
if (pseudo_banks_mask == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
for (c = 0; c < num_banks; c++) {
|
||||||
|
if ((pseudo_padded_banks_mask & (1 << c)) == 0)
|
||||||
|
continue;
|
||||||
/* Compare against original SHA1 zero padded TPM PCR values */
|
/* Compare against original SHA1 zero padded TPM PCR values */
|
||||||
err_padded = compare_tpm_banks(num_banks, pseudo_padded_banks,
|
err_padded = compare_tpm_banks(num_banks,
|
||||||
tpm_banks);
|
pseudo_padded_banks,
|
||||||
|
tpm_banks,
|
||||||
|
1 << c, entry_num);
|
||||||
if (!err_padded)
|
if (!err_padded)
|
||||||
|
pseudo_padded_banks_mask ^= (1 << c);
|
||||||
|
}
|
||||||
|
if (pseudo_padded_banks_mask == 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2175,12 +2236,12 @@ static int read_binary_bios_measurements(char *file, struct tpm_bank_info *bank)
|
|||||||
log_info("Reading the TPM 1.2 event log %s.\n", file);
|
log_info("Reading the TPM 1.2 event log %s.\n", file);
|
||||||
|
|
||||||
/* Extend the pseudo TPM PCRs with the event digest */
|
/* Extend the pseudo TPM PCRs with the event digest */
|
||||||
while (fread(&event, sizeof(event.header), 1, fp)) {
|
while (fread(&event, sizeof(event.header), 1, fp) == 1) {
|
||||||
if (imaevm_params.verbose > LOG_INFO) {
|
if (imaevm_params.verbose > LOG_INFO) {
|
||||||
log_info("%02u ", event.header.pcr);
|
log_info("%02u ", event.header.pcr);
|
||||||
log_dump(event.header.digest, SHA_DIGEST_LENGTH);
|
log_dump(event.header.digest, SHA_DIGEST_LENGTH);
|
||||||
}
|
}
|
||||||
if (event.header.pcr > NUM_PCRS) {
|
if (event.header.pcr >= NUM_PCRS) {
|
||||||
log_err("Invalid PCR %d.\n", event.header.pcr);
|
log_err("Invalid PCR %d.\n", event.header.pcr);
|
||||||
err = 1;
|
err = 1;
|
||||||
break;
|
break;
|
||||||
@ -2439,17 +2500,21 @@ static void usage(void)
|
|||||||
|
|
||||||
printf(
|
printf(
|
||||||
"\n"
|
"\n"
|
||||||
" -a, --hashalgo sha1 (default), sha224, sha256, sha384, sha512, streebog256, streebog512\n"
|
" -a, --hashalgo sha1, sha224, sha256, sha384, sha512, streebog256, streebog512 (default: %s)\n"
|
||||||
" -s, --imasig make IMA signature\n"
|
" -s, --imasig make IMA signature\n"
|
||||||
" -d, --imahash make IMA hash\n"
|
" -d, --imahash make IMA hash\n"
|
||||||
" -f, --sigfile store IMA signature in .sig file instead of xattr\n"
|
" -f, --sigfile store IMA signature in .sig file instead of xattr\n"
|
||||||
" --xattr-user store xattrs in user namespace (for testing purposes)\n"
|
" --xattr-user store xattrs in user namespace (for testing purposes)\n"
|
||||||
" --rsa use RSA key type and signing scheme v1\n"
|
" --rsa use RSA key type and signing scheme v1\n"
|
||||||
" -k, --key path to signing key (default: /etc/keys/{privkey,pubkey}_evm.pem)\n"
|
" -k, --key path to signing key (default: /etc/keys/{privkey,pubkey}_evm.pem)\n"
|
||||||
|
" or a pkcs11 URI\n"
|
||||||
|
" --keyid n overwrite signature keyid with a 32-bit value in hex (for signing)\n"
|
||||||
|
" --keyid-from-cert file\n"
|
||||||
|
" read keyid value from SKID of a x509 cert file\n"
|
||||||
" -o, --portable generate portable EVM signatures\n"
|
" -o, --portable generate portable EVM signatures\n"
|
||||||
" -p, --pass password for encrypted signing key\n"
|
" -p, --pass password for encrypted signing key\n"
|
||||||
" -r, --recursive recurse into directories (sign)\n"
|
" -r, --recursive recurse into directories (sign)\n"
|
||||||
" -t, --type file types to fix 'fdsxm' (f: file, d: directory, s: block/char/symlink)\n"
|
" -t, --type file types to fix 'fxm' (f: file)\n"
|
||||||
" x - skip fixing if both ima and evm xattrs exist (use with caution)\n"
|
" x - skip fixing if both ima and evm xattrs exist (use with caution)\n"
|
||||||
" m - stay on the same filesystem (like 'find -xdev')\n"
|
" m - stay on the same filesystem (like 'find -xdev')\n"
|
||||||
" -n print result to stdout instead of setting xattr\n"
|
" -n print result to stdout instead of setting xattr\n"
|
||||||
@ -2467,10 +2532,13 @@ static void usage(void)
|
|||||||
" --caps use custom Capabilities for EVM(unspecified: from FS, empty: do not use)\n"
|
" --caps use custom Capabilities for EVM(unspecified: from FS, empty: do not use)\n"
|
||||||
" --verify-sig verify measurement list signatures\n"
|
" --verify-sig verify measurement list signatures\n"
|
||||||
" --engine e preload OpenSSL engine e (such as: gost)\n"
|
" --engine e preload OpenSSL engine e (such as: gost)\n"
|
||||||
" --ignore-violations ignore ToMToU measurement violations"
|
" --ignore-violations ignore ToMToU measurement violations\n"
|
||||||
" -v increase verbosity level\n"
|
" -v increase verbosity level\n"
|
||||||
" -h, --help display this help and exit\n"
|
" -h, --help display this help and exit\n"
|
||||||
"\n");
|
"\n"
|
||||||
|
"Environment variables:\n\n"
|
||||||
|
"EVMCTL_KEY_PASSWORD : Private key password to use; do not use --pass option\n"
|
||||||
|
"\n", DEFAULT_HASH_ALGO);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct command cmds[] = {
|
struct command cmds[] = {
|
||||||
@ -2484,8 +2552,8 @@ struct command cmds[] = {
|
|||||||
{"ima_verify", cmd_verify_ima, 0, "file", "Verify IMA signature (for debugging).\n"},
|
{"ima_verify", cmd_verify_ima, 0, "file", "Verify IMA signature (for debugging).\n"},
|
||||||
{"ima_setxattr", cmd_setxattr_ima, 0, "[--sigfile file]", "Set IMA signature from sigfile\n"},
|
{"ima_setxattr", cmd_setxattr_ima, 0, "[--sigfile file]", "Set IMA signature from sigfile\n"},
|
||||||
{"ima_hash", cmd_hash_ima, 0, "file", "Make file content hash.\n"},
|
{"ima_hash", cmd_hash_ima, 0, "file", "Make file content hash.\n"},
|
||||||
{"ima_measurement", cmd_ima_measurement, 0, "[--ignore-violations] [--verify-sig [--key key1, key2, ...]] [--pcrs [hash-algorithm,]file [--pcrs hash-algorithm,file] ...] file", "Verify measurement list (experimental).\n"},
|
{"ima_measurement", cmd_ima_measurement, 0, "[--ignore-violations] [--verify-sig [--key key1, key2, ...]] [--pcrs [hash-algorithm,]file [--pcrs hash-algorithm,file] ...] [--verify-bank hash-algorithm] file", "Verify measurement list (experimental).\n"},
|
||||||
{"ima_boot_aggregate", cmd_ima_bootaggr, 0, "[file]", "Calculate per TPM bank boot_aggregate digests\n"},
|
{"ima_boot_aggregate", cmd_ima_bootaggr, 0, "[--pcrs hash-algorithm,file] [TPM 1.2 BIOS event log]", "Calculate per TPM bank boot_aggregate digests\n"},
|
||||||
{"ima_fix", cmd_ima_fix, 0, "[-t fdsxm] path", "Recursively fix IMA/EVM xattrs in fix mode.\n"},
|
{"ima_fix", cmd_ima_fix, 0, "[-t fdsxm] path", "Recursively fix IMA/EVM xattrs in fix mode.\n"},
|
||||||
{"ima_clear", cmd_ima_clear, 0, "[-t fdsxm] path", "Recursively remove IMA/EVM xattrs.\n"},
|
{"ima_clear", cmd_ima_clear, 0, "[-t fdsxm] path", "Recursively remove IMA/EVM xattrs.\n"},
|
||||||
{"sign_hash", cmd_sign_hash, 0, "[--key key] [--pass [password]", "Sign hashes from shaXsum output.\n"},
|
{"sign_hash", cmd_sign_hash, 0, "[--key key] [--pass [password]", "Sign hashes from shaXsum output.\n"},
|
||||||
@ -2525,6 +2593,9 @@ static struct option opts[] = {
|
|||||||
{"xattr-user", 0, 0, 140},
|
{"xattr-user", 0, 0, 140},
|
||||||
{"ignore-violations", 0, 0, 141},
|
{"ignore-violations", 0, 0, 141},
|
||||||
{"pcrs", 1, 0, 142},
|
{"pcrs", 1, 0, 142},
|
||||||
|
{"verify-bank", 2, 0, 143},
|
||||||
|
{"keyid", 1, 0, 144},
|
||||||
|
{"keyid-from-cert", 1, 0, 145},
|
||||||
{}
|
{}
|
||||||
|
|
||||||
};
|
};
|
||||||
@ -2562,13 +2633,36 @@ static char *get_password(void)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pwd;
|
if (pwd == NULL) {
|
||||||
|
free(password);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ENGINE *setup_engine(const char *engine_id)
|
||||||
|
{
|
||||||
|
ENGINE *eng = ENGINE_by_id(engine_id);
|
||||||
|
if (!eng) {
|
||||||
|
log_err("engine %s isn't available\n", optarg);
|
||||||
|
ERR_print_errors_fp(stderr);
|
||||||
|
} else if (!ENGINE_init(eng)) {
|
||||||
|
log_err("engine %s init failed\n", optarg);
|
||||||
|
ERR_print_errors_fp(stderr);
|
||||||
|
ENGINE_free(eng);
|
||||||
|
eng = NULL;
|
||||||
|
}
|
||||||
|
if (eng)
|
||||||
|
ENGINE_set_default(eng, ENGINE_METHOD_ALL);
|
||||||
|
return eng;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int err = 0, c, lind;
|
int err = 0, c, lind;
|
||||||
ENGINE *eng = NULL;
|
unsigned long keyid;
|
||||||
|
char *eptr;
|
||||||
|
|
||||||
#if !(OPENSSL_VERSION_NUMBER < 0x10100000)
|
#if !(OPENSSL_VERSION_NUMBER < 0x10100000)
|
||||||
OPENSSL_init_crypto(
|
OPENSSL_init_crypto(
|
||||||
@ -2687,17 +2781,9 @@ int main(int argc, char *argv[])
|
|||||||
verify_list_sig = 1;
|
verify_list_sig = 1;
|
||||||
break;
|
break;
|
||||||
case 139: /* --engine e */
|
case 139: /* --engine e */
|
||||||
eng = ENGINE_by_id(optarg);
|
imaevm_params.eng = setup_engine(optarg);
|
||||||
if (!eng) {
|
if (!imaevm_params.eng)
|
||||||
log_err("engine %s isn't available\n", optarg);
|
goto error;
|
||||||
ERR_print_errors_fp(stderr);
|
|
||||||
} else if (!ENGINE_init(eng)) {
|
|
||||||
log_err("engine %s init failed\n", optarg);
|
|
||||||
ERR_print_errors_fp(stderr);
|
|
||||||
ENGINE_free(eng);
|
|
||||||
eng = NULL;
|
|
||||||
}
|
|
||||||
ENGINE_set_default(eng, ENGINE_METHOD_ALL);
|
|
||||||
break;
|
break;
|
||||||
case 140: /* --xattr-user */
|
case 140: /* --xattr-user */
|
||||||
xattr_ima = "user.ima";
|
xattr_ima = "user.ima";
|
||||||
@ -2713,6 +2799,33 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
pcrfile[npcrfile++] = optarg;
|
pcrfile[npcrfile++] = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 143:
|
||||||
|
verify_bank = optarg;
|
||||||
|
break;
|
||||||
|
case 144:
|
||||||
|
errno = 0;
|
||||||
|
keyid = strtoul(optarg, &eptr, 16);
|
||||||
|
/*
|
||||||
|
* ULONG_MAX is error from strtoul(3),
|
||||||
|
* UINT_MAX is `imaevm_params.keyid' maximum value,
|
||||||
|
* 0 is reserved for keyid being unset.
|
||||||
|
*/
|
||||||
|
if (errno || eptr - optarg != strlen(optarg) ||
|
||||||
|
keyid == ULONG_MAX || keyid > UINT_MAX ||
|
||||||
|
keyid == 0) {
|
||||||
|
log_err("Invalid keyid value.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
imaevm_params.keyid = keyid;
|
||||||
|
break;
|
||||||
|
case 145:
|
||||||
|
keyid = imaevm_read_keyid(optarg);
|
||||||
|
if (keyid == 0) {
|
||||||
|
log_err("Error reading keyid.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
imaevm_params.keyid = keyid;
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
exit(1);
|
exit(1);
|
||||||
break;
|
break;
|
||||||
@ -2721,6 +2834,17 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!imaevm_params.keypass)
|
||||||
|
imaevm_params.keypass = getenv("EVMCTL_KEY_PASSWORD");
|
||||||
|
|
||||||
|
if (imaevm_params.keyfile != NULL &&
|
||||||
|
imaevm_params.eng == NULL &&
|
||||||
|
!strncmp(imaevm_params.keyfile, "pkcs11:", 7)) {
|
||||||
|
imaevm_params.eng = setup_engine("pkcs11");
|
||||||
|
if (!imaevm_params.eng)
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
if (argv[optind] == NULL)
|
if (argv[optind] == NULL)
|
||||||
usage();
|
usage();
|
||||||
else
|
else
|
||||||
@ -2741,9 +2865,10 @@ int main(int argc, char *argv[])
|
|||||||
err = 125;
|
err = 125;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eng) {
|
error:
|
||||||
ENGINE_finish(eng);
|
if (imaevm_params.eng) {
|
||||||
ENGINE_free(eng);
|
ENGINE_finish(imaevm_params.eng);
|
||||||
|
ENGINE_free(imaevm_params.eng);
|
||||||
#if OPENSSL_API_COMPAT < 0x10100000L
|
#if OPENSSL_API_COMPAT < 0x10100000L
|
||||||
ENGINE_cleanup();
|
ENGINE_cleanup();
|
||||||
#endif
|
#endif
|
||||||
|
@ -84,9 +84,10 @@ echo "};"
|
|||||||
echo "const char *const hash_algo_name[HASH_ALGO__LAST] = {"
|
echo "const char *const hash_algo_name[HASH_ALGO__LAST] = {"
|
||||||
sed -n 's/HASH_ALGO_\(.*\),/\1 \L\1\E/p' $HASH_INFO | \
|
sed -n 's/HASH_ALGO_\(.*\),/\1 \L\1\E/p' $HASH_INFO | \
|
||||||
while read a b; do
|
while read a b; do
|
||||||
# Normalize text hash name: if it contains underscore between
|
# Normalize text hash name: sm3 algorithm name is different from
|
||||||
# digits replace it with a dash, other underscores are removed.
|
# the macro definition, which is also the only special case of an
|
||||||
b=$(echo "$b" | sed "s/\([0-9]\)_\([0-9]\)/\1-\2/g;s/_//g")
|
# underscore between digits. Remove all other underscores.
|
||||||
|
b=$(echo "$b" | sed "s/sm3_256/sm3/g;s/_//g")
|
||||||
printf '\t%-26s = "%s",\n' "[HASH_ALGO_$a]" "$b"
|
printf '\t%-26s = "%s",\n' "[HASH_ALGO_$a]" "$b"
|
||||||
done
|
done
|
||||||
echo "};"
|
echo "};"
|
||||||
|
@ -48,6 +48,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <openssl/rsa.h>
|
#include <openssl/rsa.h>
|
||||||
|
#include <openssl/engine.h>
|
||||||
|
|
||||||
#ifdef USE_FPRINTF
|
#ifdef USE_FPRINTF
|
||||||
#define do_log(level, fmt, args...) \
|
#define do_log(level, fmt, args...) \
|
||||||
@ -74,6 +75,10 @@
|
|||||||
#define log_err(fmt, args...) do_log(LOG_ERR, fmt, ##args)
|
#define log_err(fmt, args...) do_log(LOG_ERR, fmt, ##args)
|
||||||
#define log_errno(fmt, args...) do_log(LOG_ERR, fmt ": errno: %s (%d)\n", ##args, strerror(errno), errno)
|
#define log_errno(fmt, args...) do_log(LOG_ERR, fmt ": errno: %s (%d)\n", ##args, strerror(errno), errno)
|
||||||
|
|
||||||
|
#ifndef DEFAULT_HASH_ALGO
|
||||||
|
#define DEFAULT_HASH_ALGO "sha256"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DATA_SIZE 4096
|
#define DATA_SIZE 4096
|
||||||
#define SHA1_HASH_LEN 20
|
#define SHA1_HASH_LEN 20
|
||||||
|
|
||||||
@ -196,6 +201,8 @@ struct libimaevm_params {
|
|||||||
const char *hash_algo;
|
const char *hash_algo;
|
||||||
const char *keyfile;
|
const char *keyfile;
|
||||||
const char *keypass;
|
const char *keypass;
|
||||||
|
uint32_t keyid; /* keyid overriding value, unless 0. (Host order.) */
|
||||||
|
ENGINE *eng;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RSA_ASN1_template {
|
struct RSA_ASN1_template {
|
||||||
@ -218,6 +225,7 @@ EVP_PKEY *read_pub_pkey(const char *keyfile, int x509);
|
|||||||
void calc_keyid_v1(uint8_t *keyid, char *str, const unsigned char *pkey, int len);
|
void calc_keyid_v1(uint8_t *keyid, char *str, const unsigned char *pkey, int len);
|
||||||
void calc_keyid_v2(uint32_t *keyid, char *str, EVP_PKEY *pkey);
|
void calc_keyid_v2(uint32_t *keyid, char *str, EVP_PKEY *pkey);
|
||||||
int key2bin(RSA *key, unsigned char *pub);
|
int key2bin(RSA *key, unsigned char *pub);
|
||||||
|
uint32_t imaevm_read_keyid(const char *certfile);
|
||||||
|
|
||||||
int sign_hash(const char *algo, const unsigned char *hash, int size, const char *keyfile, const char *keypass, unsigned char *sig);
|
int sign_hash(const char *algo, const unsigned char *hash, int size, const char *keyfile, const char *keypass, unsigned char *sig);
|
||||||
int verify_hash(const char *file, const unsigned char *hash, int size, unsigned char *sig, int siglen);
|
int verify_hash(const char *file, const unsigned char *hash, int size, unsigned char *sig, int siglen);
|
||||||
|
254
src/libimaevm.c
254
src/libimaevm.c
@ -45,6 +45,7 @@
|
|||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <asm/byteorder.h>
|
#include <asm/byteorder.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -52,11 +53,14 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <openssl/asn1.h>
|
||||||
#include <openssl/crypto.h>
|
#include <openssl/crypto.h>
|
||||||
#include <openssl/pem.h>
|
#include <openssl/pem.h>
|
||||||
#include <openssl/evp.h>
|
#include <openssl/evp.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
|
#include <openssl/x509v3.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
|
#include <openssl/engine.h>
|
||||||
|
|
||||||
#include "imaevm.h"
|
#include "imaevm.h"
|
||||||
#include "hash_info.h"
|
#include "hash_info.h"
|
||||||
@ -85,19 +89,19 @@ static const char *const pkey_hash_algo_kern[PKEY_HASH__LAST] = {
|
|||||||
struct libimaevm_params imaevm_params = {
|
struct libimaevm_params imaevm_params = {
|
||||||
.verbose = LOG_INFO,
|
.verbose = LOG_INFO,
|
||||||
.x509 = 1,
|
.x509 = 1,
|
||||||
.hash_algo = "sha1",
|
.hash_algo = DEFAULT_HASH_ALGO,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void __attribute__ ((constructor)) libinit(void);
|
static void __attribute__ ((constructor)) libinit(void);
|
||||||
|
|
||||||
void imaevm_do_hexdump(FILE *fp, const void *ptr, int len, bool cr)
|
void imaevm_do_hexdump(FILE *fp, const void *ptr, int len, bool newline)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint8_t *data = (uint8_t *) ptr;
|
uint8_t *data = (uint8_t *) ptr;
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
fprintf(fp, "%02x", data[i]);
|
fprintf(fp, "%02x", data[i]);
|
||||||
if (cr)
|
if (newline)
|
||||||
fprintf(fp, "\n");
|
fprintf(fp, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +160,7 @@ static int add_file_hash(const char *file, EVP_MD_CTX *ctx)
|
|||||||
|
|
||||||
for (size = stats.st_size; size; size -= len) {
|
for (size = stats.st_size; size; size -= len) {
|
||||||
len = MIN(size, bs);
|
len = MIN(size, bs);
|
||||||
if (!fread(data, len, 1, fp)) {
|
if (fread(data, len, 1, fp) != 1) {
|
||||||
if (ferror(fp)) {
|
if (ferror(fp)) {
|
||||||
log_err("fread() failed\n\n");
|
log_err("fread() failed\n\n");
|
||||||
goto out;
|
goto out;
|
||||||
@ -177,67 +181,6 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int add_dir_hash(const char *file, EVP_MD_CTX *ctx)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
struct dirent *de;
|
|
||||||
DIR *dir;
|
|
||||||
unsigned long long ino, off;
|
|
||||||
unsigned int type;
|
|
||||||
int result = 0;
|
|
||||||
|
|
||||||
dir = opendir(file);
|
|
||||||
if (!dir) {
|
|
||||||
log_err("Failed to open: %s\n", file);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ((de = readdir(dir))) {
|
|
||||||
ino = de->d_ino;
|
|
||||||
off = de->d_off;
|
|
||||||
type = de->d_type;
|
|
||||||
log_debug("entry: %s, ino: %llu, type: %u, off: %llu, reclen: %hu\n",
|
|
||||||
de->d_name, ino, type, off, de->d_reclen);
|
|
||||||
err = EVP_DigestUpdate(ctx, de->d_name, strlen(de->d_name));
|
|
||||||
/*err |= EVP_DigestUpdate(ctx, &off, sizeof(off));*/
|
|
||||||
err |= EVP_DigestUpdate(ctx, &ino, sizeof(ino));
|
|
||||||
err |= EVP_DigestUpdate(ctx, &type, sizeof(type));
|
|
||||||
if (!err) {
|
|
||||||
log_err("EVP_DigestUpdate() failed\n");
|
|
||||||
output_openssl_errors();
|
|
||||||
result = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir(dir);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int add_link_hash(const char *path, EVP_MD_CTX *ctx)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
char buf[1024];
|
|
||||||
|
|
||||||
err = readlink(path, buf, sizeof(buf));
|
|
||||||
if (err <= 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
log_info("link: %s -> %.*s\n", path, err, buf);
|
|
||||||
return !EVP_DigestUpdate(ctx, buf, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int add_dev_hash(struct stat *st, EVP_MD_CTX *ctx)
|
|
||||||
{
|
|
||||||
uint32_t dev = st->st_rdev;
|
|
||||||
unsigned major = (dev & 0xfff00) >> 8;
|
|
||||||
unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00);
|
|
||||||
|
|
||||||
log_info("device: %u:%u\n", major, minor);
|
|
||||||
return !EVP_DigestUpdate(ctx, &dev, sizeof(dev));
|
|
||||||
}
|
|
||||||
|
|
||||||
int ima_calc_hash(const char *file, uint8_t *hash)
|
int ima_calc_hash(const char *file, uint8_t *hash)
|
||||||
{
|
{
|
||||||
const EVP_MD *md;
|
const EVP_MD *md;
|
||||||
@ -278,18 +221,8 @@ int ima_calc_hash(const char *file, uint8_t *hash)
|
|||||||
case S_IFREG:
|
case S_IFREG:
|
||||||
err = add_file_hash(file, pctx);
|
err = add_file_hash(file, pctx);
|
||||||
break;
|
break;
|
||||||
case S_IFDIR:
|
|
||||||
err = add_dir_hash(file, pctx);
|
|
||||||
break;
|
|
||||||
case S_IFLNK:
|
|
||||||
err = add_link_hash(file, pctx);
|
|
||||||
break;
|
|
||||||
case S_IFIFO: case S_IFSOCK:
|
|
||||||
case S_IFCHR: case S_IFBLK:
|
|
||||||
err = add_dev_hash(&st, pctx);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
log_errno("Unsupported file type");
|
log_err("Unsupported file type (0x%x)", st.st_mode & S_IFMT);
|
||||||
err = -1;
|
err = -1;
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
@ -463,8 +396,6 @@ void init_public_keys(const char *keyfiles)
|
|||||||
keyfiles_free = tmp_keyfiles;
|
keyfiles_free = tmp_keyfiles;
|
||||||
|
|
||||||
while ((keyfile = strsep(&tmp_keyfiles, ", \t")) != NULL) {
|
while ((keyfile = strsep(&tmp_keyfiles, ", \t")) != NULL) {
|
||||||
if (!keyfile)
|
|
||||||
break;
|
|
||||||
if ((*keyfile == '\0') || (*keyfile == ' ') ||
|
if ((*keyfile == '\0') || (*keyfile == ' ') ||
|
||||||
(*keyfile == '\t'))
|
(*keyfile == '\t'))
|
||||||
continue;
|
continue;
|
||||||
@ -518,6 +449,16 @@ static int verify_hash_v2(const char *file, const unsigned char *hash, int size,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(EVP_PKEY_SM2) && OPENSSL_VERSION_NUMBER < 0x30000000
|
||||||
|
/* If EC key are used, check whether it is SM2 key */
|
||||||
|
if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) {
|
||||||
|
EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
|
||||||
|
int curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
|
||||||
|
if (curve == NID_sm2)
|
||||||
|
EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
st = "EVP_PKEY_CTX_new";
|
st = "EVP_PKEY_CTX_new";
|
||||||
if (!(ctx = EVP_PKEY_CTX_new(pkey, NULL)))
|
if (!(ctx = EVP_PKEY_CTX_new(pkey, NULL)))
|
||||||
goto err;
|
goto err;
|
||||||
@ -747,11 +688,141 @@ void calc_keyid_v2(uint32_t *keyid, char *str, EVP_PKEY *pkey)
|
|||||||
X509_PUBKEY_free(pk);
|
X509_PUBKEY_free(pk);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract SKID from x509 in openssl portable way.
|
||||||
|
*/
|
||||||
|
static const unsigned char *x509_get_skid(X509 *x, int *len)
|
||||||
|
{
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x10100000
|
||||||
|
ASN1_STRING *skid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This will cache extensions.
|
||||||
|
* OpenSSL uses this method itself.
|
||||||
|
*/
|
||||||
|
if (X509_check_purpose(x, -1, -1) != 1)
|
||||||
|
return NULL;
|
||||||
|
skid = x->skid;
|
||||||
|
#else
|
||||||
|
const ASN1_OCTET_STRING *skid = X509_get0_subject_key_id(x);
|
||||||
|
#endif
|
||||||
|
if (len)
|
||||||
|
*len = ASN1_STRING_length(skid);
|
||||||
|
#if OPENSSL_VERSION_NUMBER < 0x10100000
|
||||||
|
return ASN1_STRING_data(x->skid);
|
||||||
|
#else
|
||||||
|
return ASN1_STRING_get0_data(skid);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read_keyid_from_cert() - Read keyid from SKID from x509 certificate file
|
||||||
|
* @keyid_be: Output 32-bit keyid in network order (BE);
|
||||||
|
* @certfile: Input filename.
|
||||||
|
* @try_der: true: try to read in DER from if there is no PEM,
|
||||||
|
* cert is considered mandatory and error will be issued
|
||||||
|
* if there is no cert;
|
||||||
|
* false: only try to read in PEM form, cert is considered
|
||||||
|
* optional.
|
||||||
|
* Return: 0 on success, -1 on error.
|
||||||
|
*/
|
||||||
|
static int read_keyid_from_cert(uint32_t *keyid_be, const char *certfile, int try_der)
|
||||||
|
{
|
||||||
|
X509 *x = NULL;
|
||||||
|
FILE *fp;
|
||||||
|
const unsigned char *skid;
|
||||||
|
int skid_len;
|
||||||
|
|
||||||
|
if (!(fp = fopen(certfile, "r"))) {
|
||||||
|
log_err("Cannot open %s: %s\n", certfile, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (!PEM_read_X509(fp, &x, NULL, NULL)) {
|
||||||
|
if (ERR_GET_REASON(ERR_peek_last_error()) == PEM_R_NO_START_LINE) {
|
||||||
|
ERR_clear_error();
|
||||||
|
if (try_der) {
|
||||||
|
rewind(fp);
|
||||||
|
d2i_X509_fp(fp, &x);
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Cert is optional and there is just no PEM
|
||||||
|
* header, then issue debug message and stop
|
||||||
|
* trying.
|
||||||
|
*/
|
||||||
|
log_debug("%s: x509 certificate not found\n",
|
||||||
|
certfile);
|
||||||
|
fclose(fp);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
if (!x) {
|
||||||
|
ERR_print_errors_fp(stderr);
|
||||||
|
log_err("read keyid: %s: Error reading x509 certificate\n",
|
||||||
|
certfile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(skid = x509_get_skid(x, &skid_len))) {
|
||||||
|
log_err("read keyid: %s: SKID not found\n", certfile);
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
if (skid_len < sizeof(*keyid_be)) {
|
||||||
|
log_err("read keyid: %s: SKID too short (len %d)\n", certfile,
|
||||||
|
skid_len);
|
||||||
|
goto err_free;
|
||||||
|
}
|
||||||
|
memcpy(keyid_be, skid + skid_len - sizeof(*keyid_be), sizeof(*keyid_be));
|
||||||
|
log_info("keyid %04x (from %s)\n", ntohl(*keyid_be), certfile);
|
||||||
|
X509_free(x);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_free:
|
||||||
|
X509_free(x);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* imaevm_read_keyid() - Read 32-bit keyid from the cert file
|
||||||
|
* @certfile: File with certificate in PEM or DER form.
|
||||||
|
*
|
||||||
|
* Try to read keyid from Subject Key Identifier (SKID) of x509 certificate.
|
||||||
|
* Autodetect if cert is in PEM (tried first) or DER encoding.
|
||||||
|
*
|
||||||
|
* Return: 0 on error or 32-bit keyid in host order otherwise.
|
||||||
|
*/
|
||||||
|
uint32_t imaevm_read_keyid(const char *certfile)
|
||||||
|
{
|
||||||
|
uint32_t keyid_be = 0;
|
||||||
|
|
||||||
|
read_keyid_from_cert(&keyid_be, certfile, true);
|
||||||
|
/* On error keyid_be will not be set, returning 0. */
|
||||||
|
return ntohl(keyid_be);
|
||||||
|
}
|
||||||
|
|
||||||
static EVP_PKEY *read_priv_pkey(const char *keyfile, const char *keypass)
|
static EVP_PKEY *read_priv_pkey(const char *keyfile, const char *keypass)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
EVP_PKEY *pkey;
|
EVP_PKEY *pkey;
|
||||||
|
|
||||||
|
if (!strncmp(keyfile, "pkcs11:", 7)) {
|
||||||
|
if (!imaevm_params.keyid) {
|
||||||
|
log_err("When using a pkcs11 URI you must provide the keyid with an option\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keypass) {
|
||||||
|
if (!ENGINE_ctrl_cmd_string(imaevm_params.eng, "PIN", keypass, 0)) {
|
||||||
|
log_err("Failed to set the PIN for the private key\n");
|
||||||
|
goto err_engine;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pkey = ENGINE_load_private_key(imaevm_params.eng, keyfile, NULL, NULL);
|
||||||
|
if (!pkey) {
|
||||||
|
log_err("Failed to load private key %s\n", keyfile);
|
||||||
|
goto err_engine;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
fp = fopen(keyfile, "r");
|
fp = fopen(keyfile, "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
log_err("Failed to open keyfile: %s\n", keyfile);
|
log_err("Failed to open keyfile: %s\n", keyfile);
|
||||||
@ -765,7 +836,13 @@ static EVP_PKEY *read_priv_pkey(const char *keyfile, const char *keypass)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
return pkey;
|
return pkey;
|
||||||
|
|
||||||
|
err_engine:
|
||||||
|
output_openssl_errors();
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static RSA *read_priv_key(const char *keyfile, const char *keypass)
|
static RSA *read_priv_key(const char *keyfile, const char *keypass)
|
||||||
@ -916,7 +993,7 @@ static int sign_hash_v2(const char *algo, const unsigned char *hash,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("hash(%s): ", imaevm_params.hash_algo);
|
log_info("hash(%s): ", algo);
|
||||||
log_dump(hash, size);
|
log_dump(hash, size);
|
||||||
|
|
||||||
pkey = read_priv_pkey(keyfile, imaevm_params.keypass);
|
pkey = read_priv_pkey(keyfile, imaevm_params.keypass);
|
||||||
@ -932,7 +1009,24 @@ static int sign_hash_v2(const char *algo, const unsigned char *hash,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(EVP_PKEY_SM2) && OPENSSL_VERSION_NUMBER < 0x30000000
|
||||||
|
/* If EC key are used, check whether it is SM2 key */
|
||||||
|
if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) {
|
||||||
|
EC_KEY *ec = EVP_PKEY_get0_EC_KEY(pkey);
|
||||||
|
int curve = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec));
|
||||||
|
if (curve == NID_sm2)
|
||||||
|
EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (imaevm_params.keyid)
|
||||||
|
keyid = htonl(imaevm_params.keyid);
|
||||||
|
else {
|
||||||
|
int keyid_read_failed = read_keyid_from_cert(&keyid, keyfile, false);
|
||||||
|
|
||||||
|
if (keyid_read_failed)
|
||||||
calc_keyid_v2(&keyid, name, pkey);
|
calc_keyid_v2(&keyid, name, pkey);
|
||||||
|
}
|
||||||
hdr->keyid = keyid;
|
hdr->keyid = keyid;
|
||||||
|
|
||||||
st = "EVP_PKEY_CTX_new";
|
st = "EVP_PKEY_CTX_new";
|
||||||
@ -942,7 +1036,7 @@ static int sign_hash_v2(const char *algo, const unsigned char *hash,
|
|||||||
if (!EVP_PKEY_sign_init(ctx))
|
if (!EVP_PKEY_sign_init(ctx))
|
||||||
goto err;
|
goto err;
|
||||||
st = "EVP_get_digestbyname";
|
st = "EVP_get_digestbyname";
|
||||||
if (!(md = EVP_get_digestbyname(imaevm_params.hash_algo)))
|
if (!(md = EVP_get_digestbyname(algo)))
|
||||||
goto err;
|
goto err;
|
||||||
st = "EVP_PKEY_CTX_set_signature_md";
|
st = "EVP_PKEY_CTX_set_signature_md";
|
||||||
if (!EVP_PKEY_CTX_set_signature_md(ctx, md))
|
if (!EVP_PKEY_CTX_set_signature_md(ctx, md))
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
int tpm2_pcr_supported(void);
|
int tpm2_pcr_supported(void);
|
||||||
int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
|
int tpm2_pcr_read(const char *algo_name, uint32_t pcr_handle, uint8_t *hwpcr,
|
||||||
int len, char **errmsg);
|
int len, char **errmsg);
|
||||||
|
164
src/pcr_ibmtss.c
Normal file
164
src/pcr_ibmtss.c
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* Support PCR reading implementation based on IBM TSS2
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 IBM Ken Goldman <kgoldman@us.ibm.com>
|
||||||
|
*/
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <openssl/sha.h>
|
||||||
|
|
||||||
|
#define USE_FPRINTF
|
||||||
|
#include "utils.h"
|
||||||
|
#include "imaevm.h"
|
||||||
|
|
||||||
|
#define TPM_POSIX /* use Posix, not Windows constructs in TSS */
|
||||||
|
#undef MAX_DIGEST_SIZE /* imaevm uses a different value than the TSS */
|
||||||
|
#include <ibmtss/tss.h>
|
||||||
|
|
||||||
|
#define CMD "tsspcrread"
|
||||||
|
|
||||||
|
static char path[PATH_MAX];
|
||||||
|
|
||||||
|
int tpm2_pcr_supported(void)
|
||||||
|
{
|
||||||
|
if (imaevm_params.verbose > LOG_INFO)
|
||||||
|
log_info("Using %s to read PCRs.\n", CMD);
|
||||||
|
|
||||||
|
if (get_cmd_path(CMD, path, sizeof(path))) {
|
||||||
|
log_debug("Couldn't find '%s' in $PATH\n", CMD);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_debug("Found '%s' in $PATH\n", CMD);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Table mapping C strings to TCG algorithm identifiers */
|
||||||
|
typedef struct tdAlgorithm_Map {
|
||||||
|
const char *algorithm_string;
|
||||||
|
TPMI_ALG_HASH algid;
|
||||||
|
} Algorithm_Map;
|
||||||
|
|
||||||
|
Algorithm_Map algorithm_map[] = {
|
||||||
|
{ "sha1", TPM_ALG_SHA1},
|
||||||
|
{ "sha256", TPM_ALG_SHA256},
|
||||||
|
#if 0 /* uncomment as these digest algorithms are supported */
|
||||||
|
{ "", TPM_ALG_SHA384},
|
||||||
|
{ "", TPM_ALG_SHA512},
|
||||||
|
{ "", TPM_ALG_SM3_256},
|
||||||
|
{ "", TPM_ALG_SHA3_256},
|
||||||
|
{ "", TPM_ALG_SHA3_384},
|
||||||
|
{ "", TPM_ALG_SHA3_512},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* algorithm_string_to_algid() converts a digest algorithm from a C string to a
|
||||||
|
* TCG algorithm identifier as defined in the TCG Algorithm Regisrty..
|
||||||
|
*
|
||||||
|
* Returns TPM_ALG_ERROR if the string has an unsupported value.
|
||||||
|
*/
|
||||||
|
static TPMI_ALG_HASH algorithm_string_to_algid(const char *algorithm_string)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i=0 ; i < sizeof(algorithm_map)/sizeof(Algorithm_Map) ; i++) {
|
||||||
|
if (strcmp(algorithm_string, algorithm_map[i].algorithm_string)
|
||||||
|
== 0) {
|
||||||
|
return algorithm_map[i].algid; /* if match */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TPM_ALG_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tpm2_pcr_read - read the PCR
|
||||||
|
*
|
||||||
|
* algo_name: PCR digest algorithm (the PCR bank) as a C string
|
||||||
|
* pcr_handle: PCR number to read
|
||||||
|
* hwpcr: buffer for the PCR output in binary
|
||||||
|
* len: allocated size of hwpcr and should match the digest algorithm
|
||||||
|
*/
|
||||||
|
int tpm2_pcr_read(const char *algo_name, uint32_t pcr_handle, uint8_t *hwpcr,
|
||||||
|
int len, char **errmsg)
|
||||||
|
{
|
||||||
|
int ret = 0; /* function return code */
|
||||||
|
TPM_RC rc = 0; /* TCG return code */
|
||||||
|
TPM_RC rc1 = 0; /* secondary return code */
|
||||||
|
PCR_Read_In pcr_read_in; /* command input */
|
||||||
|
PCR_Read_Out pcr_read_out; /* response output */
|
||||||
|
TSS_CONTEXT *tss_context = NULL;
|
||||||
|
TPMI_ALG_HASH alg_id; /* PCR algorithm */
|
||||||
|
|
||||||
|
alg_id = algorithm_string_to_algid(algo_name);
|
||||||
|
if (alg_id == TPM_ALG_ERROR) {
|
||||||
|
ret = asprintf(errmsg, "tpm2_pcr_read: unknown algorithm %s",
|
||||||
|
algo_name);
|
||||||
|
if (ret == -1) /* the contents of errmsg is undefined */
|
||||||
|
*errmsg = NULL;
|
||||||
|
rc = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = TSS_Create(&tss_context);
|
||||||
|
if (rc != 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* call TSS to execute the command */
|
||||||
|
pcr_read_in.pcrSelectionIn.count = 1;
|
||||||
|
pcr_read_in.pcrSelectionIn.pcrSelections[0].hash = alg_id;
|
||||||
|
pcr_read_in.pcrSelectionIn.pcrSelections[0].sizeofSelect = 3;
|
||||||
|
pcr_read_in.pcrSelectionIn.pcrSelections[0].pcrSelect[0] = 0;
|
||||||
|
pcr_read_in.pcrSelectionIn.pcrSelections[0].pcrSelect[1] = 0;
|
||||||
|
pcr_read_in.pcrSelectionIn.pcrSelections[0].pcrSelect[2] = 0;
|
||||||
|
pcr_read_in.pcrSelectionIn.pcrSelections[0].pcrSelect[pcr_handle / 8] =
|
||||||
|
1 << (pcr_handle % 8);
|
||||||
|
rc = TSS_Execute(tss_context,
|
||||||
|
(RESPONSE_PARAMETERS *)&pcr_read_out,
|
||||||
|
(COMMAND_PARAMETERS *)&pcr_read_in,
|
||||||
|
NULL,
|
||||||
|
TPM_CC_PCR_Read,
|
||||||
|
TPM_RH_NULL, NULL, 0);
|
||||||
|
if (rc != 0)
|
||||||
|
goto end;
|
||||||
|
|
||||||
|
/* nothing read, bank missing */
|
||||||
|
if (pcr_read_out.pcrValues.count == 0) {
|
||||||
|
ret = asprintf(errmsg, "tpm2_pcr_read: returned count 0 for %s",
|
||||||
|
algo_name);
|
||||||
|
if (ret == -1) /* the contents of errmsg is undefined */
|
||||||
|
*errmsg = NULL;
|
||||||
|
rc = 1;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
/* len parameter did not match the digest algorithm */
|
||||||
|
else if (pcr_read_out.pcrValues.digests[0].t.size != len) {
|
||||||
|
ret = asprintf(errmsg,
|
||||||
|
"tpm2_pcr_read: "
|
||||||
|
"expected length %d actual %u for %s",
|
||||||
|
len, pcr_read_out.pcrValues.digests[0].t.size,
|
||||||
|
algo_name);
|
||||||
|
if (ret == -1) /* the contents of errmsg is undefined */
|
||||||
|
*errmsg = NULL;
|
||||||
|
rc = 1;
|
||||||
|
goto end;
|
||||||
|
} else {
|
||||||
|
memcpy(hwpcr,
|
||||||
|
pcr_read_out.pcrValues.digests[0].t.buffer,
|
||||||
|
pcr_read_out.pcrValues.digests[0].t.size);
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
/* Call delete even on errors to free context resources */
|
||||||
|
rc1 = TSS_Delete(tss_context);
|
||||||
|
|
||||||
|
/* map TCG return code to function return code */
|
||||||
|
if ((rc == 0) && (rc1 == 0))
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
@ -106,7 +106,7 @@ static TPM2_ALG_ID algo_to_tss2(const char *algo_name)
|
|||||||
return TPM2_ALG_ERROR;
|
return TPM2_ALG_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
|
int tpm2_pcr_read(const char *algo_name, uint32_t pcr_handle, uint8_t *hwpcr,
|
||||||
int len, char **errmsg)
|
int len, char **errmsg)
|
||||||
{
|
{
|
||||||
TSS2_ABI_VERSION abi_version = {
|
TSS2_ABI_VERSION abi_version = {
|
||||||
@ -140,7 +140,8 @@ int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pcr_select_in.pcrSelections[0].pcrSelect[idx / 8] = (1 << (idx % 8));
|
pcr_select_in.pcrSelections[0].pcrSelect[pcr_handle / 8] =
|
||||||
|
(1 << (pcr_handle % 8));
|
||||||
|
|
||||||
ret = Esys_Initialize(&ctx, NULL, &abi_version);
|
ret = Esys_Initialize(&ctx, NULL, &abi_version);
|
||||||
if (ret != TPM2_RC_SUCCESS) {
|
if (ret != TPM2_RC_SUCCESS) {
|
||||||
|
@ -60,15 +60,15 @@ int tpm2_pcr_supported(void)
|
|||||||
log_info("Using %s to read PCRs.\n", CMD);
|
log_info("Using %s to read PCRs.\n", CMD);
|
||||||
|
|
||||||
if (get_cmd_path(CMD, path, sizeof(path))) {
|
if (get_cmd_path(CMD, path, sizeof(path))) {
|
||||||
log_debug("Couldn't find '%s' in $PATH", CMD);
|
log_debug("Couldn't find '%s' in $PATH\n", CMD);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_debug("Found '%s' in $PATH", CMD);
|
log_debug("Found '%s' in $PATH\n", CMD);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
|
int tpm2_pcr_read(const char *algo_name, uint32_t pcr_handle, uint8_t *hwpcr,
|
||||||
int len, char **errmsg)
|
int len, char **errmsg)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
@ -76,8 +76,8 @@ int tpm2_pcr_read(const char *algo_name, int idx, uint8_t *hwpcr,
|
|||||||
char cmd[PATH_MAX + 50];
|
char cmd[PATH_MAX + 50];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
sprintf(cmd, "%s -halg %s -ha %d -ns 2> /dev/null",
|
sprintf(cmd, "%s -halg %s -ha %u -ns 2> /dev/null",
|
||||||
path, algo_name, idx);
|
path, algo_name, pcr_handle);
|
||||||
fp = popen(cmd, "r");
|
fp = popen(cmd, "r");
|
||||||
if (!fp) {
|
if (!fp) {
|
||||||
ret = asprintf(errmsg, "popen failed: %s", strerror(errno));
|
ret = asprintf(errmsg, "popen failed: %s", strerror(errno));
|
||||||
|
@ -77,6 +77,7 @@ int get_cmd_path(const char *prog_name, char *buf, size_t buf_len)
|
|||||||
if (buf_len - size > ret && file_exist(buf))
|
if (buf_len - size > ret && file_exist(buf))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (end != NULL)
|
||||||
start = end + 1;
|
start = end + 1;
|
||||||
|
|
||||||
} while (end != NULL);
|
} while (end != NULL);
|
||||||
|
@ -26,44 +26,49 @@ TSSDIR="$(dirname -- "$(which tssstartup)")"
|
|||||||
PCRFILE="/sys/class/tpm/tpm0/device/pcrs"
|
PCRFILE="/sys/class/tpm/tpm0/device/pcrs"
|
||||||
MISC_PCRFILE="/sys/class/misc/tpm0/device/pcrs"
|
MISC_PCRFILE="/sys/class/misc/tpm0/device/pcrs"
|
||||||
|
|
||||||
if [ "$(id -u)" = 0 ] && [ -c "/dev/tpm0" ]; then
|
# Only stop this test's software TPM
|
||||||
ASCII_RUNTIME_MEASUREMENTS="/sys/kernel/security/ima/ascii_runtime_measurements"
|
|
||||||
else
|
|
||||||
BINARY_BIOS_MEASUREMENTS="./sample-binary_bios_measurements-pcrs-8-9"
|
|
||||||
ASCII_RUNTIME_MEASUREMENTS="./sample-ascii_runtime_measurements-pcrs-8-9"
|
|
||||||
export TPM_INTERFACE_TYPE="socsim"
|
|
||||||
export TPM_COMMAND_PORT=2321
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Only stop this test's software TPM. Preferred method: "tsstpmcmd -stop"
|
|
||||||
cleanup() {
|
cleanup() {
|
||||||
if [ ! -z "${SWTPM_PPID}" ]; then
|
if [ -n "${SWTPM_PID}" ]; then
|
||||||
if [ -f "${TSSDIR}/tsstpmcmd" ]; then
|
kill -SIGTERM "${SWTPM_PID}"
|
||||||
|
elif [ -n "${TPMSERVER_PID}" ]; then
|
||||||
"${TSSDIR}/tsstpmcmd" -stop
|
"${TSSDIR}/tsstpmcmd" -stop
|
||||||
else
|
|
||||||
pkill -P "${SWTPM_PPID}"
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Try to start a software TPM if needed.
|
# Try to start a software TPM if needed.
|
||||||
swtpm_start() {
|
swtpm_start() {
|
||||||
local swtpm
|
local tpm_server swtpm
|
||||||
|
|
||||||
swtpm="$(which tpm_server)"
|
tpm_server="$(which tpm_server)"
|
||||||
if [ -z "${swtpm}" ]; then
|
swtpm="$(which swtpm)"
|
||||||
echo "${CYAN}SKIP: Softare TPM (tpm_server) not found${NORM}"
|
if [ -z "${tpm_server}" ] && [ -z "${swtpm}" ]; then
|
||||||
|
echo "${CYAN}SKIP: Software TPM (tpm_server and swtpm) not found${NORM}"
|
||||||
return "$SKIP"
|
return "$SKIP"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -n "${swtpm}" ]; then
|
||||||
|
pgrep swtpm
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "INFO: Software TPM (swtpm) already running"
|
||||||
|
return 114
|
||||||
|
else
|
||||||
|
echo "INFO: Starting software TPM: ${swtpm}"
|
||||||
|
mkdir -p ./myvtpm
|
||||||
|
${swtpm} socket --tpmstate dir=./myvtpm --tpm2 --ctrl type=tcp,port=2322 --server type=tcp,port=2321 --flags not-need-init > /dev/null 2>&1 &
|
||||||
|
SWTPM_PID=$!
|
||||||
|
fi
|
||||||
|
elif [ -n "${tpm_server}" ]; then
|
||||||
|
# tpm_server uses the Microsoft simulator encapsulated packet format
|
||||||
|
export TPM_SERVER_TYPE="mssim"
|
||||||
pgrep tpm_server
|
pgrep tpm_server
|
||||||
if [ $? -eq 0 ]; then
|
if [ $? -eq 0 ]; then
|
||||||
echo "INFO: Software TPM (tpm_server) already running"
|
echo "INFO: Software TPM (tpm_server) already running"
|
||||||
return 114
|
return 114
|
||||||
else
|
else
|
||||||
echo "INFO: Starting software TPM: ${swtpm}"
|
echo "INFO: Starting software TPM: ${tpm_server}"
|
||||||
${swtpm} > /dev/null 2>&1 &
|
${tpm_server} > /dev/null 2>&1 &
|
||||||
SWTPM_PPID=$!
|
TPMSERVER_PID=$!
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -75,8 +80,20 @@ swtpm_init() {
|
|||||||
return "$SKIP"
|
return "$SKIP"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "INFO: Walking ${BINARY_BIOS_MEASUREMENTS} initializing the software TPM"
|
echo "INFO: Sending software TPM startup"
|
||||||
"${TSSDIR}/tssstartup"
|
"${TSSDIR}/tssstartup"
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "INFO: Retry sending software TPM startup"
|
||||||
|
sleep 1
|
||||||
|
"${TSSDIR}/tssstartup"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "INFO: Software TPM startup failed"
|
||||||
|
return "$SKIP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "INFO: Walking ${BINARY_BIOS_MEASUREMENTS} initializing the software TPM"
|
||||||
# $(${TSSDIR}/tsseventextend -tpm -if "${BINARY_BIOS_MEASUREMENTS}" -v) 2>&1 > /dev/null
|
# $(${TSSDIR}/tsseventextend -tpm -if "${BINARY_BIOS_MEASUREMENTS}" -v) 2>&1 > /dev/null
|
||||||
"${TSSDIR}/tsseventextend" -tpm -if "${BINARY_BIOS_MEASUREMENTS}" -v > /dev/null 2>&1
|
"${TSSDIR}/tsseventextend" -tpm -if "${BINARY_BIOS_MEASUREMENTS}" -v > /dev/null 2>&1
|
||||||
}
|
}
|
||||||
@ -101,7 +118,7 @@ display_pcrs() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
# The first entry in the IMA measuremnet list is the "boot_aggregate".
|
# The first entry in the IMA measurement list is the "boot_aggregate".
|
||||||
# For each kexec, an additional "boot_aggregate" will appear in the
|
# For each kexec, an additional "boot_aggregate" will appear in the
|
||||||
# measurement list, assuming the previous measurement list is carried
|
# measurement list, assuming the previous measurement list is carried
|
||||||
# across the kexec.
|
# across the kexec.
|
||||||
@ -133,6 +150,24 @@ check() {
|
|||||||
return "$FAIL"
|
return "$FAIL"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if [ "$(id -u)" = 0 ] && [ -c "/dev/tpm0" ]; then
|
||||||
|
ASCII_RUNTIME_MEASUREMENTS="/sys/kernel/security/ima/ascii_runtime_measurements"
|
||||||
|
if [ ! -d "/sys/kernel/security/ima" ]; then
|
||||||
|
echo "${CYAN}SKIP: CONFIG_IMA not enabled${NORM}"
|
||||||
|
exit "$SKIP"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
BINARY_BIOS_MEASUREMENTS="./sample-binary_bios_measurements-pcrs-8-9"
|
||||||
|
ASCII_RUNTIME_MEASUREMENTS="./sample-ascii_runtime_measurements-pcrs-8-9"
|
||||||
|
export TPM_INTERFACE_TYPE="socsim"
|
||||||
|
export TPM_COMMAND_PORT=2321
|
||||||
|
export TPM_PLATFORM_PORT=2322
|
||||||
|
export TPM_SERVER_NAME="localhost"
|
||||||
|
|
||||||
|
# swtpm uses the raw, unencapsulated packet format
|
||||||
|
export TPM_SERVER_TYPE="raw"
|
||||||
|
fi
|
||||||
|
|
||||||
# Start and initialize a software TPM as needed
|
# Start and initialize a software TPM as needed
|
||||||
if [ "$(id -u)" != 0 ] || [ ! -c "/dev/tpm0" ]; then
|
if [ "$(id -u)" != 0 ] || [ ! -c "/dev/tpm0" ]; then
|
||||||
if [ -f "$PCRFILE" ] || [ -f "$MISC_PCRFILE" ]; then
|
if [ -f "$PCRFILE" ] || [ -f "$MISC_PCRFILE" ]; then
|
||||||
|
@ -248,8 +248,12 @@ _enable_gost_engine() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Show test stats and exit into automake test system
|
# Show test stats and exit into automake test system
|
||||||
# with proper exit code (same as ours).
|
# with proper exit code (same as ours). Do cleanups.
|
||||||
_report_exit() {
|
_report_exit_and_cleanup() {
|
||||||
|
if [ -n "${WORKDIR}" ]; then
|
||||||
|
rm -rf "${WORKDIR}"
|
||||||
|
fi
|
||||||
|
|
||||||
if [ $testsfail -gt 0 ]; then
|
if [ $testsfail -gt 0 ]; then
|
||||||
echo "================================="
|
echo "================================="
|
||||||
echo " Run with FAILEARLY=1 $0 $*"
|
echo " Run with FAILEARLY=1 $0 $*"
|
||||||
@ -272,3 +276,40 @@ _report_exit() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Setup SoftHSM for local testing by calling the softhsm_setup script.
|
||||||
|
# Use the provided workdir as the directory where SoftHSM will store its state
|
||||||
|
# into.
|
||||||
|
# Upon successfully setting up SoftHSM, this function sets the global variables
|
||||||
|
# OPENSSL_ENGINE and OPENSSL_KEYFORM so that the openssl command line tool can
|
||||||
|
# use SoftHSM. Also the PKCS11_KEYURI global variable is set to the test key's
|
||||||
|
# pkcs11 URI.
|
||||||
|
_softhsm_setup() {
|
||||||
|
local workdir="$1"
|
||||||
|
|
||||||
|
local msg
|
||||||
|
|
||||||
|
export SOFTHSM_SETUP_CONFIGDIR="${workdir}/softhsm"
|
||||||
|
export SOFTHSM2_CONF="${workdir}/softhsm/softhsm2.conf"
|
||||||
|
|
||||||
|
mkdir -p "${SOFTHSM_SETUP_CONFIGDIR}"
|
||||||
|
|
||||||
|
msg=$(./softhsm_setup setup 2>&1)
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "softhsm_setup setup succeeded: $msg"
|
||||||
|
PKCS11_KEYURI=$(echo $msg | sed -n 's|^keyuri: \(.*\)|\1|p')
|
||||||
|
|
||||||
|
export EVMCTL_ENGINE="--engine pkcs11"
|
||||||
|
export OPENSSL_ENGINE="-engine pkcs11"
|
||||||
|
export OPENSSL_KEYFORM="-keyform engine"
|
||||||
|
else
|
||||||
|
echo "softhsm_setup setup failed: ${msg}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Tear down the SoftHSM setup and clean up the environment
|
||||||
|
_softhsm_teardown() {
|
||||||
|
./softhsm_setup teardown &>/dev/null
|
||||||
|
rm -rf "${SOFTHSM_SETUP_CONFIGDIR}"
|
||||||
|
unset SOFTHSM_SETUP_CONFIGDIR SOFTHSM2_CONF PKCS11_KEYURI \
|
||||||
|
EVMCTL_ENGINE OPENSSL_ENGINE OPENSSL_KEYFORM
|
||||||
|
}
|
@ -20,13 +20,14 @@ PATH=../src:$PATH
|
|||||||
type openssl
|
type openssl
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
echo - "$*"
|
echo >&2 - "$*"
|
||||||
eval "$@"
|
eval "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ "$1" = clean ]; then
|
if [ "$1" = clean ]; then
|
||||||
rm -f test-ca.conf
|
rm -f test-ca.conf
|
||||||
elif [ "$1" = force ] || [ ! -e test-ca.conf ]; then
|
elif [ "$1" = force ] || [ ! -e test-ca.conf ] \
|
||||||
|
|| [ gen-keys.sh -nt test-ca.conf ]; then
|
||||||
cat > test-ca.conf <<- EOF
|
cat > test-ca.conf <<- EOF
|
||||||
[ req ]
|
[ req ]
|
||||||
distinguished_name = req_distinguished_name
|
distinguished_name = req_distinguished_name
|
||||||
@ -43,26 +44,64 @@ cat > test-ca.conf <<- EOF
|
|||||||
basicConstraints=CA:TRUE
|
basicConstraints=CA:TRUE
|
||||||
subjectKeyIdentifier=hash
|
subjectKeyIdentifier=hash
|
||||||
authorityKeyIdentifier=keyid:always,issuer
|
authorityKeyIdentifier=keyid:always,issuer
|
||||||
|
|
||||||
|
[ skid ]
|
||||||
|
basicConstraints=CA:TRUE
|
||||||
|
subjectKeyIdentifier=12345678
|
||||||
|
authorityKeyIdentifier=keyid:always,issuer
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# RSA
|
# RSA
|
||||||
# Second key will be used for wrong key tests.
|
# Second key will be used for wrong key tests.
|
||||||
for m in 1024 2048; do
|
for m in 1024 1024_skid 2048; do
|
||||||
if [ "$1" = clean ] || [ "$1" = force ]; then
|
if [ "$1" = clean ] || [ "$1" = force ] \
|
||||||
|
|| [ gen-keys.sh -nt test-rsa$m.key ]; then
|
||||||
rm -f test-rsa$m.cer test-rsa$m.key test-rsa$m.pub
|
rm -f test-rsa$m.cer test-rsa$m.key test-rsa$m.pub
|
||||||
fi
|
fi
|
||||||
if [ "$1" = clean ]; then
|
if [ "$1" = clean ]; then
|
||||||
continue
|
continue
|
||||||
fi
|
fi
|
||||||
|
if [ -z "${m%%*_*}" ]; then
|
||||||
|
# Add named extension.
|
||||||
|
bits=${m%_*}
|
||||||
|
ext="-extensions ${m#*_}"
|
||||||
|
else
|
||||||
|
bits=$m
|
||||||
|
ext=
|
||||||
|
fi
|
||||||
if [ ! -e test-rsa$m.key ]; then
|
if [ ! -e test-rsa$m.key ]; then
|
||||||
log openssl req -verbose -new -nodes -utf8 -sha1 -days 10000 -batch -x509 \
|
log openssl req -verbose -new -nodes -utf8 -sha1 -days 10000 -batch -x509 $ext \
|
||||||
-config test-ca.conf \
|
-config test-ca.conf \
|
||||||
-newkey rsa:$m \
|
-newkey rsa:$bits \
|
||||||
-out test-rsa$m.cer -outform DER \
|
-out test-rsa$m.cer -outform DER \
|
||||||
-keyout test-rsa$m.key
|
-keyout test-rsa$m.key
|
||||||
# for v1 signatures
|
# for v1 signatures
|
||||||
log openssl pkey -in test-rsa$m.key -out test-rsa$m.pub -pubout
|
log openssl pkey -in test-rsa$m.key -out test-rsa$m.pub -pubout
|
||||||
|
if [ $m = 1024_skid ]; then
|
||||||
|
# Create combined key+cert.
|
||||||
|
log openssl x509 -inform DER -in test-rsa$m.cer >> test-rsa$m.key
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
for curve in prime192v1 prime256v1; do
|
||||||
|
if [ "$1" = clean ] || [ "$1" = force ]; then
|
||||||
|
rm -f test-$curve.cer test-$curve.key test-$curve.pub
|
||||||
|
fi
|
||||||
|
if [ "$1" = clean ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ ! -e test-$curve.key ]; then
|
||||||
|
log openssl req -verbose -new -nodes -utf8 -sha1 -days 10000 -batch -x509 \
|
||||||
|
-config test-ca.conf \
|
||||||
|
-newkey ec \
|
||||||
|
-pkeyopt ec_paramgen_curve:$curve \
|
||||||
|
-out test-$curve.cer -outform DER \
|
||||||
|
-keyout test-$curve.key
|
||||||
|
if [ -s test-$curve.key ]; then
|
||||||
|
log openssl pkey -in test-$curve.key -out test-$curve.pub -pubout
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
@ -92,6 +131,31 @@ for m in \
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# SM2, If openssl 3.0 is installed, gen SM2 keys using
|
||||||
|
if [ -x /opt/openssl3/bin/openssl ]; then
|
||||||
|
(PATH=/opt/openssl3/bin:$PATH LD_LIBRARY_PATH=/opt/openssl3/lib
|
||||||
|
for curve in sm2; do
|
||||||
|
if [ "$1" = clean ] || [ "$1" = force ]; then
|
||||||
|
rm -f test-$curve.cer test-$curve.key test-$curve.pub
|
||||||
|
fi
|
||||||
|
if [ "$1" = clean ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [ ! -e test-$curve.key ]; then
|
||||||
|
log openssl req -verbose -new -nodes -utf8 -days 10000 -batch -x509 \
|
||||||
|
-sm3 -sigopt "distid:1234567812345678" \
|
||||||
|
-config test-ca.conf \
|
||||||
|
-copy_extensions copyall \
|
||||||
|
-newkey $curve \
|
||||||
|
-out test-$curve.cer -outform DER \
|
||||||
|
-keyout test-$curve.key
|
||||||
|
if [ -s test-$curve.key ]; then
|
||||||
|
log openssl pkey -in test-$curve.key -out test-$curve.pub -pubout
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done)
|
||||||
|
fi
|
||||||
|
|
||||||
# This script leaves test-ca.conf, *.cer, *.pub, *.key files for sing/verify tests.
|
# This script leaves test-ca.conf, *.cer, *.pub, *.key files for sing/verify tests.
|
||||||
# They are never deleted except by `make distclean'.
|
# They are never deleted except by `make distclean'.
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ PATH=../src:$PATH
|
|||||||
source ./functions.sh
|
source ./functions.sh
|
||||||
_require evmctl openssl getfattr
|
_require evmctl openssl getfattr
|
||||||
|
|
||||||
trap _report_exit EXIT
|
trap _report_exit_and_cleanup EXIT
|
||||||
set -f # disable globbing
|
set -f # disable globbing
|
||||||
|
|
||||||
check() {
|
check() {
|
||||||
@ -70,8 +70,7 @@ expect_pass check sha256 0x0404 e3b0c44298fc1c149afbf4c8996fb92427ae41e4649
|
|||||||
expect_pass check sha384 0x0405 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b
|
expect_pass check sha384 0x0405 38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b
|
||||||
expect_pass check sha512 0x0406 cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
|
expect_pass check sha512 0x0406 cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e
|
||||||
expect_pass check rmd160 0x0403 9c1185a5c5e9fc54612808977ee8f548b2258d31
|
expect_pass check rmd160 0x0403 9c1185a5c5e9fc54612808977ee8f548b2258d31
|
||||||
expect_fail check sm3 0x01
|
expect_pass check sm3 0x0411 1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b
|
||||||
expect_fail check sm3-256 0x01
|
|
||||||
_enable_gost_engine
|
_enable_gost_engine
|
||||||
expect_pass check md_gost12_256 0x0412 3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb
|
expect_pass check md_gost12_256 0x0412 3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb
|
||||||
expect_pass check streebog256 0x0412 3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb
|
expect_pass check streebog256 0x0412 3f539a213e97c802cc229d474c6aa32a825a360b2a933a949fd925208d9ce1bb
|
||||||
|
23
tests/install-openssl3.sh
Executable file
23
tests/install-openssl3.sh
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
if [ -z "$COMPILE_SSL" ]; then
|
||||||
|
echo "Missing \$COMPILE_SSL!" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
version=${COMPILE_SSL}
|
||||||
|
|
||||||
|
wget --no-check-certificate https://github.com/openssl/openssl/archive/refs/tags/${version}.tar.gz
|
||||||
|
tar --no-same-owner -xzf ${version}.tar.gz
|
||||||
|
cd openssl-${version}
|
||||||
|
|
||||||
|
./Configure --prefix=/opt/openssl3 --openssldir=/opt/openssl3/ssl
|
||||||
|
make -j$(nproc)
|
||||||
|
# only install apps and library
|
||||||
|
sudo make install_sw
|
||||||
|
|
||||||
|
cd ..
|
||||||
|
rm -rf ${version}.tar.gz
|
||||||
|
rm -rf openssl-${version}
|
21
tests/install-swtpm.sh
Executable file
21
tests/install-swtpm.sh
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/sh -ex
|
||||||
|
|
||||||
|
# No need to run via sudo if we already have permissions.
|
||||||
|
# Also, some distros do not have sudo configured for root:
|
||||||
|
# `root is not in the sudoers file. This incident will be reported.'
|
||||||
|
if [ -w /usr/local/bin ]; then
|
||||||
|
SUDO=
|
||||||
|
else
|
||||||
|
SUDO=sudo
|
||||||
|
fi
|
||||||
|
|
||||||
|
version=1637
|
||||||
|
|
||||||
|
wget --no-check-certificate https://sourceforge.net/projects/ibmswtpm2/files/ibmtpm${version}.tar.gz/download
|
||||||
|
mkdir ibmtpm$version
|
||||||
|
cd ibmtpm$version
|
||||||
|
tar --no-same-owner -xvzf ../download
|
||||||
|
cd src
|
||||||
|
make -j$(nproc)
|
||||||
|
$SUDO cp tpm_server /usr/local/bin/
|
||||||
|
cd ../..
|
8
tests/install-tss.sh
Executable file
8
tests/install-tss.sh
Executable file
@ -0,0 +1,8 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
git clone https://git.code.sf.net/p/ibmtpm20tss/tss
|
||||||
|
cd tss
|
||||||
|
autoreconf -i && ./configure --disable-tpm-1.2 --disable-hwtpm && make -j$(nproc) && sudo make install
|
||||||
|
cd ..
|
||||||
|
rm -rf tss
|
@ -18,10 +18,18 @@
|
|||||||
cd "$(dirname "$0")" || exit 1
|
cd "$(dirname "$0")" || exit 1
|
||||||
PATH=../src:$PATH
|
PATH=../src:$PATH
|
||||||
source ./functions.sh
|
source ./functions.sh
|
||||||
_require evmctl openssl xxd getfattr
|
|
||||||
|
_require cmp evmctl getfattr openssl xxd
|
||||||
|
|
||||||
|
if cmp -b 2>&1 | grep -q "invalid option"; then
|
||||||
|
echo "cmp does not support -b (cmp from busybox?) Use cmp from diffutils"
|
||||||
|
exit "$HARDFAIL"
|
||||||
|
fi
|
||||||
|
|
||||||
./gen-keys.sh >/dev/null 2>&1
|
./gen-keys.sh >/dev/null 2>&1
|
||||||
|
|
||||||
trap _report_exit EXIT
|
trap _report_exit_and_cleanup EXIT
|
||||||
|
WORKDIR=$(mktemp -d)
|
||||||
set -f # disable globbing
|
set -f # disable globbing
|
||||||
|
|
||||||
# Determine keyid from a cert
|
# Determine keyid from a cert
|
||||||
@ -36,6 +44,7 @@ _keyid_from_cert() {
|
|||||||
id=$($cmd 2>/dev/null \
|
id=$($cmd 2>/dev/null \
|
||||||
| openssl asn1parse \
|
| openssl asn1parse \
|
||||||
| grep BIT.STRING \
|
| grep BIT.STRING \
|
||||||
|
| tail -n1 \
|
||||||
| cut -d: -f1)
|
| cut -d: -f1)
|
||||||
if [ -z "$id" ]; then
|
if [ -z "$id" ]; then
|
||||||
echo - "$cmd" >&2
|
echo - "$cmd" >&2
|
||||||
@ -93,7 +102,8 @@ _test_sigfile() {
|
|||||||
return "$FAIL"
|
return "$FAIL"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm "$file_sig" "$file_sig2"
|
# Leave '$file_sig' for ima_verify --sigfile test.
|
||||||
|
rm "$file_sig2"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Run single sign command
|
# Run single sign command
|
||||||
@ -123,11 +133,16 @@ check_sign() {
|
|||||||
# OPTS (additional options for evmctl),
|
# OPTS (additional options for evmctl),
|
||||||
# FILE (working file to sign).
|
# FILE (working file to sign).
|
||||||
local "$@"
|
local "$@"
|
||||||
local KEY=${KEY%.*}.key
|
local key verifykey
|
||||||
local FILE=${FILE:-$ALG.txt}
|
local FILE=${FILE:-$ALG.txt}
|
||||||
|
|
||||||
# Normalize key filename
|
# Normalize key filename if it's not a pkcs11 URI
|
||||||
KEY=test-${KEY#test-}
|
if [ ${KEY:0:7} != pkcs11: ]; then
|
||||||
|
key=${KEY%.*}.key
|
||||||
|
key=test-${key#test-}
|
||||||
|
else
|
||||||
|
key=${KEY}
|
||||||
|
fi
|
||||||
|
|
||||||
# Append suffix to files for negative tests, because we may
|
# Append suffix to files for negative tests, because we may
|
||||||
# leave only good files for verify tests.
|
# leave only good files for verify tests.
|
||||||
@ -143,33 +158,33 @@ check_sign() {
|
|||||||
|
|
||||||
if _test_expected_to_pass; then
|
if _test_expected_to_pass; then
|
||||||
# Can openssl work with this digest?
|
# Can openssl work with this digest?
|
||||||
cmd="openssl dgst $OPENSSL_ENGINE -$ALG $FILE"
|
cmd="openssl dgst $OPENSSL_ENGINE $OPENSSL_KEYFORM -$ALG $FILE"
|
||||||
echo - "$cmd"
|
echo - "$cmd"
|
||||||
if ! $cmd >/dev/null; then
|
if ! $cmd >/dev/null; then
|
||||||
echo "${CYAN}$ALG ($KEY) test is skipped (openssl is unable to digest)$NORM"
|
echo "${CYAN}$ALG ($key) test is skipped (openssl is unable to digest)$NORM"
|
||||||
return "$SKIP"
|
return "$SKIP"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -e "$KEY" ]; then
|
if [ "${key:0:7}" != pkcs11: ] && [ ! -e "$key" ]; then
|
||||||
echo "${CYAN}$ALG ($KEY) test is skipped (key file not found)$NORM"
|
echo "${CYAN}$ALG ($key) test is skipped (key file not found)$NORM"
|
||||||
return "$SKIP"
|
return "$SKIP"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Can openssl sign with this digest and key?
|
# Can openssl sign with this digest and key?
|
||||||
cmd="openssl dgst $OPENSSL_ENGINE -$ALG -sign $KEY -hex $FILE"
|
cmd="openssl dgst $OPENSSL_ENGINE $OPENSSL_KEYFORM -$ALG -sign $key -hex $FILE"
|
||||||
echo - "$cmd"
|
echo - "$cmd"
|
||||||
if ! $cmd >/dev/null; then
|
if ! $cmd >/dev/null; then
|
||||||
echo "${CYAN}$ALG ($KEY) test is skipped (openssl is unable to sign)$NORM"
|
echo "${CYAN}$ALG ($key) test is skipped (openssl is unable to sign)$NORM"
|
||||||
return "$SKIP"
|
return "$SKIP"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Insert keyid from cert into PREFIX in-place of marker `:K:'
|
# Insert keyid from cert into PREFIX in-place of marker `:K:'
|
||||||
if [[ $PREFIX =~ :K: ]]; then
|
if [[ $PREFIX =~ :K: ]]; then
|
||||||
keyid=$(_keyid_from_cert "$KEY")
|
keyid=$(_keyid_from_cert "$key")
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
color_red
|
color_red
|
||||||
echo "Unable to determine keyid for $KEY"
|
echo "Unable to determine keyid for $key"
|
||||||
color_restore
|
color_restore
|
||||||
return "$HARDFAIL"
|
return "$HARDFAIL"
|
||||||
fi
|
fi
|
||||||
@ -178,7 +193,7 @@ check_sign() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Perform signing by evmctl
|
# Perform signing by evmctl
|
||||||
_evmctl_sign "$TYPE" "$KEY" "$ALG" "$FILE" "$OPTS" || return
|
_evmctl_sign "$TYPE" "$key" "$ALG" "$FILE" "$OPTS" || return
|
||||||
|
|
||||||
# First simple pattern match the signature.
|
# First simple pattern match the signature.
|
||||||
ADD_TEXT_FOR=$ALG \
|
ADD_TEXT_FOR=$ALG \
|
||||||
@ -190,11 +205,21 @@ check_sign() {
|
|||||||
# This is all we can do for evm.
|
# This is all we can do for evm.
|
||||||
[[ "$TYPE" =~ evm ]] && return "$OK"
|
[[ "$TYPE" =~ evm ]] && return "$OK"
|
||||||
|
|
||||||
|
# When using the SM2/3 algorithm, the openssl tool uses USERID for verify,
|
||||||
|
# which is incompatible with calling API directly, so skip it.
|
||||||
|
[[ "$ALG" == sm3 ]] && return "$OK"
|
||||||
|
|
||||||
# Extract signature to a file
|
# Extract signature to a file
|
||||||
_extract_xattr "$FILE" "$(_xattr "$TYPE")" "$FILE.sig2" "$PREFIX"
|
_extract_xattr "$FILE" "$(_xattr "$TYPE")" "$FILE.sig2" "$PREFIX"
|
||||||
|
|
||||||
# Verify extracted signature with openssl
|
# Verify extracted signature with openssl
|
||||||
cmd="openssl dgst $OPENSSL_ENGINE -$ALG -verify ${KEY%.*}.pub \
|
if [ "${key:0:7}" != pkcs11: ]; then
|
||||||
|
verifykey=${key%.*}.pub
|
||||||
|
else
|
||||||
|
verifykey=${key}
|
||||||
|
fi
|
||||||
|
|
||||||
|
cmd="openssl dgst $OPENSSL_ENGINE $OPENSSL_KEYFORM -$ALG -verify ${verifykey} \
|
||||||
-signature $FILE.sig2 $FILE"
|
-signature $FILE.sig2 $FILE"
|
||||||
echo - "$cmd"
|
echo - "$cmd"
|
||||||
if ! $cmd; then
|
if ! $cmd; then
|
||||||
@ -254,9 +279,12 @@ sign_verify() {
|
|||||||
|
|
||||||
# Normal verify with proper key should pass
|
# Normal verify with proper key should pass
|
||||||
expect_pass check_verify
|
expect_pass check_verify
|
||||||
|
expect_pass check_verify OPTS="--sigfile"
|
||||||
|
|
||||||
# Multiple files and some don't verify
|
# Multiple files and some don't verify
|
||||||
expect_fail check_verify FILE="/dev/null $file"
|
expect_fail check_verify FILE="/dev/null $file"
|
||||||
|
|
||||||
|
rm "$FILE.sig"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
TYPE=evm
|
TYPE=evm
|
||||||
@ -317,9 +345,14 @@ try_different_sigs() {
|
|||||||
expect_fail check_verify TYPE=ima
|
expect_fail check_verify TYPE=ima
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Test --portable
|
# Test --portable (only supported for V2 signatures)
|
||||||
expect_pass check_sign OPTS="$OPTS --portable" PREFIX=0x05
|
if expect_pass check_sign OPTS="$OPTS --portable --imahash" PREFIX=0x05; then
|
||||||
# Cannot be verified for now, until that support is added to evmctl
|
if [[ "$OPTS" =~ --rsa ]]; then
|
||||||
|
expect_fail check_verify
|
||||||
|
else
|
||||||
|
expect_pass check_verify
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Test -i (immutable)
|
# Test -i (immutable)
|
||||||
expect_pass check_sign OPTS="$OPTS -i" PREFIX=0x0303
|
expect_pass check_sign OPTS="$OPTS -i" PREFIX=0x0303
|
||||||
@ -348,6 +381,9 @@ sign_verify rsa1024 sha256 0x0301 --rsa
|
|||||||
sign_verify rsa1024 md5 0x030201:K:0080
|
sign_verify rsa1024 md5 0x030201:K:0080
|
||||||
sign_verify rsa1024 sha1 0x030202:K:0080
|
sign_verify rsa1024 sha1 0x030202:K:0080
|
||||||
sign_verify rsa1024 sha224 0x030207:K:0080
|
sign_verify rsa1024 sha224 0x030207:K:0080
|
||||||
|
expect_pass check_sign TYPE=ima KEY=rsa1024 ALG=sha256 PREFIX=0x030204aabbccdd0080 OPTS=--keyid=aabbccdd
|
||||||
|
expect_pass check_sign TYPE=ima KEY=rsa1024 ALG=sha256 PREFIX=0x030204:K:0080 OPTS=--keyid-from-cert=test-rsa1024.cer
|
||||||
|
expect_pass check_sign TYPE=ima KEY=rsa1024_skid ALG=sha256 PREFIX=0x030204123456780080
|
||||||
sign_verify rsa1024 sha256 0x030204:K:0080
|
sign_verify rsa1024 sha256 0x030204:K:0080
|
||||||
try_different_keys
|
try_different_keys
|
||||||
try_different_sigs
|
try_different_sigs
|
||||||
@ -355,6 +391,27 @@ sign_verify rsa1024 sha384 0x030205:K:0080
|
|||||||
sign_verify rsa1024 sha512 0x030206:K:0080
|
sign_verify rsa1024 sha512 0x030206:K:0080
|
||||||
sign_verify rsa1024 rmd160 0x030203:K:0080
|
sign_verify rsa1024 rmd160 0x030203:K:0080
|
||||||
|
|
||||||
|
# Test v2 signatures with ECDSA
|
||||||
|
# Signature length is typically 0x34-0x38 bytes long, very rarely 0x33
|
||||||
|
sign_verify prime192v1 sha1 0x030202:K:003[345678]
|
||||||
|
sign_verify prime192v1 sha224 0x030207:K:003[345678]
|
||||||
|
sign_verify prime192v1 sha256 0x030204:K:003[345678]
|
||||||
|
sign_verify prime192v1 sha384 0x030205:K:003[345678]
|
||||||
|
sign_verify prime192v1 sha512 0x030206:K:003[345678]
|
||||||
|
|
||||||
|
# Signature length is typically 0x44-0x48 bytes long, very rarely 0x43
|
||||||
|
sign_verify prime256v1 sha1 0x030202:K:004[345678]
|
||||||
|
sign_verify prime256v1 sha224 0x030207:K:004[345678]
|
||||||
|
sign_verify prime256v1 sha256 0x030204:K:004[345678]
|
||||||
|
sign_verify prime256v1 sha384 0x030205:K:004[345678]
|
||||||
|
sign_verify prime256v1 sha512 0x030206:K:004[345678]
|
||||||
|
|
||||||
|
# If openssl 3.0 is installed, test the SM2/3 algorithm combination
|
||||||
|
if [ -x /opt/openssl3/bin/openssl ]; then
|
||||||
|
PATH=/opt/openssl3/bin:$PATH LD_LIBRARY_PATH=/opt/openssl3/lib \
|
||||||
|
sign_verify sm2 sm3 0x030211:K:004[345678]
|
||||||
|
fi
|
||||||
|
|
||||||
# Test v2 signatures with EC-RDSA
|
# Test v2 signatures with EC-RDSA
|
||||||
_enable_gost_engine
|
_enable_gost_engine
|
||||||
sign_verify gost2012_256-A md_gost12_256 0x030212:K:0040
|
sign_verify gost2012_256-A md_gost12_256 0x030212:K:0040
|
||||||
@ -368,3 +425,15 @@ expect_fail \
|
|||||||
expect_fail \
|
expect_fail \
|
||||||
check_sign TYPE=ima KEY=gost2012_256-B ALG=md_gost12_512 PREFIX=0x0302 OPTS=
|
check_sign TYPE=ima KEY=gost2012_256-B ALG=md_gost12_512 PREFIX=0x0302 OPTS=
|
||||||
|
|
||||||
|
# Test signing with key described by pkcs11 URI
|
||||||
|
_softhsm_setup "${WORKDIR}"
|
||||||
|
if [ -n "${PKCS11_KEYURI}" ]; then
|
||||||
|
expect_pass check_sign FILE=pkcs11test TYPE=ima KEY=${PKCS11_KEYURI} ALG=sha256 PREFIX=0x030204aabbccdd0100 OPTS=--keyid=aabbccdd
|
||||||
|
expect_pass check_sign FILE=pkcs11test TYPE=ima KEY=${PKCS11_KEYURI} ALG=sha1 PREFIX=0x030202aabbccdd0100 OPTS=--keyid=aabbccdd
|
||||||
|
else
|
||||||
|
# to have a constant number of tests, skip these two tests
|
||||||
|
__skip() { echo "pkcs11 test is skipped: could not setup softhsm"; return $SKIP; }
|
||||||
|
expect_pass __skip
|
||||||
|
expect_pass __skip
|
||||||
|
fi
|
||||||
|
_softhsm_teardown "${WORKDIR}"
|
||||||
|
293
tests/softhsm_setup
Executable file
293
tests/softhsm_setup
Executable file
@ -0,0 +1,293 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# SPDX-License-Identifier: GPL-2.0 and BSD-3-clause
|
||||||
|
# This program originates from 'swtpm' project (https://github.com/stefanberger/swtpm/)
|
||||||
|
|
||||||
|
if [ -z "$(type -P p11tool)" ]; then
|
||||||
|
echo "Need p11tool from gnutls"
|
||||||
|
exit 77
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$(type -P softhsm2-util)" ]; then
|
||||||
|
echo "Need softhsm2-util from softhsm2 package"
|
||||||
|
exit 77
|
||||||
|
fi
|
||||||
|
|
||||||
|
MAJOR=$(softhsm2-util -v | cut -d '.' -f1)
|
||||||
|
MINOR=$(softhsm2-util -v | cut -d '.' -f2)
|
||||||
|
if [ ${MAJOR} -lt 2 ] || [ ${MAJOR} -eq 2 -a ${MINOR} -lt 2 ]; then
|
||||||
|
echo "Need softhsm v2.2.0 or later"
|
||||||
|
exit 77
|
||||||
|
fi
|
||||||
|
|
||||||
|
NAME=swtpm-test
|
||||||
|
PIN=${PIN:-1234}
|
||||||
|
SO_PIN=${SO_PIN:-1234}
|
||||||
|
SOFTHSM_SETUP_CONFIGDIR=${SOFTHSM_SETUP_CONFIGDIR:-~/.config/softhsm2}
|
||||||
|
export SOFTHSM2_CONF=${SOFTHSM_SETUP_CONFIGDIR}/softhsm2.conf
|
||||||
|
|
||||||
|
UNAME_S="$(uname -s)"
|
||||||
|
|
||||||
|
case "${UNAME_S}" in
|
||||||
|
Darwin)
|
||||||
|
msg=$(sudo -v -n)
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Need password-less sudo rights on OS X to change /etc/gnutls/pkcs11.conf"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
teardown_softhsm() {
|
||||||
|
local configdir=${SOFTHSM_SETUP_CONFIGDIR}
|
||||||
|
local configfile=${SOFTHSM2_CONF}
|
||||||
|
local bakconfigfile=${configfile}.bak
|
||||||
|
local tokendir=${configdir}/tokens
|
||||||
|
|
||||||
|
softhsm2-util --token "${NAME}" --delete-token &>/dev/null
|
||||||
|
|
||||||
|
case "${UNAME_S}" in
|
||||||
|
Darwin*)
|
||||||
|
if [ -f /etc/gnutls/pkcs11.conf.bak ]; then
|
||||||
|
sudo rm -f /etc/gnutls/pkcs11.conf
|
||||||
|
sudo mv /etc/gnutls/pkcs11.conf.bak \
|
||||||
|
/etc/gnutls/pkcs11.conf &>/dev/null
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ -f "$bakconfigfile" ]; then
|
||||||
|
mv "$bakconfigfile" "$configfile"
|
||||||
|
else
|
||||||
|
rm -f "$configfile"
|
||||||
|
fi
|
||||||
|
if [ -d "$tokendir" ]; then
|
||||||
|
rm -rf "${tokendir}"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_softhsm() {
|
||||||
|
local msg tokenuri keyuri
|
||||||
|
local configdir=${SOFTHSM_SETUP_CONFIGDIR}
|
||||||
|
local configfile=${SOFTHSM2_CONF}
|
||||||
|
local bakconfigfile=${configfile}.bak
|
||||||
|
local tokendir=${configdir}/tokens
|
||||||
|
local rc
|
||||||
|
|
||||||
|
case "${UNAME_S}" in
|
||||||
|
Darwin*)
|
||||||
|
if [ -f /etc/gnutls/pkcs11.conf.bak ]; then
|
||||||
|
echo "/etc/gnutls/pkcs11.conf.bak already exists; need to 'teardown' first"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
sudo mv /etc/gnutls/pkcs11.conf \
|
||||||
|
/etc/gnutls/pkcs11.conf.bak &>/dev/null
|
||||||
|
if [ $(id -u) -eq 0 ]; then
|
||||||
|
SONAME="$(sudo -u nobody brew ls --verbose softhsm | \
|
||||||
|
grep -E "\.so$")"
|
||||||
|
else
|
||||||
|
SONAME="$(brew ls --verbose softhsm | \
|
||||||
|
grep -E "\.so$")"
|
||||||
|
fi
|
||||||
|
sudo mkdir -p /etc/gnutls &>/dev/null
|
||||||
|
sudo bash -c "echo "load=${SONAME}" > /etc/gnutls/pkcs11.conf"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if ! [ -d $configdir ]; then
|
||||||
|
mkdir -p $configdir
|
||||||
|
fi
|
||||||
|
mkdir -p ${tokendir}
|
||||||
|
|
||||||
|
if [ -f $configfile ]; then
|
||||||
|
mv "$configfile" "$bakconfigfile"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! [ -f $configfile ]; then
|
||||||
|
cat <<_EOF_ > $configfile
|
||||||
|
directories.tokendir = ${tokendir}
|
||||||
|
objectstore.backend = file
|
||||||
|
log.level = DEBUG
|
||||||
|
slots.removable = false
|
||||||
|
_EOF_
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg=$(p11tool --list-tokens 2>&1 | grep "token=${NAME}" | tail -n1)
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Could not list existing tokens"
|
||||||
|
echo "$msg"
|
||||||
|
fi
|
||||||
|
tokenuri=$(echo "$msg" | sed -n 's/.*URL: \([[:print:]*]\)/\1/p')
|
||||||
|
|
||||||
|
if [ -z "$tokenuri" ]; then
|
||||||
|
msg=$(softhsm2-util \
|
||||||
|
--init-token --pin ${PIN} --so-pin ${SO_PIN} \
|
||||||
|
--free --label ${NAME} 2>&1)
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Could not initialize token"
|
||||||
|
echo "$msg"
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
slot=$(echo "$msg" | \
|
||||||
|
sed -n 's/.* reassigned to slot \([0-9]*\)$/\1/p')
|
||||||
|
if [ -z "$slot" ]; then
|
||||||
|
slot=$(softhsm2-util --show-slots | \
|
||||||
|
grep -E "^Slot " | head -n1 |
|
||||||
|
sed -n 's/Slot \([0-9]*\)/\1/p')
|
||||||
|
if [ -z "$slot" ]; then
|
||||||
|
echo "Could not parse slot number from output."
|
||||||
|
echo "$msg"
|
||||||
|
return 3
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
msg=$(p11tool --list-tokens 2>&1 | \
|
||||||
|
grep "token=${NAME}" | tail -n1)
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Could not list existing tokens"
|
||||||
|
echo "$msg"
|
||||||
|
fi
|
||||||
|
tokenuri=$(echo "$msg" | sed -n 's/.*URL: \([[:print:]*]\)/\1/p')
|
||||||
|
if [ -z "${tokenuri}" ]; then
|
||||||
|
echo "Could not get tokenuri!"
|
||||||
|
return 4
|
||||||
|
fi
|
||||||
|
|
||||||
|
# more recent versions of p11tool have --generate-privkey ...
|
||||||
|
msg=$(GNUTLS_PIN=$PIN p11tool \
|
||||||
|
--generate-privkey=rsa --bits 2048 --label mykey --login \
|
||||||
|
"${tokenuri}" 2>&1)
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
# ... older versions have --generate-rsa
|
||||||
|
msg=$(GNUTLS_PIN=$PIN p11tool \
|
||||||
|
--generate-rsa --bits 2048 --label mykey --login \
|
||||||
|
"${tokenuri}" 2>&1)
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Could not create RSA key!"
|
||||||
|
echo "$msg"
|
||||||
|
return 5
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
getkeyuri_softhsm $slot
|
||||||
|
rc=$?
|
||||||
|
if [ $rc -ne 0 ]; then
|
||||||
|
teardown_softhsm
|
||||||
|
fi
|
||||||
|
|
||||||
|
return $rc
|
||||||
|
}
|
||||||
|
|
||||||
|
_getkeyuri_softhsm() {
|
||||||
|
local msg tokenuri keyuri
|
||||||
|
|
||||||
|
msg=$(p11tool --list-tokens 2>&1 | grep "token=${NAME}")
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Could not list existing tokens"
|
||||||
|
echo "$msg"
|
||||||
|
return 5
|
||||||
|
fi
|
||||||
|
tokenuri=$(echo "$msg" | sed -n 's/.*URL: \([[:print:]*]\)/\1/p')
|
||||||
|
if [ -z "$tokenuri" ]; then
|
||||||
|
echo "Could not get token URL"
|
||||||
|
echo "$msg"
|
||||||
|
return 6
|
||||||
|
fi
|
||||||
|
msg=$(p11tool --list-all ${tokenuri} 2>&1)
|
||||||
|
if [ $? -ne 0 ]; then
|
||||||
|
echo "Could not list object under token $tokenuri"
|
||||||
|
echo "$msg"
|
||||||
|
softhsm2-util --show-slots
|
||||||
|
return 7
|
||||||
|
fi
|
||||||
|
|
||||||
|
keyuri=$(echo "$msg" | sed -n 's/.*URL: \([[:print:]*]\)/\1/p')
|
||||||
|
if [ -z "$keyuri" ]; then
|
||||||
|
echo "Could not get key URL"
|
||||||
|
echo "$msg"
|
||||||
|
return 8
|
||||||
|
fi
|
||||||
|
echo "$keyuri"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
getkeyuri_softhsm() {
|
||||||
|
local keyuri rc
|
||||||
|
|
||||||
|
keyuri=$(_getkeyuri_softhsm)
|
||||||
|
rc=$?
|
||||||
|
if [ $rc -ne 0 ]; then
|
||||||
|
return $rc
|
||||||
|
fi
|
||||||
|
echo "keyuri: $keyuri?pin-value=${PIN}" #&module-name=softhsm2"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
getpubkey_softhsm() {
|
||||||
|
local keyuri rc
|
||||||
|
|
||||||
|
keyuri=$(_getkeyuri_softhsm)
|
||||||
|
rc=$?
|
||||||
|
if [ $rc -ne 0 ]; then
|
||||||
|
return $rc
|
||||||
|
fi
|
||||||
|
GNUTLS_PIN=${PIN} p11tool --export-pubkey "${keyuri}" --login 2>/dev/null
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<_EOF_
|
||||||
|
Usage: $0 [command]
|
||||||
|
|
||||||
|
Supported commands are:
|
||||||
|
|
||||||
|
setup : Setup the user's account for softhsm and create a
|
||||||
|
token and key with a test configuration
|
||||||
|
|
||||||
|
getkeyuri : Get the key's URI; may only be called after setup
|
||||||
|
|
||||||
|
getpubkey : Get the public key in PEM format; may only be called after setup
|
||||||
|
|
||||||
|
teardown : Remove the temporary softhsm test configuration
|
||||||
|
|
||||||
|
_EOF_
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local ret
|
||||||
|
|
||||||
|
if [ $# -lt 1 ]; then
|
||||||
|
usage $0
|
||||||
|
echo -e "Missing command.\n\n"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
case "$1" in
|
||||||
|
setup)
|
||||||
|
setup_softhsm
|
||||||
|
ret=$?
|
||||||
|
;;
|
||||||
|
getkeyuri)
|
||||||
|
getkeyuri_softhsm
|
||||||
|
ret=$?
|
||||||
|
;;
|
||||||
|
getpubkey)
|
||||||
|
getpubkey_softhsm
|
||||||
|
ret=$?
|
||||||
|
;;
|
||||||
|
teardown)
|
||||||
|
teardown_softhsm
|
||||||
|
ret=$?
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo -e "Unsupported command: $1\n\n"
|
||||||
|
usage $0
|
||||||
|
ret=1
|
||||||
|
esac
|
||||||
|
return $ret
|
||||||
|
}
|
||||||
|
|
||||||
|
main "$@"
|
||||||
|
exit $?
|
Reference in New Issue
Block a user