mirror of
https://github.com/nsacyber/HIRS.git
synced 2024-12-19 04:58:00 +00:00
Merge branch 'master' into java_xml_timestamp
This commit is contained in:
commit
25e77a6173
25
.ci/docker/Dockerfile.acaimage
Normal file
25
.ci/docker/Dockerfile.acaimage
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
FROM centos:7
|
||||||
|
|
||||||
|
# Install packages for installing HIRS ACA
|
||||||
|
RUN yum -y update && yum clean all
|
||||||
|
# install build tools for TPM2 provisioner
|
||||||
|
RUN yum install -y epel-release cmake make git gcc-c++ doxygen graphviz protobuf-compiler cppcheck python libssh2-devel openssl libcurl-devel log4cplus-devel protobuf-devel re2-devel tpm2-tss-devel tpm2-abrmd-devel && yum clean all
|
||||||
|
|
||||||
|
# install build tools for ACA
|
||||||
|
RUN yum install -y sudo yum install java-1.8.0-openjdk-devel protobuf-compiler rpm-build epel-release cmake make git gcc-c++ doxygen graphviz cppcheck python libssh2-devel openssl libcurl-devel log4cplus-devel protobuf-devel re2-devel tpm2-tss-devel tpm2-abrmd-devel trousers-devel && yum clean all
|
||||||
|
# install run time dependencies
|
||||||
|
RUN yum install -y mariadb-server openssl tomcat java-1.8.0-openjdk-headless rpmdevtools coreutils initscripts chkconfig sed grep wget which firewalld policycoreutils net-tools git rpm-build && yum clean all
|
||||||
|
|
||||||
|
# Remove TLSv1, TLSv1.1, references to prevent java security from stopping tomcat launch
|
||||||
|
RUN sed -i 's/TLSv1,//' /usr/lib/jvm/java-1.8.0-openjdk-1.8.0*/jre/lib/security/java.security
|
||||||
|
RUN sed -i 's/TLSv1.1,//' /usr/lib/jvm/java-1.8.0-openjdk-1.8.0*/jre/lib/security/java.security
|
||||||
|
|
||||||
|
RUN mkdir /hirs
|
||||||
|
|
||||||
|
# Expose ACA Port
|
||||||
|
EXPOSE 8443 8080
|
||||||
|
|
||||||
|
COPY ../../package/rpm/RPMS/noarch/HIRS_AttestationCA*.el7.noarch.rpm /
|
||||||
|
COPY ../../scripts/aca_image_setup.sh /
|
||||||
|
CMD ["sh","/aca_image_setup.sh"]
|
||||||
|
RUN yum install -y HIRS_AttestationCA*.el7.noarch.rpm
|
64
.github/workflows/build_aca_image.yml
vendored
Normal file
64
.github/workflows/build_aca_image.yml
vendored
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
name: ACA Docker Image Build
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [ published ]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
imagename:
|
||||||
|
description: 'ACA Docker Image Name'
|
||||||
|
default: 'aca-centos7'
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
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.GITHUB_TOKEN }} | docker login ghcr.io -u $ --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/* /.; \
|
||||||
|
cp /HIRS/package/rpm/RPMS/x86_64/* /.; \
|
||||||
|
cp /HIRS/scripts/aca_image_setup.sh /.; \
|
||||||
|
popd;' \
|
||||||
|
- name: Build and publish a release Docker image for ${{ github.repository }}
|
||||||
|
if: github.event_name == 'release'
|
||||||
|
uses: macbre/push-to-ghcr@master
|
||||||
|
with:
|
||||||
|
image_name: nsacyber/hirs/aca-centos7
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
dockerfile: "./.ci/docker/Dockerfile.acaimage"
|
||||||
|
- name: Build and publish a Docker image for ${{ github.repository }}
|
||||||
|
if: github.event_name == 'workflow_dispatch'
|
||||||
|
uses: macbre/push-to-ghcr@master
|
||||||
|
with:
|
||||||
|
image_name: nsacyber/hirs/${{ inputs.imagename }}
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
dockerfile: "./.ci/docker/Dockerfile.acaimage"
|
@ -121,10 +121,11 @@ public class TpmPcrEvent {
|
|||||||
* This can be SHA1 for older event structures or any algorithm for newer structure.
|
* This can be SHA1 for older event structures or any algorithm for newer structure.
|
||||||
*
|
*
|
||||||
* @param digestData cryptographic hash
|
* @param digestData cryptographic hash
|
||||||
|
* @param digestLength length of the cryptographic hash
|
||||||
*/
|
*/
|
||||||
protected void setEventDigest(final byte[] digestData) {
|
protected void setEventDigest(final byte[] digestData, final int digestLength) {
|
||||||
digest = new byte[digestLength];
|
digest = new byte[digestLength];
|
||||||
System.arraycopy(digestData, 0, digest, 0, this.digestLength);
|
System.arraycopy(digestData, 0, digest, 0, digestLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -469,23 +470,31 @@ public class TpmPcrEvent {
|
|||||||
* @param event the byte array holding the event data.
|
* @param event the byte array holding the event data.
|
||||||
* @param eventContent the byte array holding the event content.
|
* @param eventContent the byte array holding the event content.
|
||||||
* @param eventNumber event position within the event log.
|
* @param eventNumber event position within the event log.
|
||||||
|
* @param hashName name of the hash algorithm used by the event log
|
||||||
* @return String description of the event.
|
* @return String description of the event.
|
||||||
* @throws CertificateException if the event contains an event that cannot be processed.
|
* @throws CertificateException if the event contains an event that cannot be processed.
|
||||||
* @throws NoSuchAlgorithmException if an event contains an unsupported algorithm.
|
* @throws NoSuchAlgorithmException if an event contains an unsupported algorithm.
|
||||||
* @throws IOException if the event cannot be parsed.
|
* @throws IOException if the event cannot be parsed.
|
||||||
*/
|
*/
|
||||||
public String processEvent(final byte[] event, final byte[] eventContent, final int eventNumber)
|
public String processEvent(final byte[] event, final byte[] eventContent, final int eventNumber,
|
||||||
throws CertificateException, NoSuchAlgorithmException, IOException {
|
final String hashName)
|
||||||
|
throws CertificateException, NoSuchAlgorithmException, IOException {
|
||||||
int eventID = (int) eventType;
|
int eventID = (int) eventType;
|
||||||
this.eventNumber = eventNumber;
|
this.eventNumber = eventNumber;
|
||||||
description += "Event# " + eventNumber + ": ";
|
description += "Event# " + eventNumber + ": ";
|
||||||
description += "Index PCR[" + getPcrIndex() + "]\n";
|
description += "Index PCR[" + getPcrIndex() + "]\n";
|
||||||
description += "Event Type: 0x" + Long.toHexString(eventType) + " " + eventString(eventID);
|
description += "Event Type: 0x" + Long.toHexString(eventType) + " " + eventString(eventID);
|
||||||
description += "\n";
|
description += "\n";
|
||||||
if (logFormat == 1) { // Digest
|
if (hashName.compareToIgnoreCase("TPM_ALG_SHA1") == 0) { // Digest
|
||||||
description += "digest (SHA-1): " + Hex.encodeHexString(this.digest);
|
description += "digest (SHA-1): " + Hex.encodeHexString(this.digest);
|
||||||
} else {
|
} else if (hashName.compareToIgnoreCase("TPM_ALG_SHA256") == 0) { // Digest
|
||||||
description += "digest (SHA256): " + Hex.encodeHexString(this.digest);
|
description += "digest (SHA256): " + Hex.encodeHexString(this.digest);
|
||||||
|
} else if (hashName.compareToIgnoreCase("TPM_ALG_SHA384") == 0) { // Digest
|
||||||
|
description += "digest (SHA384): " + Hex.encodeHexString(this.digest);
|
||||||
|
} else if (hashName.compareToIgnoreCase("TPM_ALG_SHA512") == 0) { // Digest
|
||||||
|
description += "digest (SHA512): " + Hex.encodeHexString(this.digest);
|
||||||
|
} else {
|
||||||
|
description += "Unsupported Hash Algorithm encoutered";
|
||||||
}
|
}
|
||||||
if (eventID != UefiConstants.SIZE_4) {
|
if (eventID != UefiConstants.SIZE_4) {
|
||||||
description += "\n";
|
description += "\n";
|
||||||
|
@ -49,15 +49,16 @@ public class TpmPcrEvent1 extends TpmPcrEvent {
|
|||||||
byte[] rawEventSize = new byte[UefiConstants.SIZE_4];
|
byte[] rawEventSize = new byte[UefiConstants.SIZE_4];
|
||||||
byte[] eventDigest = new byte[EvConstants.SHA1_LENGTH];
|
byte[] eventDigest = new byte[EvConstants.SHA1_LENGTH];
|
||||||
byte[] eventContent = null;
|
byte[] eventContent = null;
|
||||||
|
int digestSize = EvConstants.SHA1_LENGTH;
|
||||||
int eventSize = 0;
|
int eventSize = 0;
|
||||||
|
String hashName = "TPM_ALG_SHA1";
|
||||||
if (is.available() > UefiConstants.SIZE_32) {
|
if (is.available() > UefiConstants.SIZE_32) {
|
||||||
is.read(rawIndex);
|
is.read(rawIndex);
|
||||||
setPcrIndex(rawIndex);
|
setPcrIndex(rawIndex);
|
||||||
is.read(rawType);
|
is.read(rawType);
|
||||||
setEventType(rawType);
|
setEventType(rawType);
|
||||||
is.read(eventDigest);
|
is.read(eventDigest);
|
||||||
setEventDigest(eventDigest);
|
setEventDigest(eventDigest, digestSize);
|
||||||
is.read(rawEventSize);
|
is.read(rawEventSize);
|
||||||
eventSize = HexUtils.leReverseInt(rawEventSize);
|
eventSize = HexUtils.leReverseInt(rawEventSize);
|
||||||
eventContent = new byte[eventSize];
|
eventContent = new byte[eventSize];
|
||||||
@ -78,7 +79,7 @@ public class TpmPcrEvent1 extends TpmPcrEvent {
|
|||||||
offset += rawEventSize.length;
|
offset += rawEventSize.length;
|
||||||
setEventData(event);
|
setEventData(event);
|
||||||
//System.arraycopy(eventContent, 0, event, offset, eventContent.length);
|
//System.arraycopy(eventContent, 0, event, offset, eventContent.length);
|
||||||
this.processEvent(event, eventContent, eventNumber);
|
this.processEvent(event, eventContent, eventNumber, hashName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,12 +78,14 @@ public class TpmPcrEvent2 extends TpmPcrEvent {
|
|||||||
setDigestLength(EvConstants.SHA256_LENGTH);
|
setDigestLength(EvConstants.SHA256_LENGTH);
|
||||||
setLogFormat(2);
|
setLogFormat(2);
|
||||||
/** Event data. */
|
/** Event data. */
|
||||||
|
int eventDigestLength = 0;
|
||||||
|
String hashName = "";
|
||||||
byte[] event;
|
byte[] event;
|
||||||
byte[] rawIndex = new byte[UefiConstants.SIZE_4];
|
byte[] rawIndex = new byte[UefiConstants.SIZE_4];
|
||||||
byte[] algCountBytes = new byte[UefiConstants.SIZE_4];
|
byte[] algCountBytes = new byte[UefiConstants.SIZE_4];
|
||||||
byte[] rawType = new byte[UefiConstants.SIZE_4];
|
byte[] rawType = new byte[UefiConstants.SIZE_4];
|
||||||
byte[] rawEventSize = new byte[UefiConstants.SIZE_4];
|
byte[] rawEventSize = new byte[UefiConstants.SIZE_4];
|
||||||
byte[] eventDigest = new byte[EvConstants.SHA256_LENGTH];
|
byte[] eventDigest = null;
|
||||||
byte[] eventContent = null;
|
byte[] eventContent = null;
|
||||||
TcgTpmtHa hashAlg = null;
|
TcgTpmtHa hashAlg = null;
|
||||||
int eventSize = 0;
|
int eventSize = 0;
|
||||||
@ -99,10 +101,10 @@ public class TpmPcrEvent2 extends TpmPcrEvent {
|
|||||||
// Process TPMT_HA,
|
// Process TPMT_HA,
|
||||||
for (int i = 0; i < algCount; i++) {
|
for (int i = 0; i < algCount; i++) {
|
||||||
hashAlg = new TcgTpmtHa(is);
|
hashAlg = new TcgTpmtHa(is);
|
||||||
|
hashName = hashAlg.getHashName();
|
||||||
hashlist.add(hashAlg);
|
hashlist.add(hashAlg);
|
||||||
if (hashAlg.getHashName().compareToIgnoreCase("TPM_ALG_SHA256") == 0) {
|
eventDigest = new byte[hashAlg.getHashLength()];
|
||||||
setEventDigest(hashAlg.getDigest());
|
setEventDigest(hashAlg.getDigest(), hashAlg.getHashLength());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
is.read(rawEventSize);
|
is.read(rawEventSize);
|
||||||
eventSize = HexUtils.leReverseInt(rawEventSize);
|
eventSize = HexUtils.leReverseInt(rawEventSize);
|
||||||
@ -126,7 +128,8 @@ public class TpmPcrEvent2 extends TpmPcrEvent {
|
|||||||
offset += rawEventSize.length;
|
offset += rawEventSize.length;
|
||||||
//System.arraycopy(eventContent, 0, event, offset, eventContent.length);
|
//System.arraycopy(eventContent, 0, event, offset, eventContent.length);
|
||||||
setEventData(event);
|
setEventData(event);
|
||||||
this.processEvent(event, eventContent, eventNumber);
|
//setDigestLength(eventDigestLength);
|
||||||
|
this.processEvent(event, eventContent, eventNumber, hashName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ public final class EvConstants {
|
|||||||
public static final int SHA1_LENGTH = 20;
|
public static final int SHA1_LENGTH = 20;
|
||||||
/** Event Type (byte array). */
|
/** Event Type (byte array). */
|
||||||
public static final int SHA256_LENGTH = 32;
|
public static final int SHA256_LENGTH = 32;
|
||||||
|
/** Event Type (byte array). */
|
||||||
|
public static final int SHA384_LENGTH = 48;
|
||||||
/** Each PCR bank holds 24 registers. */
|
/** Each PCR bank holds 24 registers. */
|
||||||
public static final int PCR_COUNT = 24;
|
public static final int PCR_COUNT = 24;
|
||||||
// Event IDs
|
// Event IDs
|
||||||
|
19
scripts/aca_image_setup.sh
Normal file
19
scripts/aca_image_setup.sh
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Setup db
|
||||||
|
|
||||||
|
if [[ $(pgrep -c -u mysql mysqld) -ne 0 ]]; then
|
||||||
|
echo "shutting down ..."
|
||||||
|
usr/bin/mysqladmin -u root shutdown -p;
|
||||||
|
fi
|
||||||
|
|
||||||
|
/usr/libexec/mariadb-prepare-db-dir
|
||||||
|
nohup /usr/bin/mysqld_safe --basedir=/usr &>/dev/null &
|
||||||
|
MYSQLD_PID=$(pgrep -u mysql mysqld)
|
||||||
|
/usr/libexec/mariadb-wait-ready $MYSQLD_PID
|
||||||
|
|
||||||
|
mysql -fu root < /opt/hirs/scripts/common/db_create.sql.el7
|
||||||
|
mysql -fu root < /opt/hirs/scripts/common/secure_mysql.sql
|
||||||
|
|
||||||
|
# Start tomcat
|
||||||
|
/usr/libexec/tomcat/server start
|
@ -65,11 +65,12 @@ buildscript {
|
|||||||
|
|
||||||
// Produce packages
|
// Produce packages
|
||||||
ospackage {
|
ospackage {
|
||||||
|
def gitCommitHash = 'git rev-parse --verify --short HEAD'.execute().text.trim()
|
||||||
packageName = 'tcg_eventlog_tool'
|
packageName = 'tcg_eventlog_tool'
|
||||||
os = LINUX
|
os = LINUX
|
||||||
arch = NOARCH
|
arch = X86_64
|
||||||
version = '2.1.0'
|
version = '2.1.0'
|
||||||
release = '1'
|
release = gitCommitHash
|
||||||
|
|
||||||
into '/opt/hirs/eventlog'
|
into '/opt/hirs/eventlog'
|
||||||
user 'root'
|
user 'root'
|
||||||
@ -104,7 +105,7 @@ ospackage {
|
|||||||
details.file.name.endsWith('.md')
|
details.file.name.endsWith('.md')
|
||||||
}
|
}
|
||||||
into './'
|
into './'
|
||||||
link("/usr/local/bin/elt", "/opt/hirs/eventlog/scripts/eventlog.sh", 0x755)
|
link("/usr/bin/elt", "/opt/hirs/eventlog/scripts/eventlog.sh", 0x755)
|
||||||
}
|
}
|
||||||
|
|
||||||
into('/tmp/') {
|
into('/tmp/') {
|
||||||
@ -118,9 +119,9 @@ ospackage {
|
|||||||
postInstall file('scripts/vendor-table.sh')
|
postInstall file('scripts/vendor-table.sh')
|
||||||
|
|
||||||
buildRpm {
|
buildRpm {
|
||||||
arch = I386
|
arch = X86_64
|
||||||
}
|
}
|
||||||
buildDeb {
|
buildDeb {
|
||||||
arch = I386
|
arch = X86_64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ public class Commander {
|
|||||||
private static final String PCR_STRING = "pcr";
|
private static final String PCR_STRING = "pcr";
|
||||||
private static final String VERIFY_STRING = "Verify";
|
private static final String VERIFY_STRING = "Verify";
|
||||||
private static final String VERSION_STRING = "version";
|
private static final String VERSION_STRING = "version";
|
||||||
private static final String VERSION_NUMBER = "1.0";
|
private static final String VERSION_NUMBER = "2.1";
|
||||||
private static final String REGEX = "[0-9]+";
|
private static final String REGEX = "[0-9]+";
|
||||||
|
|
||||||
private boolean hasArguments = false;
|
private boolean hasArguments = false;
|
||||||
@ -63,7 +63,6 @@ public class Commander {
|
|||||||
defualtArgs[0] = "-e";
|
defualtArgs[0] = "-e";
|
||||||
hasArguments = true;
|
hasArguments = true;
|
||||||
parseArguments(defualtArgs);
|
parseArguments(defualtArgs);
|
||||||
// printHelp("");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,15 +74,16 @@ public class Commander {
|
|||||||
*/
|
*/
|
||||||
public final void parseArguments(final String[] args) {
|
public final void parseArguments(final String[] args) {
|
||||||
String tempValue;
|
String tempValue;
|
||||||
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
tempValue = args[i];
|
tempValue = args[i];
|
||||||
|
|
||||||
|
if (bDone) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (args.length == 0) { // Process default params if none were given
|
if (args.length == 0) { // Process default params if none were given
|
||||||
bEventIds = true;
|
bEventIds = true;
|
||||||
} else {
|
} else {
|
||||||
switch (tempValue) {
|
switch (tempValue) {
|
||||||
case FULL_COMMAND_PREFIX + CONTENT_STRING:
|
|
||||||
case FULL_COMMAND_PREFIX + EVENTIDS_STRING:
|
case FULL_COMMAND_PREFIX + EVENTIDS_STRING:
|
||||||
case COMMAND_PREFIX + "e":
|
case COMMAND_PREFIX + "e":
|
||||||
if (i < args.length - 1) { // Check for a filter following the -e
|
if (i < args.length - 1) { // Check for a filter following the -e
|
||||||
@ -92,12 +92,16 @@ public class Commander {
|
|||||||
if (eventFilter.matches(REGEX)) {
|
if (eventFilter.matches(REGEX)) {
|
||||||
eventNumber = Integer.parseInt(eventFilter);
|
eventNumber = Integer.parseInt(eventFilter);
|
||||||
} else {
|
} else {
|
||||||
System.out.println("invalid parameter following -e: " + eventFilter);
|
printHelp("Invalid parameter following -e: " + eventFilter
|
||||||
|
+ "\n");
|
||||||
|
bValidArgs = false;
|
||||||
|
bDone = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bEventIds = true;
|
bEventIds = true;
|
||||||
break;
|
break;
|
||||||
|
case FULL_COMMAND_PREFIX + CONTENT_STRING:
|
||||||
case COMMAND_PREFIX + "ec":
|
case COMMAND_PREFIX + "ec":
|
||||||
bContentHex = true;
|
bContentHex = true;
|
||||||
break;
|
break;
|
||||||
@ -109,10 +113,10 @@ public class Commander {
|
|||||||
case COMMAND_PREFIX + "d":
|
case COMMAND_PREFIX + "d":
|
||||||
if ((args.length < i + 2 + 1) || (args[i + 1].charAt(0) == '-')
|
if ((args.length < i + 2 + 1) || (args[i + 1].charAt(0) == '-')
|
||||||
|| (args[i + 2].charAt(0) == '-')) {
|
|| (args[i + 2].charAt(0) == '-')) {
|
||||||
System.out.print("tcg_eventlog_tool command line error:"
|
printHelp("tcg_eventlog_tool command line error:"
|
||||||
+ " 2 or 3 parameters needed for -diff.\n");
|
+ " 2 parameters needed for -diff." + "\n");
|
||||||
System.out.print("usage: elt -d logFile1 logFile2 pcr#");
|
|
||||||
bValidArgs = false;
|
bValidArgs = false;
|
||||||
|
bDone = true;
|
||||||
} else {
|
} else {
|
||||||
inFile = args[i++ + 1];
|
inFile = args[i++ + 1];
|
||||||
inFile2 = args[i++ + 1];
|
inFile2 = args[i++ + 1];
|
||||||
@ -121,18 +125,36 @@ public class Commander {
|
|||||||
break;
|
break;
|
||||||
case FULL_COMMAND_PREFIX + FILE_STRING:
|
case FULL_COMMAND_PREFIX + FILE_STRING:
|
||||||
case COMMAND_PREFIX + "f":
|
case COMMAND_PREFIX + "f":
|
||||||
bFile = true;
|
if (i == args.length - 1) {
|
||||||
inFile = args[++i];
|
printHelp("No output file specified with the " + tempValue
|
||||||
|
+ " option" + "\n");
|
||||||
|
bValidArgs = false;
|
||||||
|
bDone = true;
|
||||||
|
} else if (args[i + 1].charAt(0) == '-') {
|
||||||
|
printHelp("No output file specified with the " + tempValue
|
||||||
|
+ "option" + "\n");
|
||||||
|
bValidArgs = false;
|
||||||
|
bDone = true;
|
||||||
|
} else {
|
||||||
|
bFile = true;
|
||||||
|
inFile = args[++i];
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case FULL_COMMAND_PREFIX + OUTPUT_STRING:
|
case FULL_COMMAND_PREFIX + OUTPUT_STRING:
|
||||||
case COMMAND_PREFIX + "o":
|
case COMMAND_PREFIX + "o":
|
||||||
if (i < args.length - 1) { // Check for a filter following the -o
|
if (i == args.length - 1) {
|
||||||
if (!args[i + 1].startsWith("-")) {
|
printHelp("No output file specified with the " + tempValue
|
||||||
outFile = args[i++ + 1];
|
+ " option" + "\n");
|
||||||
} else {
|
bValidArgs = false;
|
||||||
System.out.print("no output file specified with -o option");
|
bDone = true;
|
||||||
bValidArgs = false;
|
} else {
|
||||||
}
|
outFile = args[i++ + 1];
|
||||||
|
if (outFile.isEmpty()) {
|
||||||
|
printHelp("No output file specified with the " + tempValue
|
||||||
|
+ "option" + "\n");
|
||||||
|
bValidArgs = false;
|
||||||
|
bDone = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bOutput = true;
|
bOutput = true;
|
||||||
break;
|
break;
|
||||||
@ -144,7 +166,10 @@ public class Commander {
|
|||||||
if (pcrFilter.matches(REGEX)) {
|
if (pcrFilter.matches(REGEX)) {
|
||||||
pcrNumber = Integer.parseInt(pcrFilter);
|
pcrNumber = Integer.parseInt(pcrFilter);
|
||||||
} else {
|
} else {
|
||||||
System.out.println("invalid parameter following -p: " + pcrFilter);
|
printHelp("Invalid parameter following -p: "
|
||||||
|
+ pcrFilter + "\n");
|
||||||
|
bValidArgs = false;
|
||||||
|
bDone = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -168,11 +193,15 @@ public class Commander {
|
|||||||
bHelp = true;
|
bHelp = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
printHelp("");
|
//System.out.print("Unknown option: " + tempValue + "\n");
|
||||||
bValidArgs = false;
|
bValidArgs = false;
|
||||||
|
bDone = true;
|
||||||
|
printHelp("Unknown option: " + tempValue + "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
checkForInvalidOptions();
|
||||||
|
checkDefaults();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -316,6 +345,41 @@ public class Commander {
|
|||||||
public final int getPcrNumber() {
|
public final int getPcrNumber() {
|
||||||
return pcrNumber;
|
return pcrNumber;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Setter for the input associated with the EventIds flag.
|
||||||
|
*/
|
||||||
|
public final void setEventIdsFlag() {
|
||||||
|
bEventIds = true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Check for invalid option combinations.
|
||||||
|
* @return false is an invalid combination was found
|
||||||
|
*/
|
||||||
|
public final boolean checkForInvalidOptions() {
|
||||||
|
if (!bEventIds && (bEventHex || bContentHex)) {
|
||||||
|
bValidArgs = false;
|
||||||
|
} else if (bHex && (bEventHex || bContentHex)) {
|
||||||
|
bValidArgs = false;
|
||||||
|
} else {
|
||||||
|
bValidArgs = true;
|
||||||
|
}
|
||||||
|
return bValidArgs;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Check for situations where default values need to be set.
|
||||||
|
*/
|
||||||
|
public final void checkDefaults() {
|
||||||
|
if (bFile) {
|
||||||
|
if (!bHex && !bEventIds && !bContentHex && !bPCRs) {
|
||||||
|
bEventIds = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bOutput) {
|
||||||
|
if (!bHex && !bEventIds && !bContentHex && !bPCRs) {
|
||||||
|
bEventIds = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This method is used to inform the user of the allowed functionality of the program.
|
* This method is used to inform the user of the allowed functionality of the program.
|
||||||
* @param message message caller specific message to print before listing the help.
|
* @param message message caller specific message to print before listing the help.
|
||||||
@ -324,70 +388,52 @@ public class Commander {
|
|||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
String os = System.getProperty("os.name").toLowerCase();
|
String os = System.getProperty("os.name").toLowerCase();
|
||||||
if ((message != null) && (!message.isEmpty())) {
|
if ((message != null) && (!message.isEmpty())) {
|
||||||
sb.append("\n\n" + message);
|
sb.append("\n" + message);
|
||||||
}
|
}
|
||||||
sb.append("\nTCG Log Parser ");
|
sb.append("\nTCG Log Parser ");
|
||||||
if (os.compareToIgnoreCase("linux") == 0) {
|
if (os.compareToIgnoreCase("linux") == 0) {
|
||||||
sb.append("Usage: sh elt.sh [OPTION]...-f [FILE]...\n");
|
sb.append("Usage: elt [OPTION]... [OPTION]... and Options\n");
|
||||||
} else {
|
} else {
|
||||||
sb.append("Usage: ./elt.ps1 [OPTION]...-f [FILE]...\n");
|
sb.append("Usage: ./elt.ps1 [OPTION]... [OPTION]...\n");
|
||||||
}
|
}
|
||||||
sb.append("Options:\n"
|
sb.append("\nOptions:\n"
|
||||||
+ " -f\t--file\t\t Use specific Event Log file. "
|
+ " -f\t--file\t\t Use a specific Event Log file. "
|
||||||
+ "\n\t\t\t Following parameter MUST be a path and file name."
|
+ "\n\t\t\t example: elt [-f|--file] /path/to/eventlogfile\n"
|
||||||
+ "\n\t\t\t The local Event Log file will be used if this option is not present."
|
+ " -e\t--event\t\t Display all event details for a specific event"
|
||||||
+ "\n\t\t\t Note: Access to the local Event Log may require admin privileges.\n"
|
+ "\n\t\t\t example: elt [-e|--event] 30"
|
||||||
+ " -e\t--event\t Display event descriptions (including event content) in "
|
+ "\n\t\t\t No event specified will default to all events"
|
||||||
+ "human readable form."
|
+ "\n\t\t\t example: elt [-e|--event]\n"
|
||||||
+ "\n\t\t\t Following optional parameter is a single event number used to filter"
|
+ " -ec\t--contenthex\t Include event content in hex format."
|
||||||
+ " the output."
|
+ " Only valid with -e option.\n"
|
||||||
+ "\n\t\t\t All events will be displayed if the optional parameter is not +"
|
+ " -ex\t--eventhex\t Include event only (no content) in hex format."
|
||||||
+ "provided.\n"
|
+ " Only valid with -e option.\n"
|
||||||
+ " -ec\t--contenthex\t Displays event content"
|
+ " -d\t--diff\t\t Compares two TCG Event Logs and displays events from second"
|
||||||
+ " in eventhex format when -event is used.\n"
|
+ " file that do not match."
|
||||||
+ " -ex\t--eventhex\t Displays event in hex format when -event is used.\n"
|
+ "\n\t\t\t example: elt [-d|--diff] /path/to/eventlogfile1 "
|
||||||
+ " -d\t--diff\t\t Compares two TCG Event Logs and outputs a list of events"
|
+ "/path/to/eventlogfile2\n"
|
||||||
+ " of the second log that differred.\n"
|
+ " -o\t--output\t Redirect output to a specified path/file."
|
||||||
+ " -o\t--output\t Output to a file. "
|
+ "\n\t\t\t example: elt [-o|--output] /path/to/outputfile\n"
|
||||||
+ "\n\t\t\t Following parameter MUST be a relative path and file name.\n"
|
+ " -p\t--pcr\t\t Display all expected PCR values calculated from the TCG Log "
|
||||||
+ " -p\t--pcr\t\t Output expected PCR value calculated from the "
|
+ "(for PCR Replay)."
|
||||||
+ "TCG Log (for PCR Replay)."
|
+ "\n\t\t\t Specify a PCR number to filter on a single PCR."
|
||||||
+ "\n\t\t\t Following parameter MAY be a PCR number used to specify a single pcr."
|
+ "\n\t\t\t example: elt [-p|--pcr] 5\n"
|
||||||
+ "\n\t\t\t No following parameters will display all PCRs.\n"
|
+ " -v\t--version\t Version info.\n"
|
||||||
+ " -v\t--version\t Parser Version.\n"
|
+ " -x\t--hex\t\t Event only (no content) in hex format."
|
||||||
// + " -V\t--Verify\t Attempts to verify the log file against values."
|
|
||||||
+ " -x\t--hex\t\t Displays event in hex format. Use with -ec to get content."
|
|
||||||
+ "\n\t\t\t Use -e -ec and -ex options to filter output."
|
|
||||||
+ "\n\t\t\t All output will be human readble form if not present."
|
|
||||||
+ "\n\n");
|
+ "\n\n");
|
||||||
if (os.compareToIgnoreCase("linux") == 0) {
|
if (os.compareToIgnoreCase("linux") == 0) {
|
||||||
sb.append("\nIf no FILE parameter is provided then the standard Linux TCGEventLog path "
|
sb.append("\nTo run this tool it may require root privileges due to the permissions set "
|
||||||
+ "\n(/sys/kernel/security/tpm0/binary_bios_measurements) is used."
|
+ "on the event log file. \nRun without options to display all event details for "
|
||||||
+ "\n Note admin privileges may be required (e.g. use sudo when running the "
|
+ "/sys/kernel/security/tpm0/binary_bios_measurements. "
|
||||||
+ " script).\n"
|
+ "\nAll options must be separated by a space delimiter as concatenation of "
|
||||||
+ "All OPTIONS must be seperated by a space delimiter, no concatenation"
|
+ "options is currently not supported.\n"
|
||||||
+ " of OPTIONS is currently supported.\n"
|
|
||||||
+ "\nExamples: (run from the script directory)\n"
|
|
||||||
+ "1. Display all events from the binary_bios_measurements.bin test pattern:\n"
|
|
||||||
+ " sh elt.sh -f ../test/testdata/binary_bios_measurements_Dell_Fedora30.bin "
|
|
||||||
+ " -e\n"
|
|
||||||
+ "2. Display only the event with an index of 0 (e.g event that extend PCR 0):\n"
|
|
||||||
+ " sh scripts/elt.sh -f "
|
|
||||||
+ "../test/testdata/binary_bios_measurements_Dell_Fedora30.bin -p 0\n"
|
|
||||||
);
|
);
|
||||||
} else { //windows
|
} else { //windows
|
||||||
sb.append("\nIf no FILE parameter is provided then the "
|
sb.append("\nIf no file parameter is provided then the "
|
||||||
+ "standard Windows TCGEventLog path (C:\\Windows\\Logs\\MeasuredBoot) is used"
|
+ "standard Windows TCGEventLog path (C:\\Windows\\Logs\\MeasuredBoot) is used"
|
||||||
|
+ "\nIf no parameter is given then the -e option will be used as default."
|
||||||
+ "\n Note admin privileges may be required (e.g. run as Administrator).\n"
|
+ "\n Note admin privileges may be required (e.g. run as Administrator).\n"
|
||||||
+ "All OPTIONS must be seperated by a space delimiter, "
|
+ "All OPTIONS must be seperated by a space delimiter, "
|
||||||
+ "no concatenation of OPTIONS is currently supported.\n"
|
+ "no concatenation of options is not supported.\n"
|
||||||
+ "\nExamples:(run from the script directory)\n"
|
|
||||||
+ "1. Display all events from the binary_bios_measurements.bin test pattern:\n"
|
|
||||||
+ " ./elt.ps1 -f "
|
|
||||||
+ "..\\test\\testdata\\binary_bios_measurements_Dell_Fedora30.bin -e\n"
|
|
||||||
+ "2. Display only the event with an index of 0 (e.g event that extend PCR 0):\n"
|
|
||||||
+ " ./elt.ps1 -f "
|
|
||||||
+ "..\\test\\testdata\\binary_bios_measurements_Dell_Fedora30.bin -p 0\n"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
System.out.println(sb.toString());
|
System.out.println(sb.toString());
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package hirs.tcg_eventlog;
|
package hirs.tcg_eventlog;
|
||||||
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
@ -12,7 +11,6 @@ import java.security.cert.CertificateException;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
import hirs.tpm.eventlog.TCGEventLog;
|
import hirs.tpm.eventlog.TCGEventLog;
|
||||||
import hirs.tpm.eventlog.TpmPcrEvent;
|
import hirs.tpm.eventlog.TpmPcrEvent;
|
||||||
import hirs.utils.HexUtils;
|
import hirs.utils.HexUtils;
|
||||||
@ -35,9 +33,10 @@ final class Main {
|
|||||||
public static void main(final String[] args) {
|
public static void main(final String[] args) {
|
||||||
commander = new Commander(args);
|
commander = new Commander(args);
|
||||||
if (!commander.getValidityFlag()) {
|
if (!commander.getValidityFlag()) {
|
||||||
System.out.print("Program exiting without processs due to issues with"
|
System.out.print("\nProgram exiting without processs due to issues with"
|
||||||
+ " parameters provided.");
|
+ " parameters provided.\n");
|
||||||
System.exit(1);
|
commander.printHelp("");
|
||||||
|
System.exit(0);
|
||||||
}
|
}
|
||||||
if (commander.hasArguments()) {
|
if (commander.hasArguments()) {
|
||||||
if (commander.getDoneFlag()) {
|
if (commander.getDoneFlag()) {
|
||||||
@ -50,15 +49,14 @@ final class Main {
|
|||||||
if (commander.getOutputFlag()) {
|
if (commander.getOutputFlag()) {
|
||||||
try {
|
try {
|
||||||
outputStream = new FileOutputStream(commander.getOutputFileName());
|
outputStream = new FileOutputStream(commander.getOutputFileName());
|
||||||
} catch (FileNotFoundException e) {
|
System.out.print("Writing to output file: " + commander.getOutputFileName()
|
||||||
|
+ "\n");
|
||||||
|
} catch (Exception e) {
|
||||||
System.out.print("Error opening output file" + commander.getOutputFileName()
|
System.out.print("Error opening output file" + commander.getOutputFileName()
|
||||||
+ "\nError was " + e.getMessage());
|
+ "\nError was " + e.getMessage());
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (commander.getFileFlag()) {
|
|
||||||
eventLog = openLog(commander.getInFileName());
|
|
||||||
}
|
|
||||||
if (commander.getContentFlag()) {
|
if (commander.getContentFlag()) {
|
||||||
bContentFlag = true;
|
bContentFlag = true;
|
||||||
}
|
}
|
||||||
@ -91,10 +89,8 @@ final class Main {
|
|||||||
} // End commander processing
|
} // End commander processing
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (eventLog == null) {
|
eventLog = openLog(commander.getInFileName());
|
||||||
eventLog = openLog("");
|
// Main Event processing
|
||||||
}
|
|
||||||
// Main Event processing
|
|
||||||
TCGEventLog evLog = new TCGEventLog(eventLog, bEventFlag, bContentFlag, bHexEvent);
|
TCGEventLog evLog = new TCGEventLog(eventLog, bEventFlag, bContentFlag, bHexEvent);
|
||||||
if (bPcrFlag) {
|
if (bPcrFlag) {
|
||||||
String[] pcrs = evLog.getExpectedPCRValues();
|
String[] pcrs = evLog.getExpectedPCRValues();
|
||||||
@ -116,9 +112,8 @@ final class Main {
|
|||||||
writeOut("\n----------------- End PCR Values ----------------- \n\n");
|
writeOut("\n----------------- End PCR Values ----------------- \n\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// General event log output
|
// General event log output
|
||||||
if (bEventFlag) {
|
if ((bEventFlag || bHexFlag) && !bPcrFlag) {
|
||||||
if (!bHexFlag) {
|
if (!bHexFlag) {
|
||||||
if (evLog.isCryptoAgile()) {
|
if (evLog.isCryptoAgile()) {
|
||||||
writeOut("\nEvent Log follows the \"Crypto Agile\" format and has "
|
writeOut("\nEvent Log follows the \"Crypto Agile\" format and has "
|
||||||
@ -135,7 +130,7 @@ final class Main {
|
|||||||
if ((commander.getPcrNumber() == event.getPcrIndex())
|
if ((commander.getPcrNumber() == event.getPcrIndex())
|
||||||
|| commander.getPcrNumber() == -1) {
|
|| commander.getPcrNumber() == -1) {
|
||||||
if (bHexFlag) {
|
if (bHexFlag) {
|
||||||
if (bEventFlag || bHexEvent) {
|
if (bHexFlag || bHexEvent) {
|
||||||
writeOut(HexUtils.byteArrayToHexString(event.getEvent())
|
writeOut(HexUtils.byteArrayToHexString(event.getEvent())
|
||||||
+ "\n");
|
+ "\n");
|
||||||
}
|
}
|
||||||
@ -178,7 +173,6 @@ final class Main {
|
|||||||
boolean bDefault = false;
|
boolean bDefault = false;
|
||||||
bHexFlag = commander.getHexFlag();
|
bHexFlag = commander.getHexFlag();
|
||||||
try {
|
try {
|
||||||
|
|
||||||
if (fileName.isEmpty()) {
|
if (fileName.isEmpty()) {
|
||||||
if (os.compareToIgnoreCase("linux") == 0) { // need to find Windows path
|
if (os.compareToIgnoreCase("linux") == 0) { // need to find Windows path
|
||||||
fName = "/sys/kernel/security/tpm0/binary_bios_measurements";
|
fName = "/sys/kernel/security/tpm0/binary_bios_measurements";
|
||||||
@ -196,9 +190,9 @@ final class Main {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
String error = "Error reading event Log File: " + e.toString();
|
String error = "Error reading event Log File: " + e.toString();
|
||||||
if (bDefault) {
|
if (bDefault) {
|
||||||
error += "\nTry using the -f option to specify an Event Log File";
|
error += "\nTry using the -f option to specify an Event Log File\n";
|
||||||
}
|
}
|
||||||
writeOut(error);
|
System.out.print(error);
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
return rawLog;
|
return rawLog;
|
||||||
@ -218,6 +212,8 @@ final class Main {
|
|||||||
System.out.print(dataNoNull); // output to the console
|
System.out.print(dataNoNull); // output to the console
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
System.out.print("Error writing to output file: " + commander.getOutputFileName()
|
||||||
|
+ "\n error was: " + e.toString() + "\n");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,7 +243,8 @@ final class Main {
|
|||||||
ArrayList<TpmPcrEvent> errors = diffEventLogs(eventLog1.getEventList(),
|
ArrayList<TpmPcrEvent> errors = diffEventLogs(eventLog1.getEventList(),
|
||||||
eventLog2.getEventList(), commander.getPcrNumber());
|
eventLog2.getEventList(), commander.getPcrNumber());
|
||||||
if (errors.isEmpty() && !bHexFlag) {
|
if (errors.isEmpty() && !bHexFlag) {
|
||||||
sb.append("\nEvent Log " + logFileName1 + " MATCHED EventLog " + logFileName2);
|
sb.append("\nEvent Log " + logFileName1 + " MATCHED EventLog " + logFileName2
|
||||||
|
+ "\n");
|
||||||
} else {
|
} else {
|
||||||
if (!errors.isEmpty() && !bHexFlag) {
|
if (!errors.isEmpty() && !bHexFlag) {
|
||||||
sb.append("\nEvent Log " + logFileName1
|
sb.append("\nEvent Log " + logFileName1
|
||||||
@ -332,4 +329,15 @@ final class Main {
|
|||||||
}
|
}
|
||||||
return matchFound;
|
return matchFound;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* Diagnostic method for detecting flag settings.
|
||||||
|
*/
|
||||||
|
public static void dumpFlags() {
|
||||||
|
System.out.print("Event Flag is " + commander.getEventIdsFlag() + "\n");
|
||||||
|
System.out.print("Hex Flag is " + commander.getEventHexFlag() + "\n");
|
||||||
|
System.out.print("Context Flag is " + commander.getContentFlag() + "\n");
|
||||||
|
System.out.print("PCR Flag is " + commander.getPCRFlag() + "\n");
|
||||||
|
System.out.print("Output File Flag is " + commander.getFileFlag() + "\n");
|
||||||
|
System.out.print("Output Flag is " + commander.getOutputFlag() + "\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,10 @@ dependencies {
|
|||||||
testCompile 'org.testng:testng:6.8.8'
|
testCompile 'org.testng:testng:6.8.8'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
testLogging.showStandardStreams true
|
||||||
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
manifest {
|
manifest {
|
||||||
attributes("Main-Class": "hirs.swid.Main",
|
attributes("Main-Class": "hirs.swid.Main",
|
||||||
|
@ -65,7 +65,7 @@ public class CredentialParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void parsePEMCredentials(String certificateFile, String privateKeyFile)
|
public void parsePEMCredentials(String certificateFile, String privateKeyFile)
|
||||||
throws CertificateException, FileNotFoundException {
|
throws Exception {
|
||||||
certificate = parsePEMCertificates(certificateFile).get(0);
|
certificate = parsePEMCertificates(certificateFile).get(0);
|
||||||
if (certificate.getIssuerX500Principal().equals(certificate.getSubjectX500Principal())) {
|
if (certificate.getIssuerX500Principal().equals(certificate.getSubjectX500Principal())) {
|
||||||
throw new CertificateException("Signing certificate cannot be self-signed!");
|
throw new CertificateException("Signing certificate cannot be self-signed!");
|
||||||
@ -125,7 +125,8 @@ public class CredentialParser {
|
|||||||
CertificateFactory certificateFactory = CertificateFactory.getInstance(X509);
|
CertificateFactory certificateFactory = CertificateFactory.getInstance(X509);
|
||||||
|
|
||||||
while (bis.available() > 0) {
|
while (bis.available() > 0) {
|
||||||
certificates = (List<X509Certificate>) certificateFactory.generateCertificates(bis);
|
certificates =
|
||||||
|
(List<X509Certificate>) certificateFactory.generateCertificates(bis);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (certificates.size() < 1) {
|
if (certificates.size() < 1) {
|
||||||
@ -160,10 +161,11 @@ public class CredentialParser {
|
|||||||
* @param filename
|
* @param filename
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private PrivateKey parsePEMPrivateKey(String filename, String algorithm) {
|
private PrivateKey parsePEMPrivateKey(String filename, String algorithm) throws Exception {
|
||||||
PrivateKey privateKey = null;
|
PrivateKey privateKey = null;
|
||||||
FileInputStream fis = null;
|
FileInputStream fis = null;
|
||||||
DataInputStream dis = null;
|
DataInputStream dis = null;
|
||||||
|
String errorMessage = "";
|
||||||
try {
|
try {
|
||||||
File file = new File(filename);
|
File file = new File(filename);
|
||||||
fis = new FileInputStream(file);
|
fis = new FileInputStream(file);
|
||||||
@ -186,15 +188,15 @@ public class CredentialParser {
|
|||||||
privateKey = keyFactory.generatePrivate(spec);
|
privateKey = keyFactory.generatePrivate(spec);
|
||||||
}
|
}
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
System.out.println("Unable to locate private key file: " + filename);
|
errorMessage += "Unable to locate private key file: " + filename;
|
||||||
} catch (DecoderException e) {
|
} catch (DecoderException e) {
|
||||||
System.out.println("Failed to parse uploaded pem file: " + e.getMessage());
|
errorMessage += "Failed to parse uploaded pem file: " + e.getMessage();
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
System.out.println("Unable to instantiate KeyFactory with algorithm: " + algorithm);
|
errorMessage += "Unable to instantiate KeyFactory with algorithm: " + algorithm;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("IOException: " + e.getMessage());
|
errorMessage += "IOException: " + e.getMessage();
|
||||||
} catch (InvalidKeySpecException e) {
|
} catch (InvalidKeySpecException e) {
|
||||||
System.out.println("Error instantiating PKCS8EncodedKeySpec object: " + e.getMessage());
|
errorMessage += "Error instantiating PKCS8EncodedKeySpec object: " + e.getMessage();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (fis != null) {
|
if (fis != null) {
|
||||||
@ -204,7 +206,10 @@ public class CredentialParser {
|
|||||||
dis.close();
|
dis.close();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
System.out.println("Error closing input stream: " + e.getMessage());
|
errorMessage += "Error closing input stream: " + e.getMessage();
|
||||||
|
}
|
||||||
|
if (!errorMessage.isEmpty()) {
|
||||||
|
throw new Exception("Error parsing private key: " + errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ public class Main {
|
|||||||
String jksTruststoreFile = commander.getTruststoreFile();
|
String jksTruststoreFile = commander.getTruststoreFile();
|
||||||
String certificateFile = commander.getPublicCertificate();
|
String certificateFile = commander.getPublicCertificate();
|
||||||
String privateKeyFile = commander.getPrivateKeyFile();
|
String privateKeyFile = commander.getPrivateKeyFile();
|
||||||
|
boolean embeddedCert = commander.isEmbedded();
|
||||||
boolean defaultKey = commander.isDefaultKey();
|
boolean defaultKey = commander.isDefaultKey();
|
||||||
String rimEventLog = commander.getRimEventLog();
|
String rimEventLog = commander.getRimEventLog();
|
||||||
switch (createType) {
|
switch (createType) {
|
||||||
@ -63,6 +64,9 @@ public class Main {
|
|||||||
gateway.setDefaultCredentials(false);
|
gateway.setDefaultCredentials(false);
|
||||||
gateway.setPemCertificateFile(certificateFile);
|
gateway.setPemCertificateFile(certificateFile);
|
||||||
gateway.setPemPrivateKeyFile(privateKeyFile);
|
gateway.setPemPrivateKeyFile(privateKeyFile);
|
||||||
|
if (embeddedCert) {
|
||||||
|
gateway.setEmbeddedCert(true);
|
||||||
|
}
|
||||||
} else if (defaultKey){
|
} else if (defaultKey){
|
||||||
gateway.setDefaultCredentials(true);
|
gateway.setDefaultCredentials(true);
|
||||||
gateway.setJksTruststoreFile(SwidTagConstants.DEFAULT_KEYSTORE_FILE);
|
gateway.setJksTruststoreFile(SwidTagConstants.DEFAULT_KEYSTORE_FILE);
|
||||||
|
@ -15,7 +15,7 @@ public class SwidTagConstants {
|
|||||||
public static final String DEFAULT_KEYSTORE_FILE = "/opt/hirs/rimtool/keystore.jks";
|
public static final String DEFAULT_KEYSTORE_FILE = "/opt/hirs/rimtool/keystore.jks";
|
||||||
public static final String DEFAULT_KEYSTORE_PASSWORD = "password";
|
public static final String DEFAULT_KEYSTORE_PASSWORD = "password";
|
||||||
public static final String DEFAULT_PRIVATE_KEY_ALIAS = "selfsigned";
|
public static final String DEFAULT_PRIVATE_KEY_ALIAS = "selfsigned";
|
||||||
public static final String DEFAULT_ATTRIBUTES_FILE = "rim_fields.json";
|
public static final String DEFAULT_ATTRIBUTES_FILE = "/opt/hirs/rimtool/rim_fields.json";
|
||||||
public static final String DEFAULT_ENGLISH = "en";
|
public static final String DEFAULT_ENGLISH = "en";
|
||||||
|
|
||||||
public static final String SIGNATURE_ALGORITHM_RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
|
public static final String SIGNATURE_ALGORITHM_RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
|
||||||
|
@ -12,6 +12,7 @@ import org.w3c.dom.Document;
|
|||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
|
|
||||||
import javax.json.Json;
|
import javax.json.Json;
|
||||||
|
import javax.json.JsonException;
|
||||||
import javax.json.JsonObject;
|
import javax.json.JsonObject;
|
||||||
import javax.json.JsonReader;
|
import javax.json.JsonReader;
|
||||||
import javax.xml.bind.JAXBContext;
|
import javax.xml.bind.JAXBContext;
|
||||||
@ -58,6 +59,7 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
|
import java.security.KeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
@ -82,7 +84,9 @@ public class SwidTagGateway {
|
|||||||
private String jksTruststoreFile;
|
private String jksTruststoreFile;
|
||||||
private String pemPrivateKeyFile;
|
private String pemPrivateKeyFile;
|
||||||
private String pemCertificateFile;
|
private String pemCertificateFile;
|
||||||
|
private boolean embeddedCert;
|
||||||
private String rimEventLog;
|
private String rimEventLog;
|
||||||
|
private String errorRequiredFields;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor initializes jaxbcontext, marshaller, and unmarshaller
|
* Default constructor initializes jaxbcontext, marshaller, and unmarshaller
|
||||||
@ -94,7 +98,9 @@ public class SwidTagGateway {
|
|||||||
attributesFile = SwidTagConstants.DEFAULT_ATTRIBUTES_FILE;
|
attributesFile = SwidTagConstants.DEFAULT_ATTRIBUTES_FILE;
|
||||||
defaultCredentials = true;
|
defaultCredentials = true;
|
||||||
pemCertificateFile = "";
|
pemCertificateFile = "";
|
||||||
|
embeddedCert = false;
|
||||||
rimEventLog = "";
|
rimEventLog = "";
|
||||||
|
errorRequiredFields = "";
|
||||||
} catch (JAXBException e) {
|
} catch (JAXBException e) {
|
||||||
System.out.println("Error initializing jaxbcontext: " + e.getMessage());
|
System.out.println("Error initializing jaxbcontext: " + e.getMessage());
|
||||||
}
|
}
|
||||||
@ -105,7 +111,7 @@ public class SwidTagGateway {
|
|||||||
*
|
*
|
||||||
* @param attributesFile
|
* @param attributesFile
|
||||||
*/
|
*/
|
||||||
public void setAttributesFile(String attributesFile) {
|
public void setAttributesFile(final String attributesFile) {
|
||||||
this.attributesFile = attributesFile;
|
this.attributesFile = attributesFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +121,7 @@ public class SwidTagGateway {
|
|||||||
* @param defaultCredentials
|
* @param defaultCredentials
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public void setDefaultCredentials(boolean defaultCredentials) {
|
public void setDefaultCredentials(final boolean defaultCredentials) {
|
||||||
this.defaultCredentials = defaultCredentials;
|
this.defaultCredentials = defaultCredentials;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +130,7 @@ public class SwidTagGateway {
|
|||||||
*
|
*
|
||||||
* @param jksTruststoreFile
|
* @param jksTruststoreFile
|
||||||
*/
|
*/
|
||||||
public void setJksTruststoreFile(String jksTruststoreFile) {
|
public void setJksTruststoreFile(final String jksTruststoreFile) {
|
||||||
this.jksTruststoreFile = jksTruststoreFile;
|
this.jksTruststoreFile = jksTruststoreFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +139,7 @@ public class SwidTagGateway {
|
|||||||
*
|
*
|
||||||
* @param pemPrivateKeyFile
|
* @param pemPrivateKeyFile
|
||||||
*/
|
*/
|
||||||
public void setPemPrivateKeyFile(String pemPrivateKeyFile) {
|
public void setPemPrivateKeyFile(final String pemPrivateKeyFile) {
|
||||||
this.pemPrivateKeyFile = pemPrivateKeyFile;
|
this.pemPrivateKeyFile = pemPrivateKeyFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,16 +148,25 @@ public class SwidTagGateway {
|
|||||||
*
|
*
|
||||||
* @param pemCertificateFile
|
* @param pemCertificateFile
|
||||||
*/
|
*/
|
||||||
public void setPemCertificateFile(String pemCertificateFile) {
|
public void setPemCertificateFile(final String pemCertificateFile) {
|
||||||
this.pemCertificateFile = pemCertificateFile;
|
this.pemCertificateFile = pemCertificateFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter to embed certificate file in signature block
|
||||||
|
*
|
||||||
|
* @param embeddedCert
|
||||||
|
*/
|
||||||
|
public void setEmbeddedCert(final boolean embeddedCert) {
|
||||||
|
this.embeddedCert = embeddedCert;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setter for event log support RIM
|
* Setter for event log support RIM
|
||||||
*
|
*
|
||||||
* @param rimEventLog
|
* @param rimEventLog
|
||||||
*/
|
*/
|
||||||
public void setRimEventLog(String rimEventLog) {
|
public void setRimEventLog(final String rimEventLog) {
|
||||||
this.rimEventLog = rimEventLog;
|
this.rimEventLog = rimEventLog;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,33 +197,44 @@ public class SwidTagGateway {
|
|||||||
JAXBElement<SoftwareMeta> meta = objectFactory.createSoftwareIdentityMeta(
|
JAXBElement<SoftwareMeta> meta = objectFactory.createSoftwareIdentityMeta(
|
||||||
createSoftwareMeta(configProperties.getJsonObject(SwidTagConstants.META)));
|
createSoftwareMeta(configProperties.getJsonObject(SwidTagConstants.META)));
|
||||||
swidTag.getEntityOrEvidenceOrLink().add(meta);
|
swidTag.getEntityOrEvidenceOrLink().add(meta);
|
||||||
|
//Payload
|
||||||
|
ResourceCollection payload = createPayload(
|
||||||
|
configProperties.getJsonObject(SwidTagConstants.PAYLOAD));
|
||||||
|
//Directory
|
||||||
|
Directory directory = createDirectory(
|
||||||
|
configProperties.getJsonObject(SwidTagConstants.PAYLOAD)
|
||||||
|
.getJsonObject(SwidTagConstants.DIRECTORY));
|
||||||
//File
|
//File
|
||||||
hirs.swid.xjc.File file = createFile(
|
hirs.swid.xjc.File file = createFile(
|
||||||
configProperties.getJsonObject(SwidTagConstants.PAYLOAD)
|
configProperties.getJsonObject(SwidTagConstants.PAYLOAD)
|
||||||
.getJsonObject(SwidTagConstants.DIRECTORY)
|
.getJsonObject(SwidTagConstants.DIRECTORY)
|
||||||
.getJsonObject(SwidTagConstants.FILE));
|
.getJsonObject(SwidTagConstants.FILE));
|
||||||
//Directory
|
//Nest File in Directory in Payload
|
||||||
Directory directory = createDirectory(
|
|
||||||
configProperties.getJsonObject(SwidTagConstants.PAYLOAD)
|
|
||||||
.getJsonObject(SwidTagConstants.DIRECTORY));
|
|
||||||
directory.getDirectoryOrFile().add(file);
|
directory.getDirectoryOrFile().add(file);
|
||||||
//Payload
|
|
||||||
ResourceCollection payload = createPayload(
|
|
||||||
configProperties.getJsonObject(SwidTagConstants.PAYLOAD));
|
|
||||||
payload.getDirectoryOrFileOrProcess().add(directory);
|
payload.getDirectoryOrFileOrProcess().add(directory);
|
||||||
JAXBElement<ResourceCollection> jaxbPayload =
|
JAXBElement<ResourceCollection> jaxbPayload =
|
||||||
objectFactory.createSoftwareIdentityPayload(payload);
|
objectFactory.createSoftwareIdentityPayload(payload);
|
||||||
swidTag.getEntityOrEvidenceOrLink().add(jaxbPayload);
|
swidTag.getEntityOrEvidenceOrLink().add(jaxbPayload);
|
||||||
|
//Signature
|
||||||
|
if (errorRequiredFields.isEmpty()) {
|
||||||
|
Document signedSoftwareIdentity = signXMLDocument(
|
||||||
|
objectFactory.createSoftwareIdentity(swidTag));
|
||||||
|
writeSwidTagFile(signedSoftwareIdentity, filename);
|
||||||
|
} else {
|
||||||
|
System.out.println("The following fields cannot be empty or null: "
|
||||||
|
+ errorRequiredFields.substring(0, errorRequiredFields.length()-2));
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
} catch (JsonException e) {
|
||||||
|
System.out.println("Error reading JSON attributes: " + e.getMessage());
|
||||||
|
System.exit(1);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
System.out.println("File does not exist or cannot be read: " + e.getMessage());
|
System.out.println("File does not exist or cannot be read: " + e.getMessage());
|
||||||
|
System.exit(1);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
System.out.println(e.getMessage());
|
System.out.println(e.getMessage());
|
||||||
|
System.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Document signedSoftwareIdentity = signXMLDocument(
|
|
||||||
objectFactory.createSoftwareIdentity(swidTag));
|
|
||||||
writeSwidTagFile(signedSoftwareIdentity, filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -216,7 +242,7 @@ public class SwidTagGateway {
|
|||||||
*
|
*
|
||||||
* @param swidTag
|
* @param swidTag
|
||||||
*/
|
*/
|
||||||
public void writeSwidTagFile(Document swidTag, String output) {
|
public void writeSwidTagFile(final Document swidTag, final String output) {
|
||||||
try {
|
try {
|
||||||
TransformerFactory tf = TransformerFactory.newInstance();
|
TransformerFactory tf = TransformerFactory.newInstance();
|
||||||
Transformer transformer = tf.newTransformer();
|
Transformer transformer = tf.newTransformer();
|
||||||
@ -244,27 +270,31 @@ public class SwidTagGateway {
|
|||||||
* @param jsonObject the Properties object containing parameters from file
|
* @param jsonObject the Properties object containing parameters from file
|
||||||
* @return SoftwareIdentity object created from the properties
|
* @return SoftwareIdentity object created from the properties
|
||||||
*/
|
*/
|
||||||
private SoftwareIdentity createSwidTag(JsonObject jsonObject) {
|
private SoftwareIdentity createSwidTag(final JsonObject jsonObject) {
|
||||||
SoftwareIdentity swidTag = objectFactory.createSoftwareIdentity();
|
SoftwareIdentity swidTag = objectFactory.createSoftwareIdentity();
|
||||||
swidTag.setLang(SwidTagConstants.DEFAULT_ENGLISH);
|
if (jsonObject == null) {
|
||||||
String name = jsonObject.getString(SwidTagConstants.NAME, "");
|
errorRequiredFields += SwidTagConstants.SOFTWARE_IDENTITY + ", ";
|
||||||
if (!name.isEmpty()) {
|
} else {
|
||||||
swidTag.setName(name);
|
swidTag.setLang(SwidTagConstants.DEFAULT_ENGLISH);
|
||||||
}
|
String name = jsonObject.getString(SwidTagConstants.NAME, "");
|
||||||
String tagId = jsonObject.getString(SwidTagConstants.TAGID, "");
|
if (!name.isEmpty()) {
|
||||||
if (!tagId.isEmpty()) {
|
swidTag.setName(name);
|
||||||
swidTag.setTagId(tagId);
|
}
|
||||||
}
|
String tagId = jsonObject.getString(SwidTagConstants.TAGID, "");
|
||||||
swidTag.setTagVersion(new BigInteger(
|
if (!tagId.isEmpty()) {
|
||||||
jsonObject.getString(SwidTagConstants.TAGVERSION, "0")));
|
swidTag.setTagId(tagId);
|
||||||
swidTag.setVersion(jsonObject.getString(SwidTagConstants.VERSION, "0.0"));
|
}
|
||||||
swidTag.setCorpus(jsonObject.getBoolean(SwidTagConstants.CORPUS, false));
|
swidTag.setTagVersion(new BigInteger(
|
||||||
swidTag.setPatch(jsonObject.getBoolean(SwidTagConstants.PATCH, false));
|
jsonObject.getString(SwidTagConstants.TAGVERSION, "0")));
|
||||||
swidTag.setSupplemental(jsonObject.getBoolean(SwidTagConstants.SUPPLEMENTAL, false));
|
swidTag.setVersion(jsonObject.getString(SwidTagConstants.VERSION, "0.0"));
|
||||||
if (!swidTag.isCorpus() && !swidTag.isPatch()
|
swidTag.setCorpus(jsonObject.getBoolean(SwidTagConstants.CORPUS, false));
|
||||||
&& !swidTag.isSupplemental() && swidTag.getVersion() != "0.0") {
|
swidTag.setPatch(jsonObject.getBoolean(SwidTagConstants.PATCH, false));
|
||||||
swidTag.setVersionScheme(
|
swidTag.setSupplemental(jsonObject.getBoolean(SwidTagConstants.SUPPLEMENTAL, false));
|
||||||
jsonObject.getString(SwidTagConstants.VERSION_SCHEME, "multipartnumeric"));
|
if (!swidTag.isCorpus() && !swidTag.isPatch()
|
||||||
|
&& !swidTag.isSupplemental() && swidTag.getVersion() != "0.0") {
|
||||||
|
swidTag.setVersionScheme(
|
||||||
|
jsonObject.getString(SwidTagConstants.VERSION_SCHEME, "multipartnumeric"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return swidTag;
|
return swidTag;
|
||||||
@ -277,33 +307,38 @@ public class SwidTagGateway {
|
|||||||
* @param jsonObject the Properties object containing parameters from file
|
* @param jsonObject the Properties object containing parameters from file
|
||||||
* @return Entity object created from the properties
|
* @return Entity object created from the properties
|
||||||
*/
|
*/
|
||||||
private Entity createEntity(JsonObject jsonObject) {
|
private Entity createEntity(final JsonObject jsonObject) {
|
||||||
boolean isTagCreator = false;
|
boolean isTagCreator = false;
|
||||||
Entity entity = objectFactory.createEntity();
|
Entity entity = objectFactory.createEntity();
|
||||||
String name = jsonObject.getString(SwidTagConstants.NAME, "");
|
if (jsonObject == null) {
|
||||||
if (!name.isEmpty()) {
|
errorRequiredFields += SwidTagConstants.ENTITY + ", ";
|
||||||
entity.setName(name);
|
|
||||||
}
|
|
||||||
String[] roles = jsonObject.getString(SwidTagConstants.ROLE, "").split(",");
|
|
||||||
for (int i = 0; i < roles.length; i++) {
|
|
||||||
entity.getRole().add(roles[i]);
|
|
||||||
if (roles[i].equals("tagCreator")) {
|
|
||||||
isTagCreator = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (isTagCreator) {
|
|
||||||
String regid = jsonObject.getString(SwidTagConstants.REGID, "");
|
|
||||||
if (regid.isEmpty()) {
|
|
||||||
//throw exception that regid is required
|
|
||||||
} else {
|
|
||||||
entity.setRegid(regid);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
entity.setRegid(jsonObject.getString(SwidTagConstants.REGID, "invalid.unavailable"));
|
String name = jsonObject.getString(SwidTagConstants.NAME, "");
|
||||||
}
|
if (!name.isEmpty()) {
|
||||||
String thumbprint = jsonObject.getString(SwidTagConstants.THUMBPRINT, "");
|
entity.setName(name);
|
||||||
if (!thumbprint.isEmpty()) {
|
}
|
||||||
entity.setThumbprint(thumbprint);
|
String[] roles = jsonObject.getString(SwidTagConstants.ROLE, "").split(",");
|
||||||
|
for (int i = 0; i < roles.length; i++) {
|
||||||
|
entity.getRole().add(roles[i]);
|
||||||
|
if (roles[i].equals("tagCreator")) {
|
||||||
|
isTagCreator = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isTagCreator) {
|
||||||
|
String regid = jsonObject.getString(SwidTagConstants.REGID, "");
|
||||||
|
if (regid.isEmpty()) {
|
||||||
|
//throw exception that regid is required
|
||||||
|
} else {
|
||||||
|
entity.setRegid(regid);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entity.setRegid(jsonObject.getString(SwidTagConstants.REGID,
|
||||||
|
"invalid.unavailable"));
|
||||||
|
}
|
||||||
|
String thumbprint = jsonObject.getString(SwidTagConstants.THUMBPRINT, "");
|
||||||
|
if (!thumbprint.isEmpty()) {
|
||||||
|
entity.setThumbprint(thumbprint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
@ -315,7 +350,7 @@ public class SwidTagGateway {
|
|||||||
* @param jsonObject the Properties object containing parameters from file
|
* @param jsonObject the Properties object containing parameters from file
|
||||||
* @return Link element created from the properties
|
* @return Link element created from the properties
|
||||||
*/
|
*/
|
||||||
private Link createLink(JsonObject jsonObject) {
|
private Link createLink(final JsonObject jsonObject) {
|
||||||
Link link = objectFactory.createLink();
|
Link link = objectFactory.createLink();
|
||||||
String href = jsonObject.getString(SwidTagConstants.HREF, "");
|
String href = jsonObject.getString(SwidTagConstants.HREF, "");
|
||||||
if (!href.isEmpty()) {
|
if (!href.isEmpty()) {
|
||||||
@ -336,7 +371,7 @@ public class SwidTagGateway {
|
|||||||
* @param jsonObject the Properties object containing parameters from file
|
* @param jsonObject the Properties object containing parameters from file
|
||||||
* @return the Meta element created from the properties
|
* @return the Meta element created from the properties
|
||||||
*/
|
*/
|
||||||
private SoftwareMeta createSoftwareMeta(JsonObject jsonObject) {
|
private SoftwareMeta createSoftwareMeta(final JsonObject jsonObject) {
|
||||||
SoftwareMeta softwareMeta = objectFactory.createSoftwareMeta();
|
SoftwareMeta softwareMeta = objectFactory.createSoftwareMeta();
|
||||||
Map<QName, String> attributes = softwareMeta.getOtherAttributes();
|
Map<QName, String> attributes = softwareMeta.getOtherAttributes();
|
||||||
addNonNullAttribute(attributes, SwidTagConstants._COLLOQUIAL_VERSION,
|
addNonNullAttribute(attributes, SwidTagConstants._COLLOQUIAL_VERSION,
|
||||||
@ -350,11 +385,11 @@ public class SwidTagGateway {
|
|||||||
addNonNullAttribute(attributes, SwidTagConstants._PAYLOAD_TYPE,
|
addNonNullAttribute(attributes, SwidTagConstants._PAYLOAD_TYPE,
|
||||||
jsonObject.getString(SwidTagConstants.PAYLOAD_TYPE, ""));
|
jsonObject.getString(SwidTagConstants.PAYLOAD_TYPE, ""));
|
||||||
addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_MANUFACTURER_STR,
|
addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_MANUFACTURER_STR,
|
||||||
jsonObject.getString(SwidTagConstants.PLATFORM_MANUFACTURER_STR, ""));
|
jsonObject.getString(SwidTagConstants.PLATFORM_MANUFACTURER_STR, ""), true);
|
||||||
addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_MANUFACTURER_ID,
|
addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_MANUFACTURER_ID,
|
||||||
jsonObject.getString(SwidTagConstants.PLATFORM_MANUFACTURER_ID, ""));
|
jsonObject.getString(SwidTagConstants.PLATFORM_MANUFACTURER_ID, ""), true);
|
||||||
addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_MODEL,
|
addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_MODEL,
|
||||||
jsonObject.getString(SwidTagConstants.PLATFORM_MODEL, ""));
|
jsonObject.getString(SwidTagConstants.PLATFORM_MODEL, ""), true);
|
||||||
addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_VERSION,
|
addNonNullAttribute(attributes, SwidTagConstants._PLATFORM_VERSION,
|
||||||
jsonObject.getString(SwidTagConstants.PLATFORM_VERSION, ""));
|
jsonObject.getString(SwidTagConstants.PLATFORM_VERSION, ""));
|
||||||
addNonNullAttribute(attributes, SwidTagConstants._FIRMWARE_MANUFACTURER_STR,
|
addNonNullAttribute(attributes, SwidTagConstants._FIRMWARE_MANUFACTURER_STR,
|
||||||
@ -385,15 +420,19 @@ public class SwidTagGateway {
|
|||||||
* @param jsonObject the Properties object containing parameters from file
|
* @param jsonObject the Properties object containing parameters from file
|
||||||
* @return the Payload object created
|
* @return the Payload object created
|
||||||
*/
|
*/
|
||||||
private ResourceCollection createPayload(JsonObject jsonObject) {
|
private ResourceCollection createPayload(final JsonObject jsonObject) {
|
||||||
ResourceCollection payload = objectFactory.createResourceCollection();
|
ResourceCollection payload = objectFactory.createResourceCollection();
|
||||||
Map<QName, String> attributes = payload.getOtherAttributes();
|
Map<QName, String> attributes = payload.getOtherAttributes();
|
||||||
addNonNullAttribute(attributes, SwidTagConstants._N8060_ENVVARPREFIX,
|
if (jsonObject == null) {
|
||||||
jsonObject.getString(SwidTagConstants._N8060_ENVVARPREFIX.getLocalPart(), ""));
|
errorRequiredFields += SwidTagConstants.PAYLOAD + ", ";
|
||||||
addNonNullAttribute(attributes, SwidTagConstants._N8060_ENVVARSUFFIX,
|
} else {
|
||||||
jsonObject.getString(SwidTagConstants._N8060_ENVVARSUFFIX.getLocalPart(), ""));
|
addNonNullAttribute(attributes, SwidTagConstants._N8060_ENVVARPREFIX,
|
||||||
addNonNullAttribute(attributes, SwidTagConstants._N8060_PATHSEPARATOR,
|
jsonObject.getString(SwidTagConstants._N8060_ENVVARPREFIX.getLocalPart(), ""));
|
||||||
jsonObject.getString(SwidTagConstants._N8060_PATHSEPARATOR.getLocalPart(), ""));
|
addNonNullAttribute(attributes, SwidTagConstants._N8060_ENVVARSUFFIX,
|
||||||
|
jsonObject.getString(SwidTagConstants._N8060_ENVVARSUFFIX.getLocalPart(), ""));
|
||||||
|
addNonNullAttribute(attributes, SwidTagConstants._N8060_PATHSEPARATOR,
|
||||||
|
jsonObject.getString(SwidTagConstants._N8060_PATHSEPARATOR.getLocalPart(), ""));
|
||||||
|
}
|
||||||
|
|
||||||
return payload;
|
return payload;
|
||||||
}
|
}
|
||||||
@ -404,7 +443,7 @@ public class SwidTagGateway {
|
|||||||
* @param jsonObject the Properties object containing parameters from file
|
* @param jsonObject the Properties object containing parameters from file
|
||||||
* @return Directory object created from the properties
|
* @return Directory object created from the properties
|
||||||
*/
|
*/
|
||||||
private Directory createDirectory(JsonObject jsonObject) {
|
private Directory createDirectory(final JsonObject jsonObject) {
|
||||||
Directory directory = objectFactory.createDirectory();
|
Directory directory = objectFactory.createDirectory();
|
||||||
directory.setName(jsonObject.getString(SwidTagConstants.NAME, ""));
|
directory.setName(jsonObject.getString(SwidTagConstants.NAME, ""));
|
||||||
Map<QName, String> attributes = directory.getOtherAttributes();
|
Map<QName, String> attributes = directory.getOtherAttributes();
|
||||||
@ -434,7 +473,7 @@ public class SwidTagGateway {
|
|||||||
* @param jsonObject the Properties object containing parameters from file
|
* @param jsonObject the Properties object containing parameters from file
|
||||||
* @return File object created from the properties
|
* @return File object created from the properties
|
||||||
*/
|
*/
|
||||||
private hirs.swid.xjc.File createFile(JsonObject jsonObject) {
|
private hirs.swid.xjc.File createFile(JsonObject jsonObject) throws Exception {
|
||||||
hirs.swid.xjc.File file = objectFactory.createFile();
|
hirs.swid.xjc.File file = objectFactory.createFile();
|
||||||
file.setName(jsonObject.getString(SwidTagConstants.NAME, ""));
|
file.setName(jsonObject.getString(SwidTagConstants.NAME, ""));
|
||||||
Map<QName, String> attributes = file.getOtherAttributes();
|
Map<QName, String> attributes = file.getOtherAttributes();
|
||||||
@ -454,11 +493,21 @@ public class SwidTagGateway {
|
|||||||
jsonObject.getString(SwidTagConstants.SUPPORT_RIM_URI_GLOBAL, ""));
|
jsonObject.getString(SwidTagConstants.SUPPORT_RIM_URI_GLOBAL, ""));
|
||||||
File rimEventLogFile = new File(rimEventLog);
|
File rimEventLogFile = new File(rimEventLog);
|
||||||
file.setSize(new BigInteger(Long.toString(rimEventLogFile.length())));
|
file.setSize(new BigInteger(Long.toString(rimEventLogFile.length())));
|
||||||
addNonNullAttribute(attributes, SwidTagConstants._SHA256_HASH, HashSwid.get256Hash(rimEventLog));
|
addNonNullAttribute(attributes, SwidTagConstants._SHA256_HASH,
|
||||||
|
jsonObject.getString(SwidTagConstants.HASH,
|
||||||
|
HashSwid.get256Hash(rimEventLog)), true);
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addNonNullAttribute(Map<QName, String> attributes, QName key, String value,
|
||||||
|
boolean required) {
|
||||||
|
if (required && value.isEmpty()) {
|
||||||
|
errorRequiredFields += key.getLocalPart() + ", ";
|
||||||
|
} else {
|
||||||
|
addNonNullAttribute(attributes, key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* This utility method checks if an attribute value is empty before adding it to the map.
|
* This utility method checks if an attribute value is empty before adding it to the map.
|
||||||
*
|
*
|
||||||
@ -466,7 +515,8 @@ public class SwidTagGateway {
|
|||||||
* @param key
|
* @param key
|
||||||
* @param value
|
* @param value
|
||||||
*/
|
*/
|
||||||
private void addNonNullAttribute(Map<QName, String> attributes, QName key, String value) {
|
private void addNonNullAttribute(final Map<QName, String> attributes,
|
||||||
|
final QName key, String value) {
|
||||||
if (!value.isEmpty()) {
|
if (!value.isEmpty()) {
|
||||||
attributes.put(key, value);
|
attributes.put(key, value);
|
||||||
}
|
}
|
||||||
@ -476,7 +526,7 @@ public class SwidTagGateway {
|
|||||||
* This method signs a SoftwareIdentity with an xmldsig in compatibility mode.
|
* This method signs a SoftwareIdentity with an xmldsig in compatibility mode.
|
||||||
* Current assumptions: digest method SHA256, signature method SHA256, enveloped signature
|
* Current assumptions: digest method SHA256, signature method SHA256, enveloped signature
|
||||||
*/
|
*/
|
||||||
private Document signXMLDocument(JAXBElement<SoftwareIdentity> swidTag) {
|
private Document signXMLDocument(JAXBElement<SoftwareIdentity> swidTag) throws Exception {
|
||||||
Document doc = null;
|
Document doc = null;
|
||||||
try {
|
try {
|
||||||
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
|
doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
|
||||||
@ -486,7 +536,8 @@ public class SwidTagGateway {
|
|||||||
Reference documentRef = sigFactory.newReference(
|
Reference documentRef = sigFactory.newReference(
|
||||||
"",
|
"",
|
||||||
sigFactory.newDigestMethod(DigestMethod.SHA256, null),
|
sigFactory.newDigestMethod(DigestMethod.SHA256, null),
|
||||||
Collections.singletonList(sigFactory.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)),
|
Collections.singletonList(sigFactory.newTransform(Transform.ENVELOPED,
|
||||||
|
(TransformParameterSpec) null)),
|
||||||
null,
|
null,
|
||||||
null
|
null
|
||||||
);
|
);
|
||||||
@ -534,11 +585,15 @@ public class SwidTagGateway {
|
|||||||
cp.parsePEMCredentials(pemCertificateFile, pemPrivateKeyFile);
|
cp.parsePEMCredentials(pemCertificateFile, pemPrivateKeyFile);
|
||||||
X509Certificate certificate = cp.getCertificate();
|
X509Certificate certificate = cp.getCertificate();
|
||||||
privateKey = cp.getPrivateKey();
|
privateKey = cp.getPrivateKey();
|
||||||
ArrayList<Object> x509Content = new ArrayList<Object>();
|
if (embeddedCert) {
|
||||||
x509Content.add(certificate.getSubjectX500Principal().getName());
|
ArrayList<Object> x509Content = new ArrayList<Object>();
|
||||||
x509Content.add(certificate);
|
x509Content.add(certificate.getSubjectX500Principal().getName());
|
||||||
X509Data data = kiFactory.newX509Data(x509Content);
|
x509Content.add(certificate);
|
||||||
keyInfoElements.add(data);
|
X509Data data = kiFactory.newX509Data(x509Content);
|
||||||
|
keyInfoElements.add(data);
|
||||||
|
} else {
|
||||||
|
keyInfoElements.add(kiFactory.newKeyValue(certificate.getPublicKey()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
KeyInfo keyinfo = kiFactory.newKeyInfo(keyInfoElements);
|
KeyInfo keyinfo = kiFactory.newKeyInfo(keyInfoElements);
|
||||||
|
|
||||||
@ -564,6 +619,9 @@ public class SwidTagGateway {
|
|||||||
System.out.println("Error marshaling signed swidtag: " + e.getMessage());
|
System.out.println("Error marshaling signed swidtag: " + e.getMessage());
|
||||||
} catch (MarshalException | XMLSignatureException e) {
|
} catch (MarshalException | XMLSignatureException e) {
|
||||||
System.out.println("Error while signing SoftwareIdentity: " + e.getMessage());
|
System.out.println("Error while signing SoftwareIdentity: " + e.getMessage());
|
||||||
|
} catch (KeyException e) {
|
||||||
|
System.out.println("Public key algorithm not recognized or supported: "
|
||||||
|
+ e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
|
@ -4,7 +4,6 @@ import hirs.swid.utils.HashSwid;
|
|||||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Element;
|
import org.w3c.dom.Element;
|
||||||
import org.w3c.dom.Node;
|
|
||||||
import org.w3c.dom.NodeList;
|
import org.w3c.dom.NodeList;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
@ -25,6 +24,7 @@ import javax.xml.crypto.dsig.XMLSignatureException;
|
|||||||
import javax.xml.crypto.dsig.XMLSignatureFactory;
|
import javax.xml.crypto.dsig.XMLSignatureFactory;
|
||||||
import javax.xml.crypto.dsig.dom.DOMValidateContext;
|
import javax.xml.crypto.dsig.dom.DOMValidateContext;
|
||||||
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
|
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
|
||||||
|
import javax.xml.crypto.dsig.keyinfo.KeyValue;
|
||||||
import javax.xml.crypto.dsig.keyinfo.X509Data;
|
import javax.xml.crypto.dsig.keyinfo.X509Data;
|
||||||
import javax.xml.transform.Source;
|
import javax.xml.transform.Source;
|
||||||
import javax.xml.transform.Transformer;
|
import javax.xml.transform.Transformer;
|
||||||
@ -39,10 +39,9 @@ import java.io.File;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
import java.security.KeyFactory;
|
import java.security.KeyException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
@ -51,9 +50,7 @@ import java.security.SignatureException;
|
|||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.security.spec.RSAPublicKeySpec;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -65,6 +62,7 @@ public class SwidTagValidator {
|
|||||||
private String rimEventLog;
|
private String rimEventLog;
|
||||||
private String certificateFile;
|
private String certificateFile;
|
||||||
private String trustStoreFile;
|
private String trustStoreFile;
|
||||||
|
private List<X509Certificate> trustStore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
|
* Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
|
||||||
@ -116,7 +114,12 @@ public class SwidTagValidator {
|
|||||||
si.append("SoftwareIdentity tagId: " + softwareIdentity.getAttribute("tagId") + "\n");
|
si.append("SoftwareIdentity tagId: " + softwareIdentity.getAttribute("tagId") + "\n");
|
||||||
System.out.println(si.toString());
|
System.out.println(si.toString());
|
||||||
Element file = (Element) document.getElementsByTagName("File").item(0);
|
Element file = (Element) document.getElementsByTagName("File").item(0);
|
||||||
validateFile(file);
|
try {
|
||||||
|
validateFile(file);
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println(e.getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
System.out.println("Signature core validity: " + validateSignedXMLDocument(document));
|
System.out.println("Signature core validity: " + validateSignedXMLDocument(document));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -124,7 +127,7 @@ public class SwidTagValidator {
|
|||||||
/**
|
/**
|
||||||
* This method validates a hirs.swid.xjc.File from an indirect payload
|
* This method validates a hirs.swid.xjc.File from an indirect payload
|
||||||
*/
|
*/
|
||||||
private boolean validateFile(Element file) {
|
private boolean validateFile(Element file) throws Exception {
|
||||||
String filepath;
|
String filepath;
|
||||||
if (!rimEventLog.isEmpty()) {
|
if (!rimEventLog.isEmpty()) {
|
||||||
filepath = rimEventLog;
|
filepath = rimEventLog;
|
||||||
@ -158,40 +161,49 @@ public class SwidTagValidator {
|
|||||||
DOMValidateContext context;
|
DOMValidateContext context;
|
||||||
CredentialParser cp = new CredentialParser();
|
CredentialParser cp = new CredentialParser();
|
||||||
X509Certificate signingCert = null;
|
X509Certificate signingCert = null;
|
||||||
List<X509Certificate> trustStore = cp.parseCertsFromPEM(trustStoreFile);
|
trustStore = cp.parseCertsFromPEM(trustStoreFile);
|
||||||
|
X509KeySelector keySelector = new X509KeySelector();
|
||||||
NodeList nodes = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
|
NodeList nodes = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
|
||||||
if (nodes.getLength() == 0) {
|
if (nodes.getLength() == 0) {
|
||||||
throw new Exception("Signature element not found!");
|
throw new Exception("Signature element not found!");
|
||||||
}
|
|
||||||
NodeList embeddedCert = doc.getElementsByTagName("X509Certificate");
|
|
||||||
if (embeddedCert.getLength() > 0) {
|
|
||||||
context = new DOMValidateContext(new X509KeySelector(), nodes.item(0));
|
|
||||||
signingCert = cp.parseCertFromPEMString(embeddedCert.item(0).getTextContent());
|
|
||||||
} else {
|
} else {
|
||||||
String skId = doc.getElementsByTagName("KeyName").item(0).getTextContent();
|
context = new DOMValidateContext(keySelector, nodes.item(0));
|
||||||
for (X509Certificate trustedCert : trustStore) {
|
}
|
||||||
String trustedSkId = cp.getCertificateSubjectKeyIdentifier(trustedCert);
|
NodeList keyName = doc.getElementsByTagName("KeyName");
|
||||||
if (skId.equals(trustedSkId)) {
|
if (keyName.getLength() > 0) {
|
||||||
signingCert = trustedCert;
|
String skId = keyName.item(0).getTextContent();
|
||||||
break;
|
if (skId != null && !skId.isEmpty()) {
|
||||||
|
for (X509Certificate trustedCert : trustStore) {
|
||||||
|
String trustedSkId = cp.getCertificateSubjectKeyIdentifier(trustedCert);
|
||||||
|
if (skId.equals(trustedSkId)) {
|
||||||
|
signingCert = trustedCert;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
if (signingCert != null) {
|
||||||
if (signingCert == null) {
|
context = new DOMValidateContext(signingCert.getPublicKey(),
|
||||||
System.out.println("Issuer certificate with subject key identifier = "
|
nodes.item(0));
|
||||||
+ skId + " not found");
|
} else {
|
||||||
|
System.out.println("Issuer certificate with subject key identifier = "
|
||||||
|
+ skId + " not found");
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
System.out.println("Base RIM must have a non-empty, non-null " +
|
||||||
|
"Subject Key Identifier (SKID) in the <KeyName> element");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
context = new DOMValidateContext(signingCert.getPublicKey(), nodes.item(0));
|
|
||||||
}
|
}
|
||||||
cp.setCertificate(signingCert);
|
|
||||||
System.out.println(cp.getCertificateAuthorityInfoAccess());
|
|
||||||
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
|
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
|
||||||
XMLSignature signature = sigFactory.unmarshalXMLSignature(context);
|
XMLSignature signature = sigFactory.unmarshalXMLSignature(context);
|
||||||
boolean signatureIsValid = signature.validate(context);
|
boolean signatureIsValid = signature.validate(context);
|
||||||
boolean certChainIsValid = validateCertChain(signingCert, trustStore);
|
|
||||||
System.out.println("Signature validity: " + signatureIsValid);
|
System.out.println("Signature validity: " + signatureIsValid);
|
||||||
System.out.println("Cert chain validity: " + certChainIsValid);
|
if (signingCert == null) {
|
||||||
return signatureIsValid && certChainIsValid;
|
signingCert = keySelector.getSigningCert();
|
||||||
|
}
|
||||||
|
cp.setCertificate(signingCert);
|
||||||
|
System.out.println(System.lineSeparator() + cp.getCertificateAuthorityInfoAccess());
|
||||||
|
return signatureIsValid;
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
System.out.println("Error parsing truststore: " + e.getMessage());
|
System.out.println("Error parsing truststore: " + e.getMessage());
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
@ -208,112 +220,21 @@ public class SwidTagValidator {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This method validates the cert chain for a given certificate. The truststore is iterated
|
|
||||||
* over until a root CA is found, otherwise an error is returned.
|
|
||||||
* @param cert the certificate at the start of the chain
|
|
||||||
* @param trustStore from which to find the chain of intermediate and root CAs
|
|
||||||
* @return true if the chain is valid
|
|
||||||
* @throws Exception if a valid chain is not found in the truststore
|
|
||||||
*/
|
|
||||||
private boolean validateCertChain(final X509Certificate cert,
|
|
||||||
final List<X509Certificate> trustStore)
|
|
||||||
throws Exception {
|
|
||||||
if (cert == null || trustStore == null) {
|
|
||||||
throw new Exception("Null certificate or truststore received");
|
|
||||||
} else if (trustStore.size() == 0) {
|
|
||||||
throw new Exception("Truststore is empty");
|
|
||||||
}
|
|
||||||
|
|
||||||
final String INT_CA_ERROR = "Intermediate CA found, searching for root CA";
|
|
||||||
String errorMessage = "";
|
|
||||||
X509Certificate startOfChain = cert;
|
|
||||||
do {
|
|
||||||
for (X509Certificate trustedCert : trustStore) {
|
|
||||||
boolean isIssuer = areYouMyIssuer(startOfChain, trustedCert);
|
|
||||||
boolean isSigner = areYouMySigner(startOfChain, trustedCert);
|
|
||||||
if (isIssuer && isSigner) {
|
|
||||||
if (isSelfSigned(trustedCert)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
startOfChain = trustedCert;
|
|
||||||
errorMessage = INT_CA_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!isIssuer) {
|
|
||||||
errorMessage = "Issuer cert not found";
|
|
||||||
} else if (!isSigner) {
|
|
||||||
errorMessage = "Signing cert not found";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while (errorMessage.equals(INT_CA_ERROR));
|
|
||||||
|
|
||||||
throw new Exception("Error while validating cert chain: " + errorMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method checks if cert's issuerDN matches issuer's subjectDN.
|
|
||||||
* @param cert the signed certificate
|
|
||||||
* @param issuer the signing certificate
|
|
||||||
* @return true if they match, false if not
|
|
||||||
* @throws Exception if either argument is null
|
|
||||||
*/
|
|
||||||
private boolean areYouMyIssuer(final X509Certificate cert, final X509Certificate issuer)
|
|
||||||
throws Exception {
|
|
||||||
if (cert == null || issuer == null) {
|
|
||||||
throw new Exception("Cannot verify issuer, null certificate received");
|
|
||||||
}
|
|
||||||
X500Principal issuerDN = new X500Principal(cert.getIssuerX500Principal().getName());
|
|
||||||
return issuer.getSubjectX500Principal().equals(issuerDN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method checks if cert's signature matches signer's public key.
|
|
||||||
* @param cert the signed certificate
|
|
||||||
* @param signer the signing certificate
|
|
||||||
* @return true if they match
|
|
||||||
* @throws Exception if an error occurs or there is no match
|
|
||||||
*/
|
|
||||||
private boolean areYouMySigner(final X509Certificate cert, final X509Certificate signer)
|
|
||||||
throws Exception {
|
|
||||||
if (cert == null || signer == null) {
|
|
||||||
throw new Exception("Cannot verify signature, null certificate received");
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
cert.verify(signer.getPublicKey(), BouncyCastleProvider.PROVIDER_NAME);
|
|
||||||
return true;
|
|
||||||
} catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new Exception("Signing algorithm in signing cert not supported");
|
|
||||||
} catch (InvalidKeyException e) {
|
|
||||||
throw new Exception("Signing certificate key does not match signature");
|
|
||||||
} catch (NoSuchProviderException e) {
|
|
||||||
throw new Exception("Error with BouncyCastleProvider: " + e.getMessage());
|
|
||||||
} catch (SignatureException e) {
|
|
||||||
String error = "Error with signature: " + e.getMessage()
|
|
||||||
+ System.lineSeparator()
|
|
||||||
+ "Certificate needed for verification is missing: "
|
|
||||||
+ signer.getSubjectX500Principal().getName();
|
|
||||||
throw new Exception(error);
|
|
||||||
} catch (CertificateException e) {
|
|
||||||
throw new Exception("Encoding error: " + e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method checks if a given certificate is self signed or not.
|
|
||||||
* @param cert the cert to check
|
|
||||||
* @return true if self signed, false if not
|
|
||||||
*/
|
|
||||||
private boolean isSelfSigned(final X509Certificate cert) {
|
|
||||||
return cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This internal class handles parsing the public key from a KeyInfo element.
|
* This internal class handles parsing the public key from a KeyInfo element.
|
||||||
*/
|
*/
|
||||||
public class X509KeySelector extends KeySelector {
|
public class X509KeySelector extends KeySelector {
|
||||||
|
PublicKey publicKey;
|
||||||
|
X509Certificate signingCert;
|
||||||
|
|
||||||
|
public PublicKey getPublicKey() {
|
||||||
|
return publicKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public X509Certificate getSigningCert() {
|
||||||
|
return signingCert;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method extracts a public key from either an X509Certificate element
|
* This method extracts a public key from either an X509Certificate element
|
||||||
* or a KeyValue element. If the public key's algorithm matches the declared
|
* or a KeyValue element. If the public key's algorithm matches the declared
|
||||||
@ -339,12 +260,41 @@ public class SwidTagValidator {
|
|||||||
while (dataItr.hasNext()) {
|
while (dataItr.hasNext()) {
|
||||||
Object object = dataItr.next();
|
Object object = dataItr.next();
|
||||||
if (object instanceof X509Certificate) {
|
if (object instanceof X509Certificate) {
|
||||||
final PublicKey publicKey = ((X509Certificate) object).getPublicKey();
|
X509Certificate embeddedCert = (X509Certificate) object;
|
||||||
if (areAlgorithmsEqual(algorithm.getAlgorithm(), publicKey.getAlgorithm())) {
|
try {
|
||||||
return new SwidTagValidator.X509KeySelector.RIMKeySelectorResult(publicKey);
|
if (isCertChainValid(embeddedCert)) {
|
||||||
|
publicKey = ((X509Certificate) embeddedCert).getPublicKey();
|
||||||
|
signingCert = embeddedCert;
|
||||||
|
System.out.println("Certificate chain validity: true");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Certificate chain invalid: "
|
||||||
|
+ e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (element instanceof KeyValue) {
|
||||||
|
try {
|
||||||
|
PublicKey pk = ((KeyValue) element).getPublicKey();
|
||||||
|
if (isPublicKeyTrusted(pk)) {
|
||||||
|
publicKey = pk;
|
||||||
|
try {
|
||||||
|
System.out.println("Certificate chain validity: "
|
||||||
|
+ isCertChainValid(signingCert));
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Certificate chain invalid: "
|
||||||
|
+ e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (KeyException e) {
|
||||||
|
System.out.println("Unable to convert KeyValue data to PK.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (publicKey != null) {
|
||||||
|
if (areAlgorithmsEqual(algorithm.getAlgorithm(), publicKey.getAlgorithm())) {
|
||||||
|
return new
|
||||||
|
SwidTagValidator.X509KeySelector.RIMKeySelectorResult(publicKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new KeySelectorException("No key found!");
|
throw new KeySelectorException("No key found!");
|
||||||
@ -361,6 +311,123 @@ public class SwidTagValidator {
|
|||||||
&& name.equalsIgnoreCase("RSA");
|
&& name.equalsIgnoreCase("RSA");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method validates the cert chain for a given certificate. The truststore is iterated
|
||||||
|
* over until a root CA is found, otherwise an error is returned.
|
||||||
|
* @param cert the certificate at the start of the chain
|
||||||
|
* @return true if the chain is valid
|
||||||
|
* @throws Exception if a valid chain is not found in the truststore
|
||||||
|
*/
|
||||||
|
private boolean isCertChainValid(final X509Certificate cert)
|
||||||
|
throws Exception {
|
||||||
|
if (cert == null || trustStore == null) {
|
||||||
|
throw new Exception("Null certificate or truststore received");
|
||||||
|
} else if (trustStore.size() == 0) {
|
||||||
|
throw new Exception("Truststore is empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String INT_CA_ERROR = "Intermediate CA found, searching for root CA";
|
||||||
|
String errorMessage = "";
|
||||||
|
X509Certificate startOfChain = cert;
|
||||||
|
do {
|
||||||
|
for (X509Certificate trustedCert : trustStore) {
|
||||||
|
boolean isIssuer = areYouMyIssuer(startOfChain, trustedCert);
|
||||||
|
boolean isSigner = areYouMySigner(startOfChain, trustedCert);
|
||||||
|
if (isIssuer && isSigner) {
|
||||||
|
if (isSelfSigned(trustedCert)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
startOfChain = trustedCert;
|
||||||
|
errorMessage = INT_CA_ERROR;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!isIssuer) {
|
||||||
|
errorMessage = "Issuer cert not found";
|
||||||
|
} else if (!isSigner) {
|
||||||
|
errorMessage = "Signing cert not found";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (errorMessage.equals(INT_CA_ERROR));
|
||||||
|
|
||||||
|
throw new Exception("Error while validating cert chain: " + errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks if cert's issuerDN matches issuer's subjectDN.
|
||||||
|
* @param cert the signed certificate
|
||||||
|
* @param issuer the signing certificate
|
||||||
|
* @return true if they match, false if not
|
||||||
|
* @throws Exception if either argument is null
|
||||||
|
*/
|
||||||
|
private boolean areYouMyIssuer(final X509Certificate cert, final X509Certificate issuer)
|
||||||
|
throws Exception {
|
||||||
|
if (cert == null || issuer == null) {
|
||||||
|
throw new Exception("Cannot verify issuer, null certificate received");
|
||||||
|
}
|
||||||
|
X500Principal issuerDN = new X500Principal(cert.getIssuerX500Principal().getName());
|
||||||
|
return issuer.getSubjectX500Principal().equals(issuerDN);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks if cert's signature matches signer's public key.
|
||||||
|
* @param cert the signed certificate
|
||||||
|
* @param signer the signing certificate
|
||||||
|
* @return true if they match
|
||||||
|
* @throws Exception if an error occurs or there is no match
|
||||||
|
*/
|
||||||
|
private boolean areYouMySigner(final X509Certificate cert, final X509Certificate signer)
|
||||||
|
throws Exception {
|
||||||
|
if (cert == null || signer == null) {
|
||||||
|
throw new Exception("Cannot verify signature, null certificate received");
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
cert.verify(signer.getPublicKey(), BouncyCastleProvider.PROVIDER_NAME);
|
||||||
|
return true;
|
||||||
|
} catch (NoSuchAlgorithmException e) {
|
||||||
|
throw new Exception("Signing algorithm in signing cert not supported");
|
||||||
|
} catch (InvalidKeyException e) {
|
||||||
|
throw new Exception("Signing certificate key does not match signature");
|
||||||
|
} catch (NoSuchProviderException e) {
|
||||||
|
throw new Exception("Error with BouncyCastleProvider: " + e.getMessage());
|
||||||
|
} catch (SignatureException e) {
|
||||||
|
String error = "Error with signature: " + e.getMessage()
|
||||||
|
+ System.lineSeparator()
|
||||||
|
+ "Certificate needed for verification is missing: "
|
||||||
|
+ signer.getSubjectX500Principal().getName();
|
||||||
|
throw new Exception(error);
|
||||||
|
} catch (CertificateException e) {
|
||||||
|
throw new Exception("Encoding error: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks if a given certificate is self signed or not.
|
||||||
|
* @param cert the cert to check
|
||||||
|
* @return true if self signed, false if not
|
||||||
|
*/
|
||||||
|
private boolean isSelfSigned(final X509Certificate cert) {
|
||||||
|
return cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method compares a public key against those in the truststore.
|
||||||
|
* @param pk a public key
|
||||||
|
* @return true if pk is found in the trust store, false otherwise
|
||||||
|
*/
|
||||||
|
private boolean isPublicKeyTrusted(final PublicKey pk) {
|
||||||
|
for (X509Certificate trustedCert : trustStore) {
|
||||||
|
if (Arrays.equals(trustedCert.getPublicKey().getEncoded(),
|
||||||
|
pk.getEncoded())) {
|
||||||
|
signingCert = trustedCert;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private class RIMKeySelectorResult implements KeySelectorResult {
|
private class RIMKeySelectorResult implements KeySelectorResult {
|
||||||
private Key key;
|
private Key key;
|
||||||
|
|
||||||
|
@ -36,10 +36,13 @@ public class Commander {
|
|||||||
description = "The public key certificate to embed in the base RIM created by "
|
description = "The public key certificate to embed in the base RIM created by "
|
||||||
+ "this tool.")
|
+ "this tool.")
|
||||||
private String publicCertificate = "";
|
private String publicCertificate = "";
|
||||||
@Parameter(names = {"-d", "--default-key"},
|
@Parameter(names = {"-e", "--embed-cert"}, order = 7,
|
||||||
|
description = "Embed the provided certificate in the signed swidtag.")
|
||||||
|
private boolean embedded = false;
|
||||||
|
@Parameter(names = {"-d", "--default-key"}, order = 8,
|
||||||
description = "Use default signing credentials.")
|
description = "Use default signing credentials.")
|
||||||
private boolean defaultKey = false;
|
private boolean defaultKey = false;
|
||||||
@Parameter(names = {"-l", "--rimel <path>"}, order = 7,
|
@Parameter(names = {"-l", "--rimel <path>"}, order = 9,
|
||||||
description = "The TCG eventlog file to use as a support RIM.")
|
description = "The TCG eventlog file to use as a support RIM.")
|
||||||
private String rimEventLog = "";
|
private String rimEventLog = "";
|
||||||
|
|
||||||
@ -73,6 +76,8 @@ public class Commander {
|
|||||||
return publicCertificate;
|
return publicCertificate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmbedded() { return embedded; }
|
||||||
|
|
||||||
public boolean isDefaultKey() { return defaultKey; }
|
public boolean isDefaultKey() { return defaultKey; }
|
||||||
|
|
||||||
public String getRimEventLog() { return rimEventLog; }
|
public String getRimEventLog() { return rimEventLog; }
|
||||||
@ -82,11 +87,12 @@ public class Commander {
|
|||||||
sb.append("Create a base RIM using the values in attributes.json; " +
|
sb.append("Create a base RIM using the values in attributes.json; " +
|
||||||
"sign it with the default keystore; ");
|
"sign it with the default keystore; ");
|
||||||
sb.append("and write the data to base_rim.swidtag:\n\n");
|
sb.append("and write the data to base_rim.swidtag:\n\n");
|
||||||
sb.append("\t\t-c base -a attributes.json -d -l support_rim.bin -o base_rim.swidtag\n\n\n");
|
sb.append("\t\t-c base -a attributes.json -d -l support_rim.bin -o base_rim.swidtag" +
|
||||||
|
"\n\n\n");
|
||||||
sb.append("Create a base RIM using the default attribute values; ");
|
sb.append("Create a base RIM using the default attribute values; ");
|
||||||
sb.append("sign it using privateKey.pem; embed cert.pem in the signature block; ");
|
sb.append("sign it using privateKey.pem; embed cert.pem in the signature block; ");
|
||||||
sb.append("and write the data to console output:\n\n");
|
sb.append("and write the data to console output:\n\n");
|
||||||
sb.append("\t\t-c base -l support_rim.bin -k privateKey.pem -p cert.pem\n\n\n");
|
sb.append("\t\t-c base -l support_rim.bin -k privateKey.pem -p cert.pem -e\n\n\n");
|
||||||
sb.append("Validate a base RIM using an external support RIM to override the ");
|
sb.append("Validate a base RIM using an external support RIM to override the ");
|
||||||
sb.append("payload file:\n\n");
|
sb.append("payload file:\n\n");
|
||||||
sb.append("\t\t-v base_rim.swidtag -l support_rim.bin\n\n\n");
|
sb.append("\t\t-v base_rim.swidtag -l support_rim.bin\n\n\n");
|
||||||
@ -107,7 +113,9 @@ public class Commander {
|
|||||||
} else if (!this.getPrivateKeyFile().isEmpty() &&
|
} else if (!this.getPrivateKeyFile().isEmpty() &&
|
||||||
!this.getPublicCertificate().isEmpty()) {
|
!this.getPublicCertificate().isEmpty()) {
|
||||||
sb.append("Private key file: " + this.getPrivateKeyFile() + System.lineSeparator());
|
sb.append("Private key file: " + this.getPrivateKeyFile() + System.lineSeparator());
|
||||||
sb.append("Public certificate: " + this.getPublicCertificate() + System.lineSeparator());
|
sb.append("Public certificate: " + this.getPublicCertificate()
|
||||||
|
+ System.lineSeparator());
|
||||||
|
sb.append("Embedded certificate: " + this.isEmbedded() + System.lineSeparator());
|
||||||
} else if (this.isDefaultKey()){
|
} else if (this.isDefaultKey()){
|
||||||
sb.append("Truststore file: default (" + SwidTagConstants.DEFAULT_KEYSTORE_FILE + ")"
|
sb.append("Truststore file: default (" + SwidTagConstants.DEFAULT_KEYSTORE_FILE + ")"
|
||||||
+ System.lineSeparator());
|
+ System.lineSeparator());
|
||||||
|
@ -26,7 +26,7 @@ public class HashSwid {
|
|||||||
* @param filepath the file to hash.
|
* @param filepath the file to hash.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static String get256Hash(String filepath) {
|
public static String get256Hash(String filepath) throws Exception {
|
||||||
return getHashValue(filepath, SHA256);
|
return getHashValue(filepath, SHA256);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,7 +35,7 @@ public class HashSwid {
|
|||||||
* @param filepath the file to hash.
|
* @param filepath the file to hash.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String get384Hash(String filepath) {
|
public String get384Hash(String filepath) throws Exception {
|
||||||
return getHashValue(filepath, SHA384);
|
return getHashValue(filepath, SHA384);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ public class HashSwid {
|
|||||||
* @param filepath the file to hash.
|
* @param filepath the file to hash.
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public String get512Hash(String filepath) {
|
public String get512Hash(String filepath) throws Exception {
|
||||||
return getHashValue(filepath, SHA512);
|
return getHashValue(filepath, SHA512);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ public class HashSwid {
|
|||||||
* @param sha the algorithm to use for the hash
|
* @param sha the algorithm to use for the hash
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
private static String getHashValue(String filepath, String sha) {
|
private static String getHashValue(String filepath, String sha) throws Exception {
|
||||||
String resultString = null;
|
String resultString = null;
|
||||||
try {
|
try {
|
||||||
MessageDigest md = MessageDigest.getInstance(sha);
|
MessageDigest md = MessageDigest.getInstance(sha);
|
||||||
@ -71,10 +71,15 @@ public class HashSwid {
|
|||||||
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
|
sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
|
||||||
}
|
}
|
||||||
resultString = sb.toString();
|
resultString = sb.toString();
|
||||||
} catch (UnsupportedEncodingException | NoSuchAlgorithmException grex) {
|
} catch (NoSuchAlgorithmException | IOException e) {
|
||||||
System.out.println(grex.getMessage());
|
String errorMessage = "Error hashing file " + filepath + ": ";
|
||||||
} catch (IOException e) {
|
if (e instanceof UnsupportedEncodingException ||
|
||||||
System.out.println("Error reading in file to hash: " + e.getMessage());
|
e instanceof NoSuchAlgorithmException) {
|
||||||
|
errorMessage += ((Exception) e).getMessage();
|
||||||
|
} else if (e instanceof IOException) {
|
||||||
|
errorMessage += "error reading file.";
|
||||||
|
}
|
||||||
|
throw new Exception(errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultString;
|
return resultString;
|
||||||
|
@ -14,13 +14,21 @@ public class TestSwidTagGateway {
|
|||||||
private SwidTagGateway gateway;
|
private SwidTagGateway gateway;
|
||||||
private SwidTagValidator validator;
|
private SwidTagValidator validator;
|
||||||
private final String DEFAULT_OUTPUT = "generated_swidTag.swidtag";
|
private final String DEFAULT_OUTPUT = "generated_swidTag.swidtag";
|
||||||
private final String DEFAULT_WITH_CERT = "generated_with_cert.swidtag";
|
private final String BASE_USER_CERT = "generated_user_cert.swidtag";
|
||||||
private final String DEFAULT_NO_CERT = "generated_no_cert.swidtag";
|
private final String BASE_USER_CERT_EMBED = "generated_user_cert_embed.swidtag";
|
||||||
private final String ATTRIBUTES_FILE = TestSwidTagGateway.class.getClassLoader().getResource("rim_fields.json").getPath();
|
private final String BASE_DEFAULT_CERT = "generated_default_cert.swidtag";
|
||||||
private final String JKS_KEYSTORE_FILE = TestSwidTagGateway.class.getClassLoader().getResource("keystore.jks").getPath();
|
private final String ATTRIBUTES_FILE = TestSwidTagGateway.class.getClassLoader()
|
||||||
private final String SIGNING_CERT_FILE = TestSwidTagGateway.class.getClassLoader().getResource("RimSignCert.pem").getPath();
|
.getResource("rim_fields.json").getPath();
|
||||||
private final String PRIVATE_KEY_FILE = TestSwidTagGateway.class.getClassLoader().getResource("privateRimKey.pem").getPath();
|
private final String JKS_KEYSTORE_FILE = TestSwidTagGateway.class.getClassLoader()
|
||||||
private final String SUPPORT_RIM_FILE = TestSwidTagGateway.class.getClassLoader().getResource("TpmLog.bin").getPath();
|
.getResource("keystore.jks").getPath();
|
||||||
|
private final String SIGNING_CERT_FILE = TestSwidTagGateway.class.getClassLoader()
|
||||||
|
.getResource("RimSignCert.pem").getPath();
|
||||||
|
private final String PRIVATE_KEY_FILE = TestSwidTagGateway.class.getClassLoader()
|
||||||
|
.getResource("privateRimKey.pem").getPath();
|
||||||
|
private final String CA_CHAIN_FILE = TestSwidTagGateway.class.getClassLoader()
|
||||||
|
.getResource("RimCertChain.pem").getPath();
|
||||||
|
private final String SUPPORT_RIM_FILE = TestSwidTagGateway.class.getClassLoader()
|
||||||
|
.getResource("TpmLog.bin").getPath();
|
||||||
private InputStream expectedFile;
|
private InputStream expectedFile;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
@ -30,6 +38,7 @@ public class TestSwidTagGateway {
|
|||||||
gateway.setAttributesFile(ATTRIBUTES_FILE);
|
gateway.setAttributesFile(ATTRIBUTES_FILE);
|
||||||
validator = new SwidTagValidator();
|
validator = new SwidTagValidator();
|
||||||
validator.setRimEventLog(SUPPORT_RIM_FILE);
|
validator.setRimEventLog(SUPPORT_RIM_FILE);
|
||||||
|
validator.setTrustStoreFile(CA_CHAIN_FILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
@ -45,13 +54,35 @@ public class TestSwidTagGateway {
|
|||||||
* where RimSignCert.pem has the AIA extension.
|
* where RimSignCert.pem has the AIA extension.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCreateBaseWithCert() {
|
public void testCreateBaseUserCertNotEmbedded() {
|
||||||
gateway.setDefaultCredentials(false);
|
gateway.setDefaultCredentials(false);
|
||||||
gateway.setPemCertificateFile(SIGNING_CERT_FILE);
|
gateway.setPemCertificateFile(SIGNING_CERT_FILE);
|
||||||
gateway.setPemPrivateKeyFile(PRIVATE_KEY_FILE);
|
gateway.setPemPrivateKeyFile(PRIVATE_KEY_FILE);
|
||||||
|
gateway.setEmbeddedCert(false);
|
||||||
gateway.generateSwidTag(DEFAULT_OUTPUT);
|
gateway.generateSwidTag(DEFAULT_OUTPUT);
|
||||||
expectedFile = TestSwidTagGateway.class.getClassLoader().getResourceAsStream(DEFAULT_WITH_CERT);
|
expectedFile = TestSwidTagGateway.class.getClassLoader()
|
||||||
|
.getResourceAsStream(BASE_USER_CERT);
|
||||||
Assert.assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT));
|
Assert.assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT));
|
||||||
|
Assert.assertTrue(validator.validateSwidTag(DEFAULT_OUTPUT));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test creates the following base RIM:
|
||||||
|
* -c base -l TpmLog.bin -k privateRimKey.pem -p RimSignCert.pem -e
|
||||||
|
* And then validates it:
|
||||||
|
* -v [base RIM] -l TpmLog.bin -t RimCertChain.pem
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCreateBaseUserCertEmbedded() {
|
||||||
|
gateway.setDefaultCredentials(false);
|
||||||
|
gateway.setPemCertificateFile(SIGNING_CERT_FILE);
|
||||||
|
gateway.setPemPrivateKeyFile(PRIVATE_KEY_FILE);
|
||||||
|
gateway.setEmbeddedCert(true);
|
||||||
|
gateway.generateSwidTag(DEFAULT_OUTPUT);
|
||||||
|
expectedFile = TestSwidTagGateway.class.getClassLoader()
|
||||||
|
.getResourceAsStream(BASE_USER_CERT_EMBED);
|
||||||
|
Assert.assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT));
|
||||||
|
Assert.assertTrue(validator.validateSwidTag(DEFAULT_OUTPUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,21 +90,24 @@ public class TestSwidTagGateway {
|
|||||||
* -c base -l TpmLog.bin
|
* -c base -l TpmLog.bin
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCreateBaseWithoutCert() {
|
public void testCreateBaseDefaultCert() {
|
||||||
gateway.setDefaultCredentials(true);
|
gateway.setDefaultCredentials(true);
|
||||||
gateway.setJksTruststoreFile(JKS_KEYSTORE_FILE);
|
gateway.setJksTruststoreFile(JKS_KEYSTORE_FILE);
|
||||||
gateway.generateSwidTag(DEFAULT_OUTPUT);
|
gateway.generateSwidTag(DEFAULT_OUTPUT);
|
||||||
expectedFile = TestSwidTagGateway.class.getClassLoader().getResourceAsStream(DEFAULT_NO_CERT);
|
expectedFile = TestSwidTagGateway.class.getClassLoader()
|
||||||
|
.getResourceAsStream(BASE_DEFAULT_CERT);
|
||||||
Assert.assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT));
|
Assert.assertTrue(compareFileBytesToExpectedFile(DEFAULT_OUTPUT));
|
||||||
|
Assert.assertTrue(validator.validateSwidTag(DEFAULT_OUTPUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test corresponds to the arguments:
|
* This test corresponds to the arguments:
|
||||||
* -v <path>
|
* -v <path>
|
||||||
*/
|
*/
|
||||||
@Test
|
|
||||||
public void testValidateSwidTag() {
|
public void testValidateSwidTag() {
|
||||||
String filepath = TestSwidTagGateway.class.getClassLoader().getResource(DEFAULT_WITH_CERT).getPath();
|
String filepath = TestSwidTagGateway.class.getClassLoader()
|
||||||
|
.getResource(BASE_USER_CERT).getPath();
|
||||||
System.out.println("Validating file at " + filepath);
|
System.out.println("Validating file at " + filepath);
|
||||||
Assert.assertTrue(validator.validateSwidTag(filepath));
|
Assert.assertTrue(validator.validateSwidTag(filepath));
|
||||||
}
|
}
|
||||||
|
43
tools/tcg_rim_tool/src/test/resources/RimCertChain.pem
Normal file
43
tools/tcg_rim_tool/src/test/resources/RimCertChain.pem
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDjDCCAnSgAwIBAgIJALEA1Q472tZoMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNV
|
||||||
|
BAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UECgwHRXhhbXBsZTERMA8GA1UECwwI
|
||||||
|
UENDbGllbnQxEjAQBgNVBAMMCUV4YW1wbGVDQTAeFw0yMDAyMTAxNzI2MDdaFw0y
|
||||||
|
OTEyMTkxNzI2MDdaMFMxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UE
|
||||||
|
CgwHRXhhbXBsZTERMA8GA1UECwwIUENDbGllbnQxEjAQBgNVBAMMCUV4YW1wbGVD
|
||||||
|
QTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPN0k+ULqFxdHZ14CCio
|
||||||
|
HAvn56T1Ca4t3ClmZoHSAiKsqzLV+rErk5SbMTIdi0vHQ+3sPYf9Opy0EeUXzh4J
|
||||||
|
g6CeGdDn247has1k135KBD9iJCaErJfZPnJ22CjKey8rvJM8fH3CAR7M/5uwYcPH
|
||||||
|
yRICwGAJMA/Qss4nsMRQpfZg4ReKVW+kAoa9eekG3q1sLu/QlCb0NC766X0ANP+8
|
||||||
|
AuGuHJmNV22fjvwSNfWbsJElcMrLbK4kliPyy05YVs19p+cBM1ADxGw2fJqsNsUy
|
||||||
|
34SXL1ATqOp7VCslRR5TJBzhxfM56xZbszry7BaqTSFDRGn1FuMw/4+qtPMAB88u
|
||||||
|
eXECAwEAAaNjMGEwHQYDVR0OBBYEFEahuO3bpnFf0NLneoo8XW6aw5Y4MB8GA1Ud
|
||||||
|
IwQYMBaAFEahuO3bpnFf0NLneoo8XW6aw5Y4MA8GA1UdEwEB/wQFMAMBAf8wDgYD
|
||||||
|
VR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IBAQCwCUSV6VjOR+v85z18q5UX
|
||||||
|
bla0gEsfbc2mx0kGtNqi2im2Xt8UoSJDnfMXzfQq3IP3en943mqgIeYUl3f9UQBT
|
||||||
|
KgGfyHNbEfa0FzqfKpxJdT37C9ilSQ85GtThffc4I50QgBHaRXOvwBdrGpU2O11V
|
||||||
|
x35VLyYoycIlg+CizVywEX53aoMil1hEbv0TPtbNnFZGwM/fxvere65GeQld9gEP
|
||||||
|
9krGtSXYlMktvr66cqPzmG0ciA6dMBZN8dpTgUopmYNz8HVoHDq/KBmXYA7CMzrX
|
||||||
|
pVNx4kMW/KxA+XAHT82xE7PCiLIJx4z9uPn0O4PBDw0tQ0mxuDpeoi1i9PuBfe6Y
|
||||||
|
-----END CERTIFICATE-----
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDoTCCAomgAwIBAgIJAIKly+6bklZlMA0GCSqGSIb3DQEBCwUAMFMxCzAJBgNV
|
||||||
|
BAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UECgwHRXhhbXBsZTERMA8GA1UECwwI
|
||||||
|
UENDbGllbnQxEjAQBgNVBAMMCUV4YW1wbGVDQTAeFw0yMDA2MTExNjUzMDFaFw0z
|
||||||
|
MDA0MjAxNjUzMDFaMFwxCzAJBgNVBAYTAlVTMQswCQYDVQQIDAJWQTEQMA4GA1UE
|
||||||
|
CgwHRXhhbXBsZTERMA8GA1UECwwIUENDbGllbnQxGzAZBgNVBAMMEmV4YW1wbGUu
|
||||||
|
UklNLnNpZ25lcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKd1lWGk
|
||||||
|
SRuxAAY2wHag2GVxUk1dZx2PTpfQOflvLeccAVwa8mQhlsRERq+QK8ilj8Xfqs44
|
||||||
|
/nBaccZDOjdfIxIUCMfwhGXjxCaqZbgTucNsExDnu4arTGraoAwzHg0cVLiKT/Cx
|
||||||
|
j9NL4dcMgxRXsPdHfXb0923C7xYd2t2qfW05umgaj7qeQl6c68CFNsGX4JA8rWFQ
|
||||||
|
ZvvGx5DGlK4KTcjPuQQINs5fxasNKqLY2hq+z82x/rqwr2hmyizD6FpFSyIABPEM
|
||||||
|
PfB036GEhRwu1WEMkq8yIp2jgRUoFYke9pB3ph9pVow0Hh4mNFSKD4pP41VSKY1n
|
||||||
|
us83mdkuukPy5o0CAwEAAaNvMG0wHQYDVR0OBBYEFC/euOfQMKIgnaoBhhqWT+3s
|
||||||
|
8rzBMB8GA1UdIwQYMBaAFEahuO3bpnFf0NLneoo8XW6aw5Y4MAkGA1UdEwQCMAAw
|
||||||
|
CwYDVR0PBAQDAgbAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUA
|
||||||
|
A4IBAQC1mG0naE0W4E9vujPhygf7LXHMFkMPs5uWyvkxe4zWgTg0RHTClbOFJQJ+
|
||||||
|
pGLOcthSG6vIC6xYJxT5EKtB9rzRlEYHOi4MxuwXz9rLWQhA2zdbSo54Fb/BPoca
|
||||||
|
5K9kxvAanRltEfqEFhCcRmqIX1i6mpOWiZsrdMs7IflHKBsylUTn+v636BAz3p2H
|
||||||
|
8/lpJbF4LUFUxFU5FWB3tLuasxYTsbeE6YyNAnQIS95ML7c5H8z2aEQs5TCNHZJD
|
||||||
|
yc0PZT2aPOuEj5lGv9oyBHbYDitszUWSVxF7z86uVGmYR/2oTIj6tqb+IwuvFtnO
|
||||||
|
wiXFRS5ctLCdESr3SjdQF5wmIN4n
|
||||||
|
-----END CERTIFICATE-----
|
@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<SoftwareIdentity xmlns="http://standards.iso.org/iso/19770/-2/2015/schema.xsd" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#" corpus="false" name="Example.com BIOS" patch="false" supplemental="false" tagId="94f6b457-9ac9-4d35-9b3f-78804173b65as" tagVersion="0" version="01" versionScheme="multipartnumeric" xml:lang="en">
|
||||||
|
<Entity name="Example Inc" regid="http://Example.com" role="softwareCreator tagCreator"/>
|
||||||
|
<Link href="https://Example.com/support/ProductA/firmware/installfiles" rel="installationmedia"/>
|
||||||
|
<Meta xmlns:n8060="http://csrc.nist.gov/ns/swid/2015-extensions/1.0" xmlns:rim="https://trustedcomputinggroup.org/wp-content/uploads/TCG_RIM_Model" n8060:colloquialVersion="Firmware_2019" n8060:edition="12" n8060:product="ProductA" n8060:revision="r2" rim:BindingSpec="PC Client RIM" rim:BindingSpecVersion="1.2" rim:PayloadType="direct" rim:firmwareManufacturerId="00213022" rim:firmwareManufacturerStr="BIOSVendorA" rim:firmwareModel="A0" rim:firmwareVersion="12" rim:pcURIGlobal="https://Example.com/support/ProductA/" rim:pcURILocal="/boot/tcg/manifest/switag/" rim:platformManufacturerId="00201234" rim:platformManufacturerStr="Example.com" rim:platformModel="ProductA" rim:platformVersion="01"/>
|
||||||
|
<Payload>
|
||||||
|
<Directory name="rim">
|
||||||
|
<File xmlns:SHA256="http://www.w3.org/2001/04/xmlenc#sha256" SHA256:hash="4479ca722623f8c47b703996ced3cbd981b06b1ae8a897db70137e0b7c546848" name="Example.com.BIOS.01.rimel" size="7549"/>
|
||||||
|
</Directory>
|
||||||
|
</Payload>
|
||||||
|
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
|
||||||
|
<SignedInfo>
|
||||||
|
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
|
||||||
|
<SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||||
|
<Reference URI="">
|
||||||
|
<Transforms>
|
||||||
|
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||||
|
</Transforms>
|
||||||
|
<DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||||
|
<DigestValue>K3XoBeYvgJBAKl8z273sL7z38qLLVBKLfUPt/gPUzBI=</DigestValue>
|
||||||
|
</Reference>
|
||||||
|
</SignedInfo>
|
||||||
|
<SignatureValue>cIl1gPsUyEj2gDv3HTWNFDVxtcBjz4Revxxf2LJejtOXQW8mGepZH8CnvgO7zCAbZYlYUZXjYZ9M
|
||||||
|
jONVv8dcsAjVHRnP6YHywFfmSm8LUCwxsfuZQqn5jClqzu5VaqLzBhuJYvCpiEdIDJwDINQuORUB
|
||||||
|
nzul1CWc3Sm1Ms2wjlIq5ctWWJcddhdyIOjl8/oD4EC5E2rOSfNcRMZxldXtie9iinFGVbr0YNE+
|
||||||
|
+lQ7hAU+SyV8RMx9tGnnsO8otwV4ddF+OfemcbzWGYBenLs3A8ZqWZyTvWphCgGqDUbOLssYciCC
|
||||||
|
mnYm5QOeh4QcE9H2kqTgZvcyCgPL/hDC7xhyjQ==</SignatureValue>
|
||||||
|
<KeyInfo>
|
||||||
|
<KeyValue>
|
||||||
|
<RSAKeyValue>
|
||||||
|
<Modulus>p3WVYaRJG7EABjbAdqDYZXFSTV1nHY9Ol9A5+W8t5xwBXBryZCGWxERGr5AryKWPxd+qzjj+cFpx
|
||||||
|
xkM6N18jEhQIx/CEZePEJqpluBO5w2wTEOe7hqtMatqgDDMeDRxUuIpP8LGP00vh1wyDFFew90d9
|
||||||
|
dvT3bcLvFh3a3ap9bTm6aBqPup5CXpzrwIU2wZfgkDytYVBm+8bHkMaUrgpNyM+5BAg2zl/Fqw0q
|
||||||
|
otjaGr7PzbH+urCvaGbKLMPoWkVLIgAE8Qw98HTfoYSFHC7VYQySrzIinaOBFSgViR72kHemH2lW
|
||||||
|
jDQeHiY0VIoPik/jVVIpjWe6zzeZ2S66Q/LmjQ==</Modulus>
|
||||||
|
<Exponent>AQAB</Exponent>
|
||||||
|
</RSAKeyValue>
|
||||||
|
</KeyValue>
|
||||||
|
</KeyInfo>
|
||||||
|
</Signature>
|
||||||
|
</SoftwareIdentity>
|
Loading…
Reference in New Issue
Block a user