removed HIRS_Provisioner

This commit is contained in:
iadgovuser26 2024-08-19 15:07:43 -04:00 committed by iadgovuser26 iadgovuser26@empire.eclipse.ncsc.mil
parent a62e45ee2e
commit 1b582dfec6
35 changed files with 0 additions and 2091 deletions

View File

@ -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/

View File

@ -1,4 +0,0 @@
TpmModuleExePath = exe
ExeName = /tpm_module
TrousersMode = False
DebugMode = True

View File

@ -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)
}
}
}
}
}
}
}
}

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -1 +0,0 @@
9

View File

@ -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.

View File

@ -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

View File

@ -1,2 +0,0 @@
/usr/share/hirs/provisioner/hirs-provisioner.sh /usr/sbin/hirs-provisioner

View File

@ -1 +0,0 @@
debian/hirs-provisioner.1

View File

@ -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

View File

@ -1,2 +0,0 @@
# Ignore lintian error about incorrectly formatted copyright file
hirs-provisioner binary: copyright-should-refer-to-common-license-file-for-lgpl

View File

@ -1,7 +0,0 @@
#!/usr/bin/make -f
# -*- makefile -*-
export DH_VERBOSE=1
%:
dh $@

View File

@ -1 +0,0 @@
3.0 (native)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -1,3 +0,0 @@
#!/bin/bash
hirs-provisioner provision

View File

@ -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

View File

@ -1,4 +0,0 @@
TpmModuleExePath = /usr/bin/
ExeName = tpm_module
TrousersMode = False
DebugMode = True

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -1,5 +0,0 @@
/**
* Defines the interfaces, exceptions, and implementations of classes required to perform client
* provisioning operations.
*/
package hirs.provisioner.client;

View File

@ -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();
}
}

View File

@ -1,4 +0,0 @@
/**
* Application configuration files pertaining to Spring's application context.
*/
package hirs.provisioner.configuration;

View File

@ -1,4 +0,0 @@
/**
* This package defines the application entry points.
*/
package hirs.provisioner;

View File

@ -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}

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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;
}
}
}