mirror of
https://github.com/nsacyber/HIRS.git
synced 2024-12-18 20:47:58 +00:00
removed HIRS_Provisioner
This commit is contained in:
parent
a62e45ee2e
commit
1b582dfec6
64
.github/workflows/package_centos.yml
vendored
64
.github/workflows/package_centos.yml
vendored
@ -1,64 +0,0 @@
|
||||
name: HIRS packages for centos
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*v2*'
|
||||
- 'master'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
# run the package script for HIRS ACA, Provisioners, tcg_rim_tool, and tcg_eventlog_tool
|
||||
Package:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v2
|
||||
with:
|
||||
java-version: '8'
|
||||
distribution: 'adopt'
|
||||
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||
package_centos:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: directory setup
|
||||
run: |
|
||||
mkdir -p artifacts/jars
|
||||
mkdir -p artifacts/wars
|
||||
mkdir -p artifacts/rpms
|
||||
- name: Create HIRS packages
|
||||
run: |
|
||||
echo ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} | docker login -u ${{ secrets.DOCKER_HUB_USERNAME }} --password-stdin
|
||||
docker run --rm \
|
||||
-v $(pwd):/HIRS hirs/hirs-ci:centos7 /bin/bash \
|
||||
-c 'pushd /HIRS; \
|
||||
sh package/package.centos.sh; \
|
||||
cp /HIRS/package/rpm/RPMS/noarch/* /HIRS/artifacts/rpms/.; \
|
||||
cp /HIRS/package/rpm/RPMS/x86_64/* /HIRS/artifacts/rpms/.; \
|
||||
sh /HIRS/tools/tcg_rim_tool/package.sh; \
|
||||
cp /HIRS/tools/tcg_rim_tool/rpmbuild/BUILD/tcg_rim_tool/build/libs/* /HIRS/artifacts/jars/.; \
|
||||
cp /HIRS/tools/tcg_rim_tool/rpmbuild/RPMS/x86_64/* /HIRS/artifacts/rpms/.; \
|
||||
sh /HIRS/tools/tcg_eventlog_tool/gradlew clean buildRPM; \
|
||||
cp /HIRS/tools/tcg_eventlog_tool/build/libs/tools/* /HIRS/artifacts/jars/.; \
|
||||
cp /HIRS/tools/tcg_eventlog_tool/build/distributions/* /HIRS/artifacts/rpms/.; \
|
||||
popd;'
|
||||
- name: Archive RPM files
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: RPM_Files
|
||||
path: artifacts/rpms/*
|
||||
if-no-files-found: error
|
||||
- name: Archive Jar files
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: JAR_Files
|
||||
path: artifacts/jars/
|
@ -1,4 +0,0 @@
|
||||
TpmModuleExePath = exe
|
||||
ExeName = /tpm_module
|
||||
TrousersMode = False
|
||||
DebugMode = True
|
@ -1,78 +0,0 @@
|
||||
apply plugin: 'findbugs'
|
||||
apply plugin: 'checkstyle'
|
||||
apply plugin: 'application'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
mainClassName = "hirs.provisioner.ProvisionerApplication"
|
||||
|
||||
dependencies {
|
||||
compile project(':TPM_Utils')
|
||||
compile project(':HIRS_Structs')
|
||||
compile project(':HIRS_Utils')
|
||||
compile libs.spring_web
|
||||
compile libs.log_bridge
|
||||
compile libs.commons_lang
|
||||
|
||||
compileOnly libs.checkstyle
|
||||
compileOnly libs.findbugs
|
||||
|
||||
testCompile libs.testng
|
||||
testCompile libs.mockito
|
||||
testCompile libs.powermock
|
||||
testCompile libs.spring_test
|
||||
testCompile libs.checkstyle
|
||||
testCompile libs.findbugs
|
||||
testCompile libs.commons_lang
|
||||
}
|
||||
|
||||
copyVersion.dependsOn compileJava
|
||||
jar.dependsOn copyVersion
|
||||
|
||||
ext.configDir = new File(projectDir, 'config')
|
||||
ext.checkstyleConfigDir = "$configDir/checkstyle"
|
||||
checkstyle {
|
||||
toolVersion = '5.7'
|
||||
configFile = checkstyleConfigFile
|
||||
configProperties.put('basedir', checkstyleConfigDir)
|
||||
ignoreFailures = false
|
||||
showViolations = true
|
||||
}
|
||||
|
||||
ext.findbugsConfigDir = "$configDir/findbugs"
|
||||
|
||||
findbugs {
|
||||
toolVersion = '3.0.0'
|
||||
ignoreFailures = false
|
||||
effort = 'max'
|
||||
}
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
maven(MavenPublication) {
|
||||
artifactId 'hirs-provisioner'
|
||||
artifact jar
|
||||
pom.withXml {
|
||||
def dependenciesNode = asNode().appendNode('dependencies')
|
||||
|
||||
configurations.runtime.allDependencies.each {
|
||||
if (it.group != null && it.name != null) {
|
||||
def dependencyNode = dependenciesNode.appendNode('dependency')
|
||||
dependencyNode.appendNode('groupId', it.group)
|
||||
dependencyNode.appendNode('artifactId', it.name)
|
||||
dependencyNode.appendNode('version', it.version)
|
||||
|
||||
if (it.excludeRules.size() > 0) {
|
||||
def exclusionsNode = dependencyNode.appendNode('exclusions')
|
||||
it.excludeRules.each { rule ->
|
||||
def exclusionNode = exclusionsNode.appendNode('exclusion')
|
||||
exclusionNode.appendNode('groupId', rule.group)
|
||||
exclusionNode.appendNode('artifactId', rule.module)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!DOCTYPE suppressions PUBLIC
|
||||
"-//Puppy Crawl//DTD Suppressions 1.1//EN"
|
||||
"http://www.puppycrawl.com/dtds/suppressions_1_1.dtd">
|
||||
|
||||
<suppressions>
|
||||
<suppress checks="MagicNumber" files=".*[/\\]src[/\\]test[/\\]+" />
|
||||
<suppress checks="FinalParameters" files=".*[/\\]src[/\\]test[/\\]+" />
|
||||
<suppress checks="JavadocPackage" files=".*[/\\]src[/\\]test[/\\]+" />
|
||||
</suppressions>
|
@ -1,110 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Assumes HIRS is already installed
|
||||
# Dependencies:
|
||||
# openssl, version 1.0.2 (must download from source)
|
||||
# tpm_module
|
||||
|
||||
# Download and install latest version of openssl from source, using these steps:
|
||||
# cd /usr/local/src
|
||||
# wget https://www.openssl.org/source/openssl-1.0.2-latest.tar.gz
|
||||
# tar -zxf openssl-1.0.2-latest.tar.gz
|
||||
# cd openssl-1.0.2*
|
||||
# ./config
|
||||
# make depend
|
||||
# make
|
||||
# make install
|
||||
# mv /usr/bin/openssl /root
|
||||
# ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl
|
||||
|
||||
# The TPM only gives us the public key modulus, not a properly formatted key
|
||||
PUBEK_MOD=$(tpm_module -m 29 -nr -d -t ek -z -d)
|
||||
rc=$?
|
||||
if [ "$rc" != "0" ]; then
|
||||
echo "Attempt to access the TPM's public Endorsement Key was unsuccessful"
|
||||
echo "Exiting"
|
||||
exit $rc;
|
||||
fi
|
||||
|
||||
# Check user's permissions
|
||||
if [ ! -w $(pwd) ] ; then
|
||||
echo "This user does not have permissions to write to this directory: $(pwd)"
|
||||
echo "Exiting"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p certs
|
||||
cd certs
|
||||
|
||||
EKCERT_PATH="$(pwd)/ek.crt"
|
||||
CAKEY_PATH="$(pwd)/ca.key"
|
||||
CACERT_PATH="$(pwd)/ca.crt"
|
||||
|
||||
# Create the asn.1 definition file used to recreate the public key using the modulus
|
||||
cat << @EOF > def.asn1
|
||||
# Start with a SEQUENCE
|
||||
asn1=SEQUENCE:pubkeyinfo
|
||||
|
||||
# pubkeyinfo contains an algorithm identifier and the public key wrapped
|
||||
# in a BIT STRING
|
||||
[pubkeyinfo]
|
||||
algorithm=SEQUENCE:rsa_alg
|
||||
pubkey=BITWRAP,SEQUENCE:rsapubkey
|
||||
|
||||
# algorithm ID for RSA is just an OID and a NULL
|
||||
[rsa_alg]
|
||||
algorithm=OID:rsaEncryption
|
||||
parameter=NULL
|
||||
|
||||
# Actual public key: modulus and exponent
|
||||
[rsapubkey]
|
||||
n=INTEGER:0x$PUBEK_MOD
|
||||
|
||||
e=INTEGER:0x010001
|
||||
@EOF
|
||||
|
||||
# openssl commands return v1 certificates by default
|
||||
# create a .ext file to specify that we want v3
|
||||
cat << @EOF > v3.ext
|
||||
authorityKeyIdentifier=keyid,issuer
|
||||
basicConstraints=CA:FALSE
|
||||
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
|
||||
@EOF
|
||||
|
||||
# Create endorsement key given the asn1 file (DER is the default)
|
||||
openssl asn1parse -genconf def.asn1 -out ek.der -noout
|
||||
rm def.asn1
|
||||
|
||||
# Convert endorsement key from DER to PEM
|
||||
openssl rsa -pubin -in ek.der -inform DER -out ek.pem -outform PEM
|
||||
rm ek.der
|
||||
|
||||
# Create self-signed CA certificate
|
||||
openssl req -newkey rsa:2048 -nodes -keyout $CAKEY_PATH -x509 -days 365 -out $CACERT_PATH \
|
||||
-subj "/CN=www.example.com"
|
||||
|
||||
# openssl needs a private key to create a new certificate signing request
|
||||
# we only have the public endorsement key, so create a temporary key pair here
|
||||
openssl req -newkey rsa:2048 -out temp.csr -nodes -keyout temp.key -subj "/CN=www.example.com"
|
||||
rm temp.key
|
||||
|
||||
# Create the certificate here, forcing the use of our endorsement key (this means our temp key isn't used anymore
|
||||
errormessage=`openssl x509 -req -days 365 -in temp.csr -extfile v3.ext -CAcreateserial -CAkey $CAKEY_PATH -CA $CACERT_PATH -out $EKCERT_PATH -force_pubkey ek.pem 2>&1`
|
||||
rc=$?
|
||||
rm v3.ext temp.csr ek.pem
|
||||
if [ "$rc" != "0" ]; then
|
||||
echo $errormessage | grep -q "unknown option -force_pubkey" && echo "ERROR: The option 'force_pubkey' is required, but was not found for this installation of openssl x509. Please install a newer version (1.0.2+) from source" || echo $errormessage
|
||||
echo "Cleaning up..."
|
||||
rm $CAKEY_PATH $CACERT_PATH
|
||||
cd ..
|
||||
rmdir certs --ignore-fail-on-non-empty
|
||||
exit $rc
|
||||
fi
|
||||
rm ca.srl
|
||||
|
||||
openssl x509 -text -in $EKCERT_PATH
|
||||
|
||||
echo "SUCCESS: EK cert created successfully at: $EKCERT_PATH"
|
||||
echo " CA key found at: $CAKEY_PATH"
|
||||
echo " self-signed CA cert found at: $CACERT_PATH"
|
||||
echo
|
@ -1,5 +0,0 @@
|
||||
hirs-provisioner (VER) RELEASE; urgency=low
|
||||
|
||||
* Initial release
|
||||
|
||||
-- HIRS HIRS <hirs@hirs.hirs> Tue, 10 Feb 2015 16:56:18 -0500
|
@ -1 +0,0 @@
|
||||
9
|
@ -1,13 +0,0 @@
|
||||
Source: hirs-provisioner
|
||||
Section: admin
|
||||
Priority: optional
|
||||
Maintainer: HIRS <HIRS@HIRS.HIRS>
|
||||
Build-Depends: debhelper (>= 9)
|
||||
Standards-Version: 3.9.5
|
||||
|
||||
Package: hirs-provisioner
|
||||
Architecture: amd64
|
||||
Depends: tpm-module, openjdk-8-jre, wget
|
||||
Description: HIRS Provisioner for Ubuntu
|
||||
Host Integrity at Runtime and Startup. Allows provisioning of TPM
|
||||
for Ubuntu 16.04 Linux clients.
|
@ -1,8 +0,0 @@
|
||||
install-provisioner/bin/ usr/share/hirs/provisioner
|
||||
install-provisioner/lib/ usr/share/hirs/provisioner
|
||||
install-provisioner/scripts/install/hirs-provisioner.sh usr/share/hirs/provisioner
|
||||
install-provisioner/scripts/hirs-provisioner-config.sh etc/hirs/provisioner
|
||||
install-provisioner/logging.properties etc/hirs/provisioner
|
||||
install-provisioner/setup/provisioner.properties etc/hirs/provisioner
|
||||
install-provisioner/setup/hirs-provisioner.properties etc/hirs/provisioner/setup
|
||||
install-provisioner/setup/tpm-module.properties etc/hirs/provisioner/setup
|
@ -1,2 +0,0 @@
|
||||
/usr/share/hirs/provisioner/hirs-provisioner.sh /usr/sbin/hirs-provisioner
|
||||
|
@ -1 +0,0 @@
|
||||
debian/hirs-provisioner.1
|
@ -1,53 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
case "$1" in
|
||||
configure)
|
||||
if [[ $(find /sys/devices -name "tpm0") ]]; then
|
||||
echo "TPM detected"
|
||||
if [ -f "/usr/lib/systemd/system/tcsd.service" ]; then
|
||||
echo "Starting tcsd service"
|
||||
systemctl start tcsd
|
||||
ret=$?
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
echo "WARNING: FAILED TO START tcsd SERVICE, PROVISIONING WILL FAIL WITHOUT THIS SERVICE"
|
||||
fi
|
||||
echo "Adding tcsd (Trousers) to run levels 1,3,5, and 6"
|
||||
chkconfig --level 1356 tcsd on
|
||||
else
|
||||
echo "Starting tcsd service"
|
||||
service tcsd start
|
||||
ret=$?
|
||||
if [[ $ret -ne 0 ]]; then
|
||||
echo "WARNING: FAILED TO START tcsd SERVICE, PROVISIONING WILL FAIL WITHOUT THIS SERVICE"
|
||||
fi
|
||||
echo "Adding tcsd (Trousers) to run levels 1,3,5, and 6"
|
||||
chkconfig --level 1356 tcsd on
|
||||
fi
|
||||
if [ ! -d "/sys/kernel/security/tpm0" ]; then
|
||||
echo "Mounting security fs partition"
|
||||
sed -i '$a securityfs /sys/kernel/security securityfs rw,nosuid,nodev,noexec,relatime 0 0' /etc/fstab
|
||||
mount -a
|
||||
if [ -d "/sys/kernel/security/tpm0" ]; then
|
||||
echo "SUCCESS: security fs partition mounted"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo "WARNING: UNABLE TO LOCATE TPM DEVICE, TPM PROVISIONING WILL FAIL"
|
||||
fi
|
||||
|
||||
# install logging.properties if it doesn't already exist
|
||||
if ! [[ -f /etc/hirs/logging.properties ]]; then
|
||||
mv /etc/hirs/provisioner/logging.properties /etc/hirs/
|
||||
else
|
||||
rm /etc/hirs/provisioner/logging.properties
|
||||
fi
|
||||
|
||||
hirs-provisioner -c
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
@ -1,2 +0,0 @@
|
||||
# Ignore lintian error about incorrectly formatted copyright file
|
||||
hirs-provisioner binary: copyright-should-refer-to-common-license-file-for-lgpl
|
@ -1,7 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
|
||||
export DH_VERBOSE=1
|
||||
|
||||
%:
|
||||
dh $@
|
@ -1 +0,0 @@
|
||||
3.0 (native)
|
@ -1,72 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
PROVISIONER_DIR="/etc/hirs/provisioner"
|
||||
CERTIFICATES="/etc/hirs/certificates/provisioner"
|
||||
SITE_CONFIG_FILE="/etc/hirs/hirs-site.config"
|
||||
PROVISIONER_PROPERTIES="$PROVISIONER_DIR/provisioner.properties"
|
||||
TMP_PROPERTIES="$PROVISIONER_DIR/tmp.properties"
|
||||
PROVISIONER_LOG_DIR="/var/log/hirs/provisioner"
|
||||
PROVISIONER_LOG_FILE="$PROVISIONER_LOG_DIR/HIRS_Provisioner.log"
|
||||
|
||||
# ensure log file exists
|
||||
mkdir -p $PROVISIONER_LOG_DIR
|
||||
touch $PROVISIONER_LOG_FILE
|
||||
|
||||
|
||||
mkdir -p ${CERTIFICATES}/private
|
||||
|
||||
# certificates and key stores generated by this script.
|
||||
CLIENT_PEM=${CERTIFICATES}/private/hirs.client.pem
|
||||
CLIENT_CERT=${CERTIFICATES}/hirs.client.cert
|
||||
INTERNAL_P12=${CERTIFICATES}/hirs.p12
|
||||
KEYSTORE_JKS=${CERTIFICATES}/keyStoreClient.jks
|
||||
|
||||
# delete the key store if it exists
|
||||
if [ -f ${KEYSTORE_JKS} ]; then
|
||||
echo "----> Deleting existing key store" | tee -a $PROVISIONER_LOG_FILE
|
||||
rm -f ${KEYSTORE_JKS}
|
||||
fi
|
||||
|
||||
# Read site config
|
||||
source ${SITE_CONFIG_FILE}
|
||||
|
||||
# Read a block of raw data bytes from /dev/urandom and convert it to text characters.
|
||||
P12_PASSWORD=$(head -c 64 /dev/urandom | md5sum | tr -dc 'a-zA-Z0-9')
|
||||
|
||||
# generate a key and certificate. The key is the private key used to sign the well known CA cert.
|
||||
echo 'Creating 2048 bit key' >> $PROVISIONER_LOG_FILE 2>&1
|
||||
openssl req -x509 -nodes -days 3652 -newkey rsa:2048 -keyout ${CLIENT_PEM} -out ${CLIENT_CERT} -subj "/C=US/O=HIRS/OU=Provisioner/CN=$CLIENT_HOSTNAME" >> $PROVISIONER_LOG_FILE 2>&1
|
||||
|
||||
# export the certificate and key as a p12 file
|
||||
echo 'Exporting key' >> $PROVISIONER_LOG_FILE 2>&1
|
||||
openssl pkcs12 -export -in ${CLIENT_CERT} -inkey ${CLIENT_PEM} -out ${INTERNAL_P12} -passout pass:${P12_PASSWORD} >> $PROVISIONER_LOG_FILE 2>&1
|
||||
|
||||
# create a key store using the pk12 file.
|
||||
echo 'Configuring key store' >> $PROVISIONER_LOG_FILE 2>&1
|
||||
keytool -importkeystore -srckeystore ${INTERNAL_P12} -destkeystore ${KEYSTORE_JKS} -srcstoretype pkcs12 -srcstorepass ${P12_PASSWORD} -deststoretype jks -deststorepass ${P12_PASSWORD} -noprompt >> $PROVISIONER_LOG_FILE 2>&1
|
||||
|
||||
if [ ! -f ${KEYSTORE_JKS} ]; then
|
||||
echo "${KEYSTORE_JKS} was not created" | tee -a $PROVISIONER_LOG_FILE
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
grep -v "javax.net.ssl" ${PROVISIONER_PROPERTIES} > ${TMP_PROPERTIES}
|
||||
mv ${TMP_PROPERTIES} ${PROVISIONER_PROPERTIES}
|
||||
|
||||
echo "javax.net.ssl.keyStore=$KEYSTORE_JKS" >> ${PROVISIONER_PROPERTIES}
|
||||
echo "javax.net.ssl.trustStore=${CERTIFICATES}/TrustStore.jks" >> ${PROVISIONER_PROPERTIES}
|
||||
echo "javax.net.ssl.keyStorePassword=$P12_PASSWORD" >> ${PROVISIONER_PROPERTIES}
|
||||
|
||||
# Checking for existing HIRS TrustStore
|
||||
if [ -f "${CERTIFICATES}/TrustStore.jks" ]; then
|
||||
rm -f ${CERTIFICATES}/TrustStore.jks
|
||||
fi
|
||||
|
||||
echo "----> Downloading truststore" | tee -a $PROVISIONER_LOG_FILE
|
||||
wget https://"$ATTESTATION_CA_FQDN":"$ATTESTATION_CA_PORT"/HIRS_AttestationCA/client-files/TrustStore.jks --no-check-certificate -P ${CERTIFICATES} >/dev/null 2>/dev/null
|
||||
if [ ! -f "${CERTIFICATES}/TrustStore.jks" ]; then
|
||||
echo "----> ERROR: Truststore could not be downloaded from $ATTESTATION_CA_FQDN" | tee -a $PROVISIONER_LOG_FILE
|
||||
fi
|
||||
|
||||
sed -i "s/provisioner\.aca\.host\s*=\s*.*/provisioner.aca.host = $ATTESTATION_CA_FQDN/" $PROVISIONER_PROPERTIES
|
||||
sed -i "s/provisioner\.aca\.port\s*=\s*.*/provisioner.aca.port = $ATTESTATION_CA_PORT/" $PROVISIONER_PROPERTIES
|
@ -1,28 +0,0 @@
|
||||
.TH hirs\-provisioner 1 "January 11, 2018"
|
||||
|
||||
.SH NAME
|
||||
hirs\-provisioner \- provision the TPM
|
||||
.SH SYNOPSIS
|
||||
.B hirs\-provisioner
|
||||
[\-c] [\-h] [\-p]
|
||||
.SH DESCRIPTION
|
||||
Provision the TPM for use with the Host Integrity at Runtime and Startup
|
||||
(HIRS) framework.
|
||||
|
||||
.B \-c, \-\-config, config
|
||||
.IP
|
||||
create /etc/hirs/hirs-site.config template if the file does not already exist.
|
||||
If it does exist, check that its contents are valid. The template must be
|
||||
filled out with the relevant fields.
|
||||
.P
|
||||
.B \-p, \-\-provision, provision
|
||||
.IP
|
||||
provision system with HIRS Attestation Credential Authority. See full HIRS
|
||||
documentation for an explanation of the provisioning process.
|
||||
.P
|
||||
.B \-h, \-\-help, help
|
||||
.IP
|
||||
print help output
|
||||
|
||||
.SH SEE ALSO
|
||||
tpm_module(1)
|
@ -1,165 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# main driving script for the HIRS Provisioner RPM/DEB. Provides user options
|
||||
# for creating a default hirs-site.config, used by the provisioner and the HIRS Client RPM,
|
||||
# as well as initiating HIRS provisioning of the TPM and loading of credentials from the
|
||||
# HIRS Attestation CA.
|
||||
|
||||
CERTS_DIR="/etc/hirs/provisioner/certs/"
|
||||
HIRS_SITE_CONFIG="/etc/hirs/hirs-site.config"
|
||||
HIRS_PROVISIONER_CONFIG="/etc/hirs/provisioner/hirs-provisioner-config.sh"
|
||||
HIRS_PROVISIONER_SCRIPT="/usr/share/hirs/provisioner/bin/HIRS_Provisioner"
|
||||
HIRS_PROVISIONER_2_0_SCRIPT="/usr/local/bin/hirs-provisioner-tpm2"
|
||||
HIRS_PROVISIONER_PROPERTIES="/etc/hirs/provisioner/provisioner.properties"
|
||||
|
||||
if [ "$EUID" != "0" ]; then
|
||||
echo "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function ShowHelp {
|
||||
echo "hirs provisioner - host integrity at runtime & startup"
|
||||
echo ""
|
||||
echo "hirs-provisioner [command]"
|
||||
echo ""
|
||||
echo "commands:"
|
||||
echo "-h, --help, help show this help"
|
||||
echo "-c, --config, config verify or generate site configuration"
|
||||
echo "-p, --provision, provision provision TPM/prepare for use with HIRS"
|
||||
exit 0
|
||||
}
|
||||
|
||||
if [ $# -eq 0 ]; then # if no arguments
|
||||
ShowHelp
|
||||
fi
|
||||
|
||||
|
||||
function CheckHIRSSiteConfig {
|
||||
|
||||
# Check for site config existence
|
||||
if [ ! -f $HIRS_SITE_CONFIG ]; then
|
||||
echo "--> ERROR: $HIRS_SITE_CONFIG not found - run \"hirs-provisioner -c\" to generate the file"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read site config
|
||||
source $HIRS_SITE_CONFIG
|
||||
|
||||
# Verify variable existence
|
||||
if [[ -z "$CLIENT_HOSTNAME" ]]; then
|
||||
echo "--> ERROR: CLIENT_HOSTNAME is not set in $HIRS_SITE_CONFIG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$ATTESTATION_CA_FQDN" ]]; then
|
||||
echo "--> ERROR: ATTESTATION_CA_FQDN not set in $HIRS_SITE_CONFIG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$ATTESTATION_CA_PORT" ]]; then
|
||||
echo "--> ERROR: ATTESTATION_CA_PORT not set in $HIRS_SITE_CONFIG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$BROKER_FQDN" ]]; then
|
||||
echo "--> ERROR: BROKER_FQDN not set in $HIRS_SITE_CONFIG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$BROKER_PORT" ]]; then
|
||||
echo "--> ERROR: BROKER_PORT not set in $HIRS_SITE_CONFIG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PORTAL_FQDN" ]]; then
|
||||
echo "--> ERROR: PORTAL_FQDN not set in $HIRS_SITE_CONFIG"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "$PORTAL_PORT" ]]; then
|
||||
echo "--> ERROR: PORTAL_PORT not set in $HIRS_SITE_CONFIG"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
function CheckProvisionPrereqsAndDoProvisioning {
|
||||
|
||||
if [ ! -f $HIRS_SITE_CONFIG ]; then
|
||||
echo "$HIRS_SITE_CONFIG not found. Run \"hirs-provisioner -c\" to generate."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# the hirs provisioner script should be verifying
|
||||
CheckHIRSSiteConfig
|
||||
|
||||
echo "--> Configuring provisioner"
|
||||
eval $HIRS_PROVISIONER_CONFIG || { echo "----> Failed configuring provisioner"; exit 1; }
|
||||
|
||||
if [ $TPM_ENABLED = "true" ]; then
|
||||
echo "--> Provisioning"
|
||||
Provision
|
||||
else
|
||||
echo "--> TPM not enabled - skipping provisioning"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function Provision {
|
||||
# Provisioner will only retain one {uuid}.cer credential; remove any existing *.cer files.
|
||||
echo "----> Removing old attestation credentials, if any"
|
||||
rm -f $CERTS_DIR/*.cer /etc/hirs/ak.cer
|
||||
echo "----> Provisioning TPM"
|
||||
|
||||
if [ -f $HIRS_PROVISIONER_2_0_SCRIPT ]
|
||||
then
|
||||
$HIRS_PROVISIONER_2_0_SCRIPT provision || { echo "----> Failed to provision TPM 2.0"; exit 1; }
|
||||
else
|
||||
$HIRS_PROVISIONER_SCRIPT $CLIENT_HOSTNAME || { echo "----> Failed to provision TPM"; exit 1; }
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
function WriteDefaultHirsSiteConfigFile {
|
||||
if [ ! -f $HIRS_SITE_CONFIG ]; then
|
||||
# Create template site config if it does not exist
|
||||
cat <<DEFAULT_SITE_CONFIG_FILE > $HIRS_SITE_CONFIG
|
||||
#*******************************************
|
||||
#* HIRS site configuration properties file
|
||||
#*******************************************
|
||||
|
||||
# Client configuration
|
||||
CLIENT_HOSTNAME=$(hostname -f)
|
||||
TPM_ENABLED=
|
||||
IMA_ENABLED=
|
||||
|
||||
# Site-specific configuration
|
||||
ATTESTATION_CA_FQDN=
|
||||
ATTESTATION_CA_PORT=8443
|
||||
BROKER_FQDN=
|
||||
BROKER_PORT=61616
|
||||
PORTAL_FQDN=
|
||||
PORTAL_PORT=8443
|
||||
|
||||
DEFAULT_SITE_CONFIG_FILE
|
||||
|
||||
echo "$HIRS_SITE_CONFIG not found - a template has been created"
|
||||
echo "Set your site configuration manually in $HIRS_SITE_CONFIG, then run 'hirs-provisioner -p' to provision this system"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
while test $# -gt 0; do # iterate over arguments
|
||||
case "$1" in
|
||||
-c|--config|config)
|
||||
shift
|
||||
WriteDefaultHirsSiteConfigFile
|
||||
;;
|
||||
-p|--provision|provision)
|
||||
shift
|
||||
CheckProvisionPrereqsAndDoProvisioning
|
||||
;;
|
||||
*)
|
||||
ShowHelp
|
||||
;;
|
||||
esac
|
||||
done
|
@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
hirs-provisioner provision
|
@ -1,15 +0,0 @@
|
||||
#TPM Provisioning Data
|
||||
TpmEndorsmentP12 = endorsement.p12
|
||||
EndorsementP12Pass = key_password
|
||||
EcValidityDays = 3652
|
||||
TpmOwnerAuth = 0000000000000000000000000000000000000000
|
||||
#HIS Identity Provisioning Data
|
||||
HisIdentityLabel = HIS Identity Key
|
||||
HisIdentityIndex = 1
|
||||
HisIdentityAuth = 0000000000000000000000000000000000000000
|
||||
AttestationCaCertFile = AttestationCA.cer
|
||||
AttestationCaUrl = https://sampleCAurl:8443/HIRS_AttestationCA
|
||||
HisRegistrationUrl = https://sampleREGurl:8443/HisWebServices
|
||||
TrustStore = TrustStore.jks
|
||||
NtruBypass = true
|
||||
ClientPath = /etc/hirs
|
@ -1,4 +0,0 @@
|
||||
TpmModuleExePath = /usr/bin/
|
||||
ExeName = tpm_module
|
||||
TrousersMode = False
|
||||
DebugMode = True
|
@ -1,29 +0,0 @@
|
||||
package hirs.provisioner;
|
||||
|
||||
/**
|
||||
* Class to hold the command line argument values passed to the provisioner.
|
||||
*/
|
||||
public final class CommandLineArguments {
|
||||
|
||||
private static String hostName;
|
||||
|
||||
private CommandLineArguments() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the host name
|
||||
*/
|
||||
public static String getHostName() {
|
||||
return hostName;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param hostName the host name
|
||||
*/
|
||||
public static void setHostName(final String hostName) {
|
||||
CommandLineArguments.hostName = hostName;
|
||||
}
|
||||
}
|
@ -1,102 +0,0 @@
|
||||
package hirs.provisioner;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import hirs.provisioner.configuration.ProvisionerConfiguration;
|
||||
import hirs.utils.LogConfigurationUtil;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileSystems;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Defines the application's entry point and the main configuration.
|
||||
*/
|
||||
public final class ProvisionerApplication {
|
||||
private static final String JAVA_PROP_TRUST_STORE = "javax.net.ssl.trustStore";
|
||||
private static final String JAVA_PROP_KEY_STORE = "javax.net.ssl.keyStore";
|
||||
private static final String JAVA_PROP_KEY_STORE_PASSWORD = "javax.net.ssl.keyStorePassword";
|
||||
private static final List<String> SYSTEM_PROPERTIES_TO_SET = Arrays.asList(
|
||||
JAVA_PROP_KEY_STORE, JAVA_PROP_TRUST_STORE, JAVA_PROP_KEY_STORE_PASSWORD
|
||||
);
|
||||
private static final Logger LOGGER = LogManager.getLogger(ProvisionerApplication.class);
|
||||
private static final int REQUIRED_ARG_COUNT = 1;
|
||||
private static final String PROP_FILE_PATH =
|
||||
"/etc/hirs/provisioner/provisioner.properties";
|
||||
|
||||
/**
|
||||
* Hidden default constructor.
|
||||
*/
|
||||
private ProvisionerApplication() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Application entry point. Uses Spring Boot to bootstrap the application.
|
||||
*
|
||||
* @param args not used
|
||||
*/
|
||||
public static void main(final String[] args) {
|
||||
try {
|
||||
LogConfigurationUtil.applyConfiguration();
|
||||
} catch (IOException e) {
|
||||
LOGGER.error("Error configuring provisioner logger", e);
|
||||
}
|
||||
|
||||
if (ArrayUtils.isEmpty(args) || args.length != REQUIRED_ARG_COUNT) {
|
||||
LOGGER.error("Provisioner requires exactly " + REQUIRED_ARG_COUNT
|
||||
+ " args (Host Name)");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
CommandLineArguments.setHostName(args[0]);
|
||||
|
||||
LOGGER.debug("Starting HIRS Provisioner command line application");
|
||||
|
||||
try {
|
||||
setTrustStore();
|
||||
} catch (IOException ex) {
|
||||
LOGGER.error("Error provisioning client", ex);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
// enable TLS 1.1 and 1.2
|
||||
System.setProperty("https.protocols", "TLSv1.2");
|
||||
|
||||
// initialize the context
|
||||
new AnnotationConfigApplicationContext(ProvisionerConfiguration.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method configures the JVM with the trustStore as read from
|
||||
* provisioner.properties.
|
||||
*
|
||||
* @throws IOException if provisioner.properties cannot be read
|
||||
*/
|
||||
private static void setTrustStore() throws IOException {
|
||||
Properties runtimeJVMProperties = new Properties();
|
||||
|
||||
try (InputStream propertiesFileInputStream = new FileInputStream(
|
||||
FileSystems.getDefault().getPath(PROP_FILE_PATH)
|
||||
.toFile())) {
|
||||
runtimeJVMProperties.load(propertiesFileInputStream);
|
||||
}
|
||||
|
||||
for (String property : SYSTEM_PROPERTIES_TO_SET) {
|
||||
String value = runtimeJVMProperties.getProperty(property);
|
||||
if (StringUtils.isBlank(value)) {
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Cannot start HIRS Provisioner; please set a value for %s in %s",
|
||||
property, PROP_FILE_PATH));
|
||||
}
|
||||
System.setProperty(property, value);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
package hirs.provisioner.client;
|
||||
|
||||
/**
|
||||
* Defines the responsibilities and behavior of a service that provisions clients. That is, to
|
||||
* take ownership of the machine's TPM, create an identity credential, attest said credential with a
|
||||
* certificate authority, and activate that credential with the client's TPM.
|
||||
*/
|
||||
public interface ClientProvisioner {
|
||||
|
||||
/**
|
||||
* Takes control of the machine's TPM. Then creates an identity credential using the TPM. That
|
||||
* credential is then attested by a certificate authority. If that passes, the provisioner
|
||||
* will activate the credential with the TPM and persist the credential on the client for
|
||||
* future TPM operations. This method may throw {@link ProvisioningException}s when encountering
|
||||
* errors dealing with the TPM and/certificate authority.
|
||||
*
|
||||
* @return true if provisioning was successful, false otherwise
|
||||
*/
|
||||
boolean provision();
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
package hirs.provisioner.client;
|
||||
|
||||
/**
|
||||
* Describes exceptions encountered while provisioning a client.
|
||||
*/
|
||||
public class ProvisioningException extends RuntimeException {
|
||||
|
||||
/**
|
||||
* Provisioning exception that includes a root exception, the throwable, as the reason why the
|
||||
* provisioning process failed. The message provides additional detail as to why the exception
|
||||
* was encountered.
|
||||
*
|
||||
* @param message additional explanation of the failure
|
||||
* @param throwable root cause for the exception
|
||||
*/
|
||||
public ProvisioningException(final String message, final Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
}
|
@ -1,308 +0,0 @@
|
||||
package hirs.provisioner.client;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.SerializationUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.InvalidKeySpecException;
|
||||
import java.security.spec.X509EncodedKeySpec;
|
||||
import java.util.UUID;
|
||||
import hirs.DeviceInfoReportRequest;
|
||||
import hirs.client.collector.DeviceInfoCollector;
|
||||
import hirs.collector.CollectorException;
|
||||
import hirs.data.persist.DeviceInfoReport;
|
||||
import hirs.provisioner.CommandLineArguments;
|
||||
import hirs.structs.converters.SimpleStructBuilder;
|
||||
import hirs.structs.converters.StructConverter;
|
||||
import hirs.structs.elements.aca.IdentityRequestEnvelope;
|
||||
import hirs.structs.elements.aca.IdentityResponseEnvelope;
|
||||
import hirs.structs.elements.tpm.AsymmetricKeyParams;
|
||||
import hirs.structs.elements.tpm.AsymmetricPublicKey;
|
||||
import hirs.structs.elements.tpm.RsaSubParams;
|
||||
import hirs.structs.elements.tpm.StorePubKey;
|
||||
import hirs.tpm.tss.Tpm;
|
||||
|
||||
/**
|
||||
* Client implementation that uses a RestTemplate to communicate
|
||||
* with the Attestation Certificate Authority.
|
||||
*
|
||||
*/
|
||||
@Component
|
||||
public class RestfulClientProvisioner implements ClientProvisioner {
|
||||
|
||||
private static final Logger LOG = LogManager.getLogger(RestfulClientProvisioner.class);
|
||||
|
||||
@Autowired
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@Autowired
|
||||
private Tpm tpm;
|
||||
|
||||
@Autowired
|
||||
private StructConverter structConverter;
|
||||
|
||||
@Value("${provisioner.files.certs}")
|
||||
private String certificatesPath;
|
||||
|
||||
@Value("${provisioner.aca.url.key}")
|
||||
private String acaPublicKeyURL;
|
||||
|
||||
@Value("${provisioner.aca.url.identity}")
|
||||
private String acaIdentityURL;
|
||||
|
||||
/**
|
||||
* When the application context is initialized, begin provisioning.
|
||||
*
|
||||
* @param event ignored
|
||||
*/
|
||||
@EventListener
|
||||
@SuppressFBWarnings(value = "DM_EXIT",
|
||||
justification = "need to exit app from spring managed class here")
|
||||
public final void handleContextInitialized(final ContextRefreshedEvent event) {
|
||||
|
||||
// attempt to create the required directory structures before provisioning.
|
||||
try {
|
||||
LOG.debug("Creating certificate directory if non existent: " + certificatesPath);
|
||||
Files.createDirectories(Paths.get(certificatesPath));
|
||||
} catch (IOException ex) {
|
||||
LOG.error("Error creating certificate directories: " + ex.getMessage(), ex);
|
||||
throw new ProvisioningException(ex.getMessage(), ex);
|
||||
}
|
||||
|
||||
// initiate provisioning process. If it fails, exit with non-zero so that
|
||||
// the caller (hirs.sh) can exit and not configure the client due to failure.
|
||||
if (!this.provision()) {
|
||||
LOG.debug("Exiting with error due to provisioning failure");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean provision() {
|
||||
|
||||
// take ownership of the TPM
|
||||
takeOwnership();
|
||||
LOG.debug("took ownership of TPM");
|
||||
|
||||
// get the public key from the ACA
|
||||
RSAPublicKey acaPublicKey = getACAPublicKey();
|
||||
LOG.debug("received public key from ACA");
|
||||
|
||||
// create uuid for identity request and response
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
|
||||
// create Tpm Key from ACA Public key
|
||||
AsymmetricPublicKey tpmKey = new SimpleStructBuilder<>(AsymmetricPublicKey.class)
|
||||
.set("asymmetricKeyParams", new SimpleStructBuilder<>(AsymmetricKeyParams.class)
|
||||
.set("algorithmId", AsymmetricPublicKey.DEFAULT_RSA_ALG_ID)
|
||||
.set("encryptionScheme", AsymmetricPublicKey.DEFAULT_RSA_ENCRYPTION_SCHEME)
|
||||
.set("signatureScheme", AsymmetricPublicKey.DEFAULT_RSA_SIGNATURE_SCHEME)
|
||||
.set("params", new SimpleStructBuilder<>(RsaSubParams.class)
|
||||
.set("totalPrimes", AsymmetricPublicKey.DEFAULT_PRIME_TOTAL)
|
||||
.set("keyLength", AsymmetricPublicKey.DEFAULT_KEY_LENGTH)
|
||||
.set("exponent", acaPublicKey.getPublicExponent().toByteArray())
|
||||
.build())
|
||||
.build())
|
||||
.set("storePubKey", new SimpleStructBuilder<>(StorePubKey.class)
|
||||
.set("key", acaPublicKey.getModulus().toByteArray())
|
||||
.build())
|
||||
.build();
|
||||
|
||||
// obtain device information required for identity request
|
||||
DeviceInfoReport deviceInfoReport = getDeviceInfoReport();
|
||||
|
||||
// create the identity request using the ACA public key and a generated UUID
|
||||
IdentityRequestEnvelope identityRequest = createIdentityRequest(tpmKey, uuid,
|
||||
deviceInfoReport);
|
||||
LOG.debug(String.format("created TPM identity request using UUID %s", uuid));
|
||||
|
||||
// attest the request with the ACA and obtain it's response
|
||||
System.out.println("----> Sending Attestation Identity Credential Request");
|
||||
IdentityResponseEnvelope response = attestIdentityRequest(identityRequest);
|
||||
if (null == response) {
|
||||
LOG.error("Provisioning failed. Please refer to the Attestation CA for details.");
|
||||
return false;
|
||||
}
|
||||
|
||||
System.out.println("----> Attestation Identity Provisioning succeeded");
|
||||
|
||||
// activate the identity with the TPM
|
||||
byte[] credential = activateCredential(response, uuid);
|
||||
LOG.debug("activated credential with TPM");
|
||||
|
||||
// create the AIK file and write the credential to the file.
|
||||
try {
|
||||
Path identityFile = Files.createFile(Paths.get(certificatesPath, uuid + ".cer"));
|
||||
Files.write(identityFile, credential);
|
||||
LOG.debug(String.format("created credential file: %s", identityFile.toString()));
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
LOG.error(String.format("Error outputting identity credential to %s: %s",
|
||||
certificatesPath, e.getMessage()), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses the TPM instance to take over the TPM ownership, if possible.
|
||||
*/
|
||||
void takeOwnership() {
|
||||
tpm.takeOwnership();
|
||||
}
|
||||
|
||||
/**
|
||||
* Communicates with the configured ACA to obtain it's public key information.
|
||||
*
|
||||
* @return the ACA public key
|
||||
*/
|
||||
RSAPublicKey getACAPublicKey() {
|
||||
// request the public key from the ACA
|
||||
ResponseEntity<byte[]> response = restTemplate.getForEntity(acaPublicKeyURL, byte[].class);
|
||||
|
||||
try {
|
||||
// use the public key information to create encoded key specification. then create a
|
||||
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(response.getBody());
|
||||
|
||||
// create the public key from that specification
|
||||
return (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(keySpec);
|
||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
|
||||
throw new ProvisioningException("Encountered error while create Public Key from "
|
||||
+ "ACA response: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an identity request using the ACA public certificate and an UUID.
|
||||
*
|
||||
* @param asymmetricPublicKey that contains the public key information of the ACA
|
||||
* @param uuid unique identifier
|
||||
* @param deviceInfoReport the full device info report used by the ACA for provisioning
|
||||
* @return identity request that can be sent on ward to the ACA for attestation.
|
||||
*/
|
||||
IdentityRequestEnvelope createIdentityRequest(final AsymmetricPublicKey asymmetricPublicKey,
|
||||
final String uuid, final DeviceInfoReport deviceInfoReport) {
|
||||
try {
|
||||
// serialize the tpm key
|
||||
byte[] asymmetricBlob = structConverter.convert(asymmetricPublicKey);
|
||||
|
||||
// collate identity based upon ACA public key and unique id
|
||||
byte[] request = tpm.collateIdentityRequest(asymmetricBlob, uuid);
|
||||
|
||||
// obtain the endorsement credential
|
||||
byte[] endorsementCredentialModulus = tpm.getEndorsementCredentialModulus();
|
||||
|
||||
// obtain full endorsement credential
|
||||
byte[] endorsementCredential = getEndorsementCredential();
|
||||
|
||||
// format device info report
|
||||
byte[] deviceInfoReportBytes = SerializationUtils.serialize(deviceInfoReport);
|
||||
|
||||
LOG.debug("Sending EC of length: " + endorsementCredential.length);
|
||||
// build up the ACA request
|
||||
return new SimpleStructBuilder<>(IdentityRequestEnvelope.class)
|
||||
.set("endorsementCredentialModulus", endorsementCredentialModulus)
|
||||
.set("endorsementCredential", endorsementCredential)
|
||||
.set("request", request)
|
||||
.set("deviceInfoReport", deviceInfoReportBytes)
|
||||
.build();
|
||||
} catch (Exception e) {
|
||||
throw new ProvisioningException("Encountered exception while creating identity "
|
||||
+ "credential: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets endorsement credential from TPM.
|
||||
* @return the EK from the TPM, or null if there was an error
|
||||
*/
|
||||
private byte[] getEndorsementCredential() {
|
||||
// initialize to a non-null array so struct builder doesn't consider this null.
|
||||
byte[] endorsementCredential = new byte[] {1};
|
||||
try {
|
||||
endorsementCredential = tpm.getEndorsementCredential();
|
||||
System.out.println("----> Got endorsement credential from TPM");
|
||||
LOG.debug("Endorsement credential size: " + endorsementCredential.length);
|
||||
} catch (Exception e) {
|
||||
LOG.warn("Failed to get endorsement credential from TPM");
|
||||
LOG.debug("EK retrieval error", e);
|
||||
}
|
||||
return endorsementCredential;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attests a given identity request with the configured Attestation Certificate Authority.
|
||||
*
|
||||
* @param identityRequest to be attested
|
||||
* @return the ACA response
|
||||
*/
|
||||
IdentityResponseEnvelope attestIdentityRequest(final IdentityRequestEnvelope identityRequest) {
|
||||
// create HTTP entity wrapper for the identity request
|
||||
HttpEntity<byte[]> message = new HttpEntity<>(structConverter.convert(identityRequest));
|
||||
|
||||
// send the identity request to the ACA and receive the identity response.
|
||||
ResponseEntity<byte[]> response =
|
||||
restTemplate.exchange(acaIdentityURL, HttpMethod.POST, message, byte[].class);
|
||||
|
||||
byte[] responseBody = response.getBody();
|
||||
if (ArrayUtils.isEmpty(responseBody)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// grab the response from the HTTP response
|
||||
return structConverter.convert(responseBody, IdentityResponseEnvelope.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates a given attested identity with the TPM associated by UUID. This UUID must match up
|
||||
* with the original identity request.
|
||||
*
|
||||
* @param response to be activated
|
||||
* @param uuid of the original identity request
|
||||
* @return the raw activated credential
|
||||
*/
|
||||
byte[] activateCredential(final IdentityResponseEnvelope response, final String uuid) {
|
||||
// grab both the symmetric and asymmetric from the identity response
|
||||
byte[] asymmetricContents = response.getAsymmetricContents();
|
||||
byte[] symmetricContents = structConverter.convert(response.getSymmetricAttestation());
|
||||
|
||||
// active the identity with the TPM
|
||||
return tpm.activateIdentity(asymmetricContents, symmetricContents, uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects the Device Info Report without TPM information, due to not having an identity
|
||||
* cert yet.
|
||||
* @return the Device Info Report
|
||||
*/
|
||||
DeviceInfoReport getDeviceInfoReport() {
|
||||
DeviceInfoReportRequest request = new DeviceInfoReportRequest();
|
||||
DeviceInfoReport report = null;
|
||||
try {
|
||||
System.out.println("----> Collecting device information");
|
||||
DeviceInfoCollector deviceInfoCollector = new DeviceInfoCollector(null, false,
|
||||
CommandLineArguments.getHostName());
|
||||
report = (DeviceInfoReport) deviceInfoCollector.collect(request);
|
||||
} catch (CollectorException e) {
|
||||
LOG.error("Error collecting device information", e);
|
||||
}
|
||||
return report;
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
/**
|
||||
* Defines the interfaces, exceptions, and implementations of classes required to perform client
|
||||
* provisioning operations.
|
||||
*/
|
||||
package hirs.provisioner.client;
|
@ -1,113 +0,0 @@
|
||||
package hirs.provisioner.configuration;
|
||||
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.context.annotation.PropertySources;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import hirs.structs.converters.SimpleStructConverter;
|
||||
import hirs.structs.converters.StructConverter;
|
||||
import hirs.tpm.tss.Tpm;
|
||||
import hirs.tpm.tss.command.CommandTpm;
|
||||
import hirs.utils.LogConfigurationUtil;
|
||||
|
||||
/**
|
||||
* Spring Java configuration file that prepares beans for the provisioning application. This
|
||||
* provides an alternative implementation of the traditional Spring XML application context files.
|
||||
*/
|
||||
@Configuration
|
||||
@PropertySources({
|
||||
@PropertySource(value = "classpath:defaults.properties"),
|
||||
|
||||
// detects if file exists, if not, ignore errors
|
||||
@PropertySource(value = "file:/etc/hirs/provisioner/provisioner.properties",
|
||||
ignoreResourceNotFound = true)
|
||||
})
|
||||
@ComponentScan("hirs.provisioner")
|
||||
public class ProvisionerConfiguration {
|
||||
|
||||
/**
|
||||
* Path to the provisioner properties overrides. By default, these properties mirror those that
|
||||
* are in the classpath. These properties provide a means for the client to customize the
|
||||
* provisioner
|
||||
*/
|
||||
public static final Path PROVISIONER_PROPERTIES_OVERRIDES =
|
||||
Paths.get("/etc/hirs/provisioner/provisioner.properties");
|
||||
|
||||
/**
|
||||
* @return bean to resolve injected annotation.Value
|
||||
* property expressions for beans.
|
||||
*/
|
||||
@Bean
|
||||
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialization of the ClientProvisioner. Detects environment and runs configuration methods
|
||||
* as required. This method is intended to be invoked by the Spring application context.
|
||||
*/
|
||||
@PostConstruct
|
||||
final void initialize() {
|
||||
try {
|
||||
LogConfigurationUtil.applyConfiguration();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
// if the properties overrides file doesn't exist (or directories), copy it over. capture
|
||||
// any exception while doing so and log a warning.
|
||||
if (!Files.exists(PROVISIONER_PROPERTIES_OVERRIDES)) {
|
||||
try {
|
||||
// obtain the embedded properties file
|
||||
ClassPathResource properties = new ClassPathResource("defaults.properties");
|
||||
|
||||
// create the directories if they do not exist
|
||||
Files.createDirectories(PROVISIONER_PROPERTIES_OVERRIDES.getParent());
|
||||
|
||||
// copy the defaults properties to the overrides location.
|
||||
Files.copy(properties.getInputStream(), PROVISIONER_PROPERTIES_OVERRIDES);
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new BeanInitializationException(
|
||||
"Encountered error while initializing ClientProvisioner configuration: "
|
||||
+ e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return configured ready to use RestTemplate.
|
||||
*/
|
||||
@Bean
|
||||
public RestTemplate restTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return configured ready to use {@link Tpm}
|
||||
*/
|
||||
@Bean
|
||||
public Tpm tpm() {
|
||||
return new CommandTpm();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return configured ready to use {@link StructConverter}
|
||||
*/
|
||||
@Bean
|
||||
public StructConverter structConverter() {
|
||||
return new SimpleStructConverter();
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
/**
|
||||
* Application configuration files pertaining to Spring's application context.
|
||||
*/
|
||||
package hirs.provisioner.configuration;
|
@ -1,4 +0,0 @@
|
||||
/**
|
||||
* This package defines the application entry points.
|
||||
*/
|
||||
package hirs.provisioner;
|
@ -1,29 +0,0 @@
|
||||
# Client Provisioner configuration
|
||||
|
||||
# ClientProvisioner files
|
||||
# root: root location of all provisioner files
|
||||
# certs: location of certificate files that the provisioner may read or write
|
||||
provisioner.files.root = /etc/hirs/provisioner
|
||||
provisioner.files.certs = ${provisioner.files.root}/certs
|
||||
|
||||
# ClientProvisioner ACA connection information
|
||||
# host: hostname of the ACA
|
||||
# port: the port number that the ACA is listening on
|
||||
provisioner.aca.host = localhost
|
||||
provisioner.aca.port = 8443
|
||||
|
||||
# ClientProvisioner ACA Context paths
|
||||
# root: the main url path for the ACA
|
||||
# key: the context path for the public key servlet
|
||||
# identity: the context path for the identity request processor servlet
|
||||
provisioner.aca.path.root = /HIRS_AttestationCA
|
||||
provisioner.aca.path.key = /public-key
|
||||
provisioner.aca.path.identity = /identity-request/process
|
||||
|
||||
# ClientProvisioner ACA URL paths
|
||||
# root: the main url
|
||||
# key: fully qualified URL for getting ACA public key
|
||||
# identity: fully qualified URL for processing identity requests
|
||||
provisioner.aca.url.root = https://${provisioner.aca.host}:${provisioner.aca.port}/${provisioner.aca.path.root}
|
||||
provisioner.aca.url.key = ${provisioner.aca.url.root}/${provisioner.aca.path.key}
|
||||
provisioner.aca.url.identity = ${provisioner.aca.url.root}/${provisioner.aca.path.identity}
|
@ -1,36 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Configuration>
|
||||
<Appenders>
|
||||
<Console name="STDOUT" target="SYSTEM_OUT">
|
||||
<PatternLayout pattern="----> %m%n"/>
|
||||
</Console>
|
||||
<RollingFile name="FILE" fileName="/var/log/hirs/provisioner/HIRS_Provisioner.log"
|
||||
filePattern="/var/log/hirs/provisioner/HIRS_Provisioner.log-%d{yyyy-MM-dd}-%i.log" >
|
||||
<PatternLayout>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss} [%C.%M] %-5p : %m%n</pattern>
|
||||
</PatternLayout>
|
||||
<Policies>
|
||||
<SizeBasedTriggeringPolicy size="10 MB" />
|
||||
</Policies>
|
||||
<DefaultRolloverStrategy max="10"/>
|
||||
</RollingFile>
|
||||
</Appenders>
|
||||
<Loggers>
|
||||
<logger name="hirs" level="WARN" additivity="false">
|
||||
<AppenderRef ref="STDOUT"/>
|
||||
<AppenderRef ref="FILE"/>
|
||||
</logger>
|
||||
<!-- log spring and activemq logs at the warn level only to all appenders-->
|
||||
<logger name="org.springframework" level="WARN" additivity="false">
|
||||
<AppenderRef ref="STDOUT"/>
|
||||
<AppenderRef ref="FILE"/>
|
||||
</logger>
|
||||
<logger name="org.apache.activemq" level="WARN" additivity="false">
|
||||
<AppenderRef ref="STDOUT"/>
|
||||
<AppenderRef ref="FILE"/>
|
||||
</logger>
|
||||
<Root level = "WARN">
|
||||
<AppenderRef ref="FILE"/>
|
||||
</Root>
|
||||
</Loggers>
|
||||
</Configuration>
|
@ -1,376 +0,0 @@
|
||||
package hirs.client.collector;
|
||||
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.testng.PowerMockTestCase;
|
||||
import org.testng.Assert;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.powermock.api.mockito.PowerMockito.when;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
import java.util.Enumeration;
|
||||
import hirs.DeviceInfoReportRequest;
|
||||
import hirs.collector.CollectorException;
|
||||
import hirs.data.persist.DeviceInfoReport;
|
||||
import hirs.data.persist.enums.OSName;
|
||||
|
||||
/**
|
||||
* Unit tests for <code>DeviceInfoCollector</code>.
|
||||
*/
|
||||
@PrepareForTest(DeviceInfoCollector.class)
|
||||
public class DeviceInfoCollectorTest extends PowerMockTestCase {
|
||||
|
||||
private DeviceInfoCollector collector;
|
||||
|
||||
/**
|
||||
* Prepares a test environment for each individual test.
|
||||
*
|
||||
* @throws CollectorException should not be thrown here as all collection is mocked
|
||||
*/
|
||||
@BeforeMethod
|
||||
public void beforeMethod() throws CollectorException {
|
||||
collector = spy(new DeviceInfoCollector());
|
||||
PowerMockito.mockStatic(DeviceInfoCollector.class);
|
||||
|
||||
// mock out serial number collection as it requires root
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
any(OSName.class), anyString())).thenReturn("some string");
|
||||
doReturn("Linux").when(collector).getSystemProperty(eq("os.name"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that a DeviceInfoCollector will generate a DeviceInfoReport.
|
||||
*
|
||||
* @throws Exception if an error occurs creating mocked output
|
||||
*/
|
||||
@Test
|
||||
public final void testCollect() throws Exception {
|
||||
final DeviceInfoReportRequest request = new DeviceInfoReportRequest();
|
||||
final DeviceInfoReport report =
|
||||
(DeviceInfoReport) collector.collect(request);
|
||||
final int numberOfDmiDecodeCalls = 9;
|
||||
|
||||
// the following two lines assert that collectDmiDecodeValue was called 9 times
|
||||
PowerMockito.verifyStatic(times(numberOfDmiDecodeCalls));
|
||||
DeviceInfoCollector.collectDmiDecodeValue(any(OSName.class), anyString());
|
||||
|
||||
Assert.assertNotNull(report.getNetworkInfo());
|
||||
Assert.assertNotNull(report.getOSInfo());
|
||||
|
||||
// Test the IP address in the report against the system that created it
|
||||
Enumeration<NetworkInterface> interfaces =
|
||||
NetworkInterface.getNetworkInterfaces();
|
||||
boolean equivalenceFound = false;
|
||||
while (interfaces.hasMoreElements()) {
|
||||
NetworkInterface netInt = interfaces.nextElement();
|
||||
Enumeration<InetAddress> addresses = netInt.getInetAddresses();
|
||||
while (addresses.hasMoreElements()) {
|
||||
InetAddress address = addresses.nextElement();
|
||||
if (address.getHostAddress().equals(
|
||||
report.getNetworkInfo().getIpAddress().
|
||||
getHostAddress())) {
|
||||
equivalenceFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Assert.assertTrue(equivalenceFound);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests that hardware and firmware info is set correctly.
|
||||
*
|
||||
* @throws CollectorException should not be thrown here as all collection is mocked
|
||||
*/
|
||||
@Test
|
||||
public final void testCollectProperInfo() throws CollectorException {
|
||||
DeviceInfoCollector mockedCollector = spy(DeviceInfoCollector.class);
|
||||
PowerMockito.mockStatic(DeviceInfoCollector.class);
|
||||
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-manufacturer")).thenReturn("Manufacturer");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-product-name")).thenReturn("Product name");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-serial-number")).thenReturn("Serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "chassis-serial-number")).thenReturn("Chassis serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "baseboard-serial-number")).thenReturn("Baseboard serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-version")).thenReturn("Version");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-vendor")).thenReturn("Bios vendor");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-version")).thenReturn("Bios version");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-release-date")).thenReturn("Bios release date");
|
||||
|
||||
doReturn("Linux").when(mockedCollector).getSystemProperty("os.name");
|
||||
|
||||
final DeviceInfoReportRequest request = new DeviceInfoReportRequest();
|
||||
DeviceInfoReport report = (DeviceInfoReport) mockedCollector.doCollect(request);
|
||||
Assert.assertEquals(report.getHardwareInfo().getManufacturer(),
|
||||
"Manufacturer");
|
||||
Assert.assertEquals(report.getHardwareInfo().getProductName(),
|
||||
"Product name");
|
||||
Assert.assertEquals(report.getHardwareInfo().getSystemSerialNumber(),
|
||||
"Serial number");
|
||||
Assert.assertEquals(report.getHardwareInfo().getChassisSerialNumber(),
|
||||
"Chassis serial number");
|
||||
Assert.assertEquals(report.getHardwareInfo().getBaseboardSerialNumber(),
|
||||
"Baseboard serial number");
|
||||
Assert.assertEquals(report.getHardwareInfo().getVersion(),
|
||||
"Version");
|
||||
Assert.assertEquals(report.getFirmwareInfo().getBiosVendor(),
|
||||
"Bios vendor");
|
||||
Assert.assertEquals(report.getFirmwareInfo().getBiosVersion(),
|
||||
"Bios version");
|
||||
Assert.assertEquals(report.getFirmwareInfo().getBiosReleaseDate(),
|
||||
"Bios release date");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that null hardware info is set to "Not specified".
|
||||
*
|
||||
* @throws CollectorException should not be thrown here as all collection is mocked
|
||||
*/
|
||||
@Test
|
||||
public final void testCollectNullHardwareInfo() throws CollectorException {
|
||||
DeviceInfoCollector mockedCollector = spy(DeviceInfoCollector.class);
|
||||
PowerMockito.mockStatic(DeviceInfoCollector.class);
|
||||
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-manufacturer")).thenReturn(null);
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-product-name")).thenReturn(null);
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-serial-number")).thenReturn(null);
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "chassis-serial-number")).thenReturn(null);
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "baseboard-serial-number")).thenReturn(null);
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-version")).thenReturn(null);
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-vendor")).thenReturn("Bios vendor");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-version")).thenReturn("Bios version");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-release-date")).thenReturn("Bios release date");
|
||||
|
||||
doReturn("Linux").when(mockedCollector).getSystemProperty("os.name");
|
||||
|
||||
final DeviceInfoReportRequest request = new DeviceInfoReportRequest();
|
||||
DeviceInfoReport report = (DeviceInfoReport) mockedCollector.doCollect(request);
|
||||
|
||||
Assert.assertEquals(report.getHardwareInfo().getManufacturer(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getHardwareInfo().getProductName(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getHardwareInfo().getSystemSerialNumber(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getHardwareInfo().getChassisSerialNumber(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getHardwareInfo().getBaseboardSerialNumber(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getHardwareInfo().getVersion(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that empty hardware info is set to "Not specified".
|
||||
*
|
||||
* @throws CollectorException should not be thrown here as all collection is mocked
|
||||
*/
|
||||
@Test
|
||||
public final void testCollectEmptyHardwareInfo() throws CollectorException {
|
||||
DeviceInfoCollector mockedCollector = spy(DeviceInfoCollector.class);
|
||||
PowerMockito.mockStatic(DeviceInfoCollector.class);
|
||||
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-manufacturer")).thenReturn("");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-product-name")).thenReturn("");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-serial-number")).thenReturn("");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "chassis-serial-number")).thenReturn("");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "baseboard-serial-number")).thenReturn("");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-version")).thenReturn("");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-vendor")).thenReturn("Bios vendor");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-version")).thenReturn("Bios version");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-release-date")).thenReturn("Bios release date");
|
||||
|
||||
doReturn("Linux").when(mockedCollector).getSystemProperty("os.name");
|
||||
|
||||
final DeviceInfoReportRequest request = new DeviceInfoReportRequest();
|
||||
DeviceInfoReport report = (DeviceInfoReport) mockedCollector.doCollect(request);
|
||||
|
||||
Assert.assertEquals(report.getHardwareInfo().getManufacturer(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getHardwareInfo().getProductName(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getHardwareInfo().getSystemSerialNumber(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getHardwareInfo().getChassisSerialNumber(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getHardwareInfo().getBaseboardSerialNumber(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getHardwareInfo().getVersion(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that null firmware info is set to "Not specified".
|
||||
*
|
||||
* @throws CollectorException should not be thrown here as all collection is mocked
|
||||
*/
|
||||
@Test
|
||||
public final void testCollectNullFirmwareInfo() throws CollectorException {
|
||||
DeviceInfoCollector mockedCollector = spy(DeviceInfoCollector.class);
|
||||
PowerMockito.mockStatic(DeviceInfoCollector.class);
|
||||
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-manufacturer")).thenReturn("Manufacturer");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-product-name")).thenReturn("Product name");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-serial-number")).thenReturn("Serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "chassis-serial-number")).thenReturn("Chassis serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "baseboard-serial-number")).thenReturn("Baseboard serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-version")).thenReturn("Version");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-vendor")).thenReturn(null);
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-version")).thenReturn(null);
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-release-date")).thenReturn(null);
|
||||
|
||||
doReturn("Linux").when(mockedCollector).getSystemProperty("os.name");
|
||||
|
||||
final DeviceInfoReportRequest request = new DeviceInfoReportRequest();
|
||||
DeviceInfoReport report = (DeviceInfoReport) mockedCollector.doCollect(request);
|
||||
|
||||
Assert.assertEquals(report.getFirmwareInfo().getBiosVendor(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getFirmwareInfo().getBiosVersion(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getFirmwareInfo().getBiosReleaseDate(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that empty firmware info is set to "Not specified".
|
||||
*
|
||||
* @throws CollectorException should not be thrown here as all collection is mocked
|
||||
*/
|
||||
@Test
|
||||
public final void testCollectEmptyFirmwareInfo() throws CollectorException {
|
||||
DeviceInfoCollector mockedCollector = spy(DeviceInfoCollector.class);
|
||||
PowerMockito.mockStatic(DeviceInfoCollector.class);
|
||||
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-manufacturer")).thenReturn("Manufacturer");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-product-name")).thenReturn("Product name");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-serial-number")).thenReturn("Serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "chassis-serial-number")).thenReturn("Chassis serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "baseboard-serial-number")).thenReturn("Baseboard serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-version")).thenReturn("Version");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-vendor")).thenReturn("");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-version")).thenReturn("");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-release-date")).thenReturn("");
|
||||
|
||||
doReturn("Linux").when(mockedCollector).getSystemProperty("os.name");
|
||||
|
||||
final DeviceInfoReportRequest request = new DeviceInfoReportRequest();
|
||||
DeviceInfoReport report = (DeviceInfoReport) mockedCollector.doCollect(request);
|
||||
|
||||
Assert.assertEquals(report.getFirmwareInfo().getBiosVendor(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getFirmwareInfo().getBiosVersion(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getFirmwareInfo().getBiosReleaseDate(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that null OS info is set to "Not specified".
|
||||
*
|
||||
* @throws CollectorException should not be thrown here as all collection is mocked
|
||||
*/
|
||||
@Test
|
||||
public final void testCollectNullOSInfo() throws CollectorException {
|
||||
DeviceInfoCollector mockedCollector = spy(DeviceInfoCollector.class);
|
||||
PowerMockito.mockStatic(DeviceInfoCollector.class);
|
||||
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-manufacturer")).thenReturn("Manufacturer");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-product-name")).thenReturn("Product name");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-serial-number")).thenReturn("Serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "chassis-serial-number")).thenReturn("Chassis serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "baseboard-serial-number")).thenReturn("Baseboard serial number");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "system-version")).thenReturn("Version");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-vendor")).thenReturn("Bios vendor");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-version")).thenReturn("Bios version");
|
||||
when(DeviceInfoCollector.collectDmiDecodeValue(
|
||||
OSName.LINUX, "bios-release-date")).thenReturn("Bios release date");
|
||||
|
||||
doReturn("Unknown").when(mockedCollector).getSystemProperty("os.name");
|
||||
|
||||
final DeviceInfoReportRequest request = new DeviceInfoReportRequest();
|
||||
DeviceInfoReport report = (DeviceInfoReport) mockedCollector.doCollect(request);
|
||||
|
||||
Assert.assertEquals(report.getOSInfo().getDistribution(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
Assert.assertEquals(report.getOSInfo().getDistributionRelease(),
|
||||
DeviceInfoCollector.NOT_SPECIFIED);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that isReportRequestSupported() will return DeviceInfoReportRequest.
|
||||
*/
|
||||
@Test
|
||||
public final void testReportRequestSupported() {
|
||||
Assert.assertEquals(collector.reportRequestTypeSupported(), DeviceInfoReportRequest.class);
|
||||
}
|
||||
|
||||
}
|
@ -1,399 +0,0 @@
|
||||
package hirs.provisioner.client;
|
||||
|
||||
import hirs.client.collector.DeviceInfoCollector;
|
||||
import hirs.data.persist.DeviceInfoReport;
|
||||
import hirs.data.persist.info.FirmwareInfo;
|
||||
import hirs.data.persist.info.HardwareInfo;
|
||||
import hirs.data.persist.info.NetworkInfo;
|
||||
import hirs.data.persist.info.OSInfo;
|
||||
import hirs.data.persist.enums.OSName;
|
||||
import hirs.data.persist.info.TPMInfo;
|
||||
import hirs.structs.converters.StructConverter;
|
||||
import hirs.structs.elements.tpm.AsymmetricPublicKey;
|
||||
import hirs.tpm.tss.Tpm;
|
||||
import hirs.tpm.tss.command.CommandException;
|
||||
import hirs.tpm.tss.command.CommandResult;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
import org.powermock.modules.testng.PowerMockObjectFactory;
|
||||
import org.powermock.modules.testng.PowerMockTestCase;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.util.SerializationUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.testng.IObjectFactory;
|
||||
import org.testng.annotations.ObjectFactory;
|
||||
import org.testng.annotations.Test;
|
||||
import org.testng.annotations.BeforeMethod;
|
||||
import org.testng.annotations.AfterMethod;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import hirs.structs.elements.aca.IdentityRequestEnvelope;
|
||||
import hirs.structs.elements.aca.IdentityResponseEnvelope;
|
||||
import hirs.structs.elements.aca.SymmetricAttestation;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
import static org.testng.Assert.assertNotNull;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* Test suite for the {@link RestfulClientProvisioner}.
|
||||
*/
|
||||
@PrepareForTest(DeviceInfoCollector.class)
|
||||
public class RestfulClientProvisionerTest extends PowerMockTestCase {
|
||||
|
||||
/**
|
||||
* Sets up PowerMockito.
|
||||
*
|
||||
* @return PowerMockObjectFactory
|
||||
*/
|
||||
@ObjectFactory
|
||||
public IObjectFactory getObjectFactory() {
|
||||
return new PowerMockObjectFactory();
|
||||
}
|
||||
|
||||
private static final String ACA_KEY_URL = "acaKeyUrl";
|
||||
|
||||
private static final String ACA_IDENTITY_URL = "acaIdentityUrl";
|
||||
|
||||
@Mock
|
||||
private Tpm mockTpm;
|
||||
|
||||
@Mock
|
||||
private StructConverter mockStructConverter;
|
||||
|
||||
@Mock
|
||||
private RestTemplate mockRestTemplate;
|
||||
|
||||
@InjectMocks
|
||||
private RestfulClientProvisioner provisioner;
|
||||
|
||||
/***
|
||||
* Initializes a unique test environment for each test.
|
||||
*/
|
||||
@BeforeMethod
|
||||
public void setup() {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that there were no more additional invocations on the mocks after each test has been
|
||||
* completed.
|
||||
*/
|
||||
@AfterMethod
|
||||
public void verifyMocks() {
|
||||
verifyNoMoreInteractions(mockStructConverter, mockRestTemplate, mockTpm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link RestfulClientProvisioner#takeOwnership()}.
|
||||
*/
|
||||
@Test
|
||||
public void testTakeOwnership() {
|
||||
// perform test
|
||||
provisioner.takeOwnership();
|
||||
|
||||
// verify tpm was used appropriately
|
||||
verify(mockTpm).takeOwnership();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link RestfulClientProvisioner#getACAPublicKey()}.
|
||||
*
|
||||
* @throws Exception while generating key pair
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testGetACAPublicKey() throws Exception {
|
||||
// create a key pair generator to generate a temporary RSA key
|
||||
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
|
||||
keyPairGenerator.initialize(512);
|
||||
|
||||
// create the temporary key
|
||||
KeyPair keyPair = keyPairGenerator.generateKeyPair();
|
||||
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
|
||||
|
||||
// assign the ACA identity URL
|
||||
ReflectionTestUtils.setField(provisioner, "acaPublicKeyURL", ACA_KEY_URL);
|
||||
|
||||
// mock response from the ACA
|
||||
ResponseEntity responseEntity = mock(ResponseEntity.class);
|
||||
|
||||
// when our rest template is called, just return our mocked response
|
||||
when(mockRestTemplate.getForEntity(ACA_KEY_URL, byte[].class)).thenReturn(responseEntity);
|
||||
|
||||
// when requesting the response, return our test public key
|
||||
when(responseEntity.getBody()).thenReturn(publicKey.getEncoded());
|
||||
|
||||
// perform the actual test
|
||||
RSAPublicKey result = provisioner.getACAPublicKey();
|
||||
|
||||
// verify that the key is correct
|
||||
assertEquals(result.getPublicExponent(), publicKey.getPublicExponent());
|
||||
assertEquals(result.getModulus(), publicKey.getModulus());
|
||||
|
||||
// verify mock interactions
|
||||
verify(mockRestTemplate).getForEntity(ACA_KEY_URL, byte[].class);
|
||||
verify(responseEntity).getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link RestfulClientProvisioner#createIdentityRequest(AsymmetricPublicKey,
|
||||
* String, DeviceInfoReport)}.
|
||||
* @throws Exception if there is a problem encountered when mocking
|
||||
* DeviceInfoCollector
|
||||
*/
|
||||
@Test
|
||||
public void createIdentityCredential() throws Exception {
|
||||
PowerMockito.spy(DeviceInfoCollector.class);
|
||||
final InetAddress ipAddress = getTestIpAddress();
|
||||
final byte[] macAddress = new byte[] {11, 22, 33, 44, 55, 66};
|
||||
|
||||
// test parameters
|
||||
String uuid = "uuid";
|
||||
|
||||
byte[] asymmetricBlob = new byte[]{1};
|
||||
byte[] request = new byte[]{2};
|
||||
byte[] ekModulus = new byte[]{3};
|
||||
byte[] ek = new byte[]{50};
|
||||
|
||||
// test specific mocks
|
||||
AsymmetricPublicKey publicKey = mock(AsymmetricPublicKey.class);
|
||||
|
||||
// when the converter is used to serialize public key, return known blob
|
||||
when(mockStructConverter.convert(publicKey)).thenReturn(asymmetricBlob);
|
||||
|
||||
// when tpm collate identity is invoked using test blob and uuid, return known request
|
||||
when(mockTpm.collateIdentityRequest(asymmetricBlob, uuid)).thenReturn(request);
|
||||
|
||||
// return known credential when asked.
|
||||
when(mockTpm.getEndorsementCredentialModulus()).thenReturn(ekModulus);
|
||||
when(mockTpm.getEndorsementCredential()).thenReturn(ek);
|
||||
|
||||
|
||||
PowerMockito.doReturn("AB12345").when(DeviceInfoCollector.class,
|
||||
"collectDmiDecodeValue", OSName.LINUX, "system-serial-number");
|
||||
|
||||
PowerMockito.doReturn("AB12346").when(DeviceInfoCollector.class,
|
||||
"collectDmiDecodeValue", OSName.LINUX, "chassis-serial-number");
|
||||
|
||||
// perform test
|
||||
final DeviceInfoReport deviceInfoReport = new DeviceInfoReport(
|
||||
new NetworkInfo("test hostname", ipAddress, macAddress),
|
||||
new OSInfo(), new FirmwareInfo(), new HardwareInfo(), new TPMInfo());
|
||||
IdentityRequestEnvelope envelope = provisioner.createIdentityRequest(publicKey, uuid,
|
||||
deviceInfoReport);
|
||||
|
||||
// validate the identity request
|
||||
assertEquals(envelope.getEndorsementCredentialModulus(), ekModulus);
|
||||
assertEquals(envelope.getEndorsementCredentialModulusLength(), ekModulus.length);
|
||||
assertEquals(envelope.getEndorsementCredential(), ek);
|
||||
assertEquals(envelope.getEndorsementCredentialLength(), ek.length);
|
||||
assertEquals(envelope.getRequest(), request);
|
||||
assertEquals(envelope.getRequestLength(), request.length);
|
||||
|
||||
int deviceInfoReportLength = envelope.getDeviceInfoReportLength();
|
||||
assertTrue(deviceInfoReportLength > 0);
|
||||
assertEquals(envelope.getDeviceInfoReport().length, deviceInfoReportLength);
|
||||
assertEquals(envelope.getDeviceInfoReport(),
|
||||
SerializationUtils.serialize(deviceInfoReport));
|
||||
|
||||
// verify mock interactions
|
||||
verify(mockStructConverter).convert(publicKey);
|
||||
verify(mockTpm).collateIdentityRequest(asymmetricBlob, uuid);
|
||||
verify(mockTpm).getEndorsementCredentialModulus();
|
||||
verify(mockTpm).getEndorsementCredential();
|
||||
verifyNoMoreInteractions(publicKey);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tests {@link RestfulClientProvisioner#createIdentityRequest(AsymmetricPublicKey,
|
||||
* String, DeviceInfoReport)}.
|
||||
* @throws Exception if there is a problem encountered when mocking
|
||||
* DeviceInfoCollector
|
||||
*/
|
||||
@Test
|
||||
public void createIdentityCredentialEkNotFound() throws Exception {
|
||||
PowerMockito.spy(DeviceInfoCollector.class);
|
||||
final InetAddress ipAddress = getTestIpAddress();
|
||||
final byte[] macAddress = new byte[] {11, 22, 33, 44, 55, 66};
|
||||
|
||||
// test parameters
|
||||
String uuid = "uuid";
|
||||
|
||||
byte[] asymmetricBlob = new byte[]{1};
|
||||
byte[] request = new byte[]{2};
|
||||
byte[] ekModulus = new byte[]{3};
|
||||
|
||||
// test specific mocks
|
||||
AsymmetricPublicKey publicKey = mock(AsymmetricPublicKey.class);
|
||||
|
||||
// when the converter is used to serialize public key, return known blob
|
||||
when(mockStructConverter.convert(publicKey)).thenReturn(asymmetricBlob);
|
||||
|
||||
// when tpm collate identity is invoked using test blob and uuid, return known request
|
||||
when(mockTpm.collateIdentityRequest(asymmetricBlob, uuid)).thenReturn(request);
|
||||
|
||||
// return known credential when asked.
|
||||
when(mockTpm.getEndorsementCredentialModulus()).thenReturn(ekModulus);
|
||||
when(mockTpm.getEndorsementCredential()).thenThrow(new CommandException("no good",
|
||||
new CommandResult("EK not found", -1)));
|
||||
|
||||
|
||||
PowerMockito.doReturn("AB12345").when(DeviceInfoCollector.class,
|
||||
"collectDmiDecodeValue", OSName.LINUX, "system-serial-number");
|
||||
|
||||
PowerMockito.doReturn("AB12346").when(DeviceInfoCollector.class,
|
||||
"collectDmiDecodeValue", OSName.LINUX, "chassis-serial-number");
|
||||
|
||||
// perform test
|
||||
final DeviceInfoReport deviceInfoReport = new DeviceInfoReport(
|
||||
new NetworkInfo("test hostname", ipAddress, macAddress),
|
||||
new OSInfo(), new FirmwareInfo(), new HardwareInfo(), new TPMInfo());
|
||||
IdentityRequestEnvelope envelope = provisioner.createIdentityRequest(publicKey, uuid,
|
||||
deviceInfoReport);
|
||||
|
||||
// validate the identity request
|
||||
assertEquals(envelope.getEndorsementCredentialModulus(), ekModulus);
|
||||
assertEquals(envelope.getEndorsementCredentialModulusLength(), ekModulus.length);
|
||||
assertNotNull(envelope.getEndorsementCredential());
|
||||
assertEquals(envelope.getEndorsementCredentialLength(), 1);
|
||||
assertEquals(envelope.getRequest(), request);
|
||||
assertEquals(envelope.getRequestLength(), request.length);
|
||||
|
||||
int deviceInfoReportLength = envelope.getDeviceInfoReportLength();
|
||||
assertTrue(deviceInfoReportLength > 0);
|
||||
assertEquals(envelope.getDeviceInfoReport().length, deviceInfoReportLength);
|
||||
assertEquals(envelope.getDeviceInfoReport(),
|
||||
SerializationUtils.serialize(deviceInfoReport));
|
||||
|
||||
// verify mock interactions
|
||||
verify(mockStructConverter).convert(publicKey);
|
||||
verify(mockTpm).collateIdentityRequest(asymmetricBlob, uuid);
|
||||
verify(mockTpm).getEndorsementCredentialModulus();
|
||||
verify(mockTpm).getEndorsementCredential();
|
||||
verifyNoMoreInteractions(publicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link RestfulClientProvisioner#attestIdentityRequest(IdentityRequestEnvelope)}.
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testAttestIdentityRequest() {
|
||||
|
||||
// create some test variables
|
||||
byte[] requestBytes = new byte[]{1};
|
||||
byte[] responseBytes = new byte[]{2};
|
||||
|
||||
// create some test mocks
|
||||
IdentityRequestEnvelope request = mock(IdentityRequestEnvelope.class);
|
||||
IdentityResponseEnvelope response = mock(IdentityResponseEnvelope.class);
|
||||
ResponseEntity responseEntity = mock(ResponseEntity.class);
|
||||
|
||||
// assign the ACA identity URL
|
||||
ReflectionTestUtils.setField(provisioner, "acaIdentityURL", ACA_IDENTITY_URL);
|
||||
|
||||
// the mock converter should serialize the identity request to bytes and likewise
|
||||
// deserialize the identity response
|
||||
when(mockStructConverter.convert(request)).thenReturn(requestBytes);
|
||||
when(mockStructConverter.convert(responseBytes, IdentityResponseEnvelope.class))
|
||||
.thenReturn(response);
|
||||
|
||||
// the template should be used to send a post to the assigned url
|
||||
when(mockRestTemplate.exchange(eq(ACA_IDENTITY_URL), eq(HttpMethod.POST),
|
||||
any(HttpEntity.class), eq(byte[].class))).thenReturn(responseEntity);
|
||||
|
||||
// the aca response body should be acquired in order to convert into a response object
|
||||
when(responseEntity.getBody()).thenReturn(responseBytes);
|
||||
|
||||
// perform the test
|
||||
provisioner.attestIdentityRequest(request);
|
||||
|
||||
// verify converter mock
|
||||
verify(mockStructConverter).convert(request);
|
||||
verify(mockStructConverter).convert(responseBytes, IdentityResponseEnvelope.class);
|
||||
|
||||
// setup captor for rest template verification.
|
||||
ArgumentCaptor<HttpEntity> argument = ArgumentCaptor.forClass(HttpEntity.class);
|
||||
|
||||
// verify the rest template and capture the argument for the response entity type
|
||||
verify(mockRestTemplate).exchange(eq(ACA_IDENTITY_URL), eq(HttpMethod.POST),
|
||||
argument.capture(), eq(byte[].class));
|
||||
|
||||
// verify response entity body is acquired
|
||||
verify(responseEntity).getBody();
|
||||
|
||||
// assert that the http entity object being sent to the aca contained the request bytes
|
||||
assertEquals(argument.getValue().getBody(), requestBytes);
|
||||
|
||||
// verify test specific mocks had no other unintended interactions
|
||||
verifyNoMoreInteractions(request, response, responseEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests {@link RestfulClientProvisioner#activateCredential(IdentityResponseEnvelope,
|
||||
* String)}.
|
||||
*/
|
||||
@Test
|
||||
public void testActivateCredential() {
|
||||
// create test parameters
|
||||
String uuid = "uuid";
|
||||
byte[] asymmetricContents = new byte[]{1};
|
||||
byte[] symmetricContents = new byte[]{2};
|
||||
byte[] response = new byte[]{3};
|
||||
|
||||
// create test specific mocks
|
||||
IdentityResponseEnvelope envelope = mock(IdentityResponseEnvelope.class);
|
||||
SymmetricAttestation attestation = mock(SymmetricAttestation.class);
|
||||
|
||||
// both asymmetric and symmetric contents should be obtained
|
||||
when(envelope.getAsymmetricContents()).thenReturn(asymmetricContents);
|
||||
when(envelope.getSymmetricAttestation()).thenReturn(attestation);
|
||||
|
||||
// the tpm should be sent both contents and the specified uuid
|
||||
when(mockTpm.activateIdentity(asymmetricContents, symmetricContents, uuid))
|
||||
.thenReturn(response);
|
||||
|
||||
// the symmetric contents need to be converted
|
||||
when(mockStructConverter.convert(attestation)).thenReturn(symmetricContents);
|
||||
|
||||
// perform the actual test
|
||||
provisioner.activateCredential(envelope, uuid);
|
||||
|
||||
// verify mock interactions
|
||||
verify(mockTpm).activateIdentity(asymmetricContents, symmetricContents, uuid);
|
||||
verify(envelope).getAsymmetricContents();
|
||||
verify(envelope).getSymmetricAttestation();
|
||||
verify(mockStructConverter).convert(attestation);
|
||||
|
||||
// ensure test specific mocks have no unintended interactions
|
||||
verifyNoMoreInteractions(envelope, attestation);
|
||||
}
|
||||
|
||||
private static InetAddress getTestIpAddress() {
|
||||
try {
|
||||
return InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
|
||||
} catch (UnknownHostException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user