diff --git a/HIRS_Provisioner/scripts/install/hirs-provisioner.sh b/HIRS_Provisioner/scripts/install/hirs-provisioner.sh index 5ceeb4bb..85d92c81 100755 --- a/HIRS_Provisioner/scripts/install/hirs-provisioner.sh +++ b/HIRS_Provisioner/scripts/install/hirs-provisioner.sh @@ -9,6 +9,7 @@ CERTS_DIR="/etc/hirs/provisioner/certs/" HIRS_SITE_CONFIG="/etc/hirs/hirs-site.config" HIRS_PROVISIONER_CONFIG="/etc/hirs/provisioner/hirs-provisioner-config.sh" HIRS_PROVISIONER_SCRIPT="/usr/share/hirs/provisioner/bin/HIRS_Provisioner" +HIRS_PROVISIONER_2_0_SCRIPT="/usr/local/bin/hirs-provisioner-tpm2" HIRS_PROVISIONER_PROPERTIES="/etc/hirs/provisioner/provisioner.properties" if [ "$EUID" != "0" ]; then @@ -105,10 +106,16 @@ function CheckProvisionPrereqsAndDoProvisioning { function Provision { # Provisioner will only retain one {uuid}.cer credential; remove any existing *.cer files. - echo "----> Removing old provisioner scripts, if any" - rm -f $CERTS_DIR/*.cer + echo "----> Removing old attestation credentials, if any" + rm -f $CERTS_DIR/*.cer /etc/hirs/ak.cer echo "----> Provisioning TPM" - $HIRS_PROVISIONER_SCRIPT $CLIENT_HOSTNAME || { echo "----> Failed to provision TPM"; exit 1; } + + if [ -f $HIRS_PROVISIONER_2_0_SCRIPT ] + then + $HIRS_PROVISIONER_2_0_SCRIPT provision || { echo "----> Failed to provision TPM 2.0"; exit 1; } + else + $HIRS_PROVISIONER_SCRIPT $CLIENT_HOSTNAME || { echo "----> Failed to provision TPM"; exit 1; } + fi } diff --git a/HIRS_ProvisionerTPM2/CMakeLists.txt b/HIRS_ProvisionerTPM2/CMakeLists.txt index ea832991..e02cfff6 100644 --- a/HIRS_ProvisionerTPM2/CMakeLists.txt +++ b/HIRS_ProvisionerTPM2/CMakeLists.txt @@ -140,11 +140,11 @@ list(APPEND REQUIRED_LIBS ${PROTOBUF_LIBRARY}) # Define the TPM 2.0 Provisioner Library add_subdirectory(src) -# Set Project Header/Source files -set(EXECUTABLE_SOURCE_FILES src/TPM2_Provisioner.cpp) - # Create project executable -add_executable(${PROJECT_NAME} ${EXECUTABLE_SOURCE_FILES} ${PROJECT_CONFIG_FILES}) +add_executable(${PROJECT_NAME} src/TPM2_Provisioner.cpp ${PROJECT_CONFIG_FILES}) + +# In TPM 2.0 land, there is currently not a way to fetch the TPM version info +add_executable(tpm_version src/tpm_version.cpp) # Link necessary libraries target_link_libraries(${PROJECT_NAME} TPM2_PROVISIONER_LIBRARY) @@ -159,13 +159,25 @@ if(CMAKE_THREAD_LIBS_INIT) endif() # Set commands for installation of project on target system (i.e. "make install") -install(TARGETS ${PROJECT_NAME} +install(TARGETS ${PROJECT_NAME} tpm_version DESTINATION "bin") install(FILES config/log4cplus_config.ini DESTINATION /etc/hirs/TPM2_Provisioner) install(FILES scripts/tpm_aca_provision DESTINATION /usr/local/bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) install(DIRECTORY DESTINATION ${/var/log/hirs/provisioner} DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + +install(DIRECTORY DESTINATION ${/etc/hirs/provisioner} + DIRECTORY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ + GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(FILES ../HIRS_Provisioner/src/main/resources/defaults.properties DESTINATION /etc/hirs/provisioner RENAME provisioner.properties) +install(FILES ../HIRS_Provisioner/hirs-provisioner-config.sh DESTINATION /etc/hirs/provisioner + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ + GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) +install(FILES ../HIRS_Provisioner/scripts/install/hirs-provisioner.sh DESTINATION /etc/hirs/provisioner + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ + GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) + execute_process(COMMAND cp ../HIRS_Utils/src/main/resources/logging.properties ./config/ RESULT_VARIABLE result WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) diff --git a/HIRS_ProvisionerTPM2/package/postinst b/HIRS_ProvisionerTPM2/package/postinst index bb337ab8..dd6cf38e 100644 --- a/HIRS_ProvisionerTPM2/package/postinst +++ b/HIRS_ProvisionerTPM2/package/postinst @@ -1,8 +1,10 @@ HIRS_SITE_CONFIG="/etc/hirs/hirs-site.config" mkdir -p /var/log/hirs/provisioner +mkdir -p /etc/hirs/provisioner/certs ln -s -f /usr/local/bin/hirs-provisioner-tpm2 /usr/sbin/hirs-provisioner-tpm2 ln -s -f /usr/local/bin/tpm_aca_provision /usr/sbin/tpm_aca_provision +ln -s -f /usr/local/bin/tpm_version /usr/sbin/tpm_version if [ ! -f $HIRS_SITE_CONFIG ]; then # Create template site config if it does not exist @@ -29,3 +31,4 @@ DEFAULT_SITE_CONFIG_FILE echo "$HIRS_SITE_CONFIG not found - a template has been created" echo "Set your site configuration manually in $HIRS_SITE_CONFIG, then run 'hirs-provisioner-tpm2 provision' to provision this system" fi +ln -s -f /etc/hirs/provisioner/hirs-provisioner.sh /usr/sbin/hirs-provisioner diff --git a/HIRS_ProvisionerTPM2/package/rpm-post-install.sh b/HIRS_ProvisionerTPM2/package/rpm-post-install.sh index bafa3692..fae761b6 100644 --- a/HIRS_ProvisionerTPM2/package/rpm-post-install.sh +++ b/HIRS_ProvisionerTPM2/package/rpm-post-install.sh @@ -8,8 +8,10 @@ fi HIRS_SITE_CONFIG="/etc/hirs/hirs-site.config" mkdir -p /var/log/hirs/provisioner +mkdir -p /etc/hirs/provisioner/certs ln -s -f /usr/local/bin/hirs-provisioner-tpm2 /usr/sbin/hirs-provisioner-tpm2 ln -s -f /usr/local/bin/tpm_aca_provision /usr/sbin/tpm_aca_provision +ln -s -f /usr/local/bin/tpm_version /usr/sbin/tpm_version if [ ! -f $HIRS_SITE_CONFIG ]; then # Create template site config if it does not exist @@ -36,3 +38,4 @@ DEFAULT_SITE_CONFIG_FILE echo "$HIRS_SITE_CONFIG not found - a template has been created" echo "Set your site configuration manually in $HIRS_SITE_CONFIG, then run 'hirs-provisioner-tpm2 provision' to provision this system" fi +ln -s -f /etc/hirs/provisioner/hirs-provisioner.sh /usr/sbin/hirs-provisioner diff --git a/HIRS_ProvisionerTPM2/src/tpm_version.cpp b/HIRS_ProvisionerTPM2/src/tpm_version.cpp new file mode 100644 index 00000000..38005daa --- /dev/null +++ b/HIRS_ProvisionerTPM2/src/tpm_version.cpp @@ -0,0 +1,11 @@ +#include + +using std::cout; +using std::endl; + +int main(void) { + cout << "Chip Version: 2.0.0.0" << endl; + cout << "TPM Vendor ID: UNKN" << endl; + return 0; +} + diff --git a/HIRS_Utils/src/main/java/hirs/data/persist/TPMMeasurementRecord.java b/HIRS_Utils/src/main/java/hirs/data/persist/TPMMeasurementRecord.java index 0a841d65..468bbca5 100644 --- a/HIRS_Utils/src/main/java/hirs/data/persist/TPMMeasurementRecord.java +++ b/HIRS_Utils/src/main/java/hirs/data/persist/TPMMeasurementRecord.java @@ -61,9 +61,6 @@ public final class TPMMeasurementRecord extends ExaminableRecord { LOGGER.error("null hash value"); throw new NullPointerException("hash"); } - if (hash.getAlgorithm() != DigestAlgorithm.SHA1) { - throw new IllegalArgumentException("hash algorithm is not SHA-1"); - } this.pcrId = pcrId; this.hash = hash; diff --git a/HIRS_Utils/src/main/java/hirs/data/persist/tpm/PcrInfoShort.java b/HIRS_Utils/src/main/java/hirs/data/persist/tpm/PcrInfoShort.java index 5b72c9c6..5f4d4a42 100644 --- a/HIRS_Utils/src/main/java/hirs/data/persist/tpm/PcrInfoShort.java +++ b/HIRS_Utils/src/main/java/hirs/data/persist/tpm/PcrInfoShort.java @@ -1,5 +1,7 @@ package hirs.data.persist.tpm; +import hirs.data.persist.Digest; +import hirs.data.persist.DigestAlgorithm; import hirs.data.persist.TPMMeasurementRecord; import javax.persistence.AttributeOverride; @@ -21,6 +23,8 @@ import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.Iterator; +import java.util.List; /** * Java class for PcrInfoShort complex type, which was modified from code @@ -200,16 +204,31 @@ public class PcrInfoShort { } /** - * Calculates the digest of the PCR values the same way a TPM computes the digest contained in - * the quote. Useful for TPM appraisal and for ensuring the digest of the collected PCR values - * match the digest in the quote. + * Calculates the SHA-1 or SHA-256 digest of the PCR values the same way a TPM computes the + * digest contained in the quote. Useful for TPM appraisal and for ensuring the digest of the + * collected PCR values match the digest in the quote. * * @return byte array containing the digest * @throws NoSuchAlgorithmException - * if MessageDigest doesn't recognize "SHA-1" + * if MessageDigest doesn't recognize "SHA-1" or "SHA-256" */ public final byte[] getCalculatedDigest() throws NoSuchAlgorithmException { - MessageDigest messageDigest = MessageDigest.getInstance("SHA-1"); + if (this.isTpm1()) { + return getCalculatedDigestTpmV1p2(MessageDigest.getInstance("SHA-1")); + } else { + return getCalculatedDigestTpmV2p0(MessageDigest.getInstance("SHA-256")); + } + } + + /** + * Calculates the SHA-1 digest of the PCR values the same way a TPM computes the digest + * contained in the quote. Useful for TPM appraisal and for ensuring the digest of the + * collected PCR values match the digest in the quote. + * + * @param messageDigest message digest algorithm to use + * @return byte array containing the digest + */ + private byte[] getCalculatedDigestTpmV1p2(final MessageDigest messageDigest) { byte[] computedDigest; final int sizeOfInt = 4; @@ -235,6 +254,32 @@ public class PcrInfoShort { return computedDigest; } + /** + * Calculates the digest of the PCR values the same way a TPM computes the digest contained in + * the quote. Useful for TPM appraisal and for ensuring the digest of the collected PCR values + * match the digest in the quote. + * + * @param messageDigest message digest algorithm to use + * @return byte array containing the digest + */ + private byte[] getCalculatedDigestTpmV2p0(final MessageDigest messageDigest) { + int sizeOfByteBuffer = pcrComposite.getValueSize(); + ByteBuffer byteBuffer = ByteBuffer.allocate(sizeOfByteBuffer); + LOGGER.debug("Size of the buffer allocated to hash: {}", sizeOfByteBuffer); + Iterator iter = pcrComposite.getPcrValueList().iterator(); + + while (iter.hasNext()) { + TPMMeasurementRecord record = (TPMMeasurementRecord) iter.next(); + byteBuffer.put(record.getHash().getDigest()); + } + + LOGGER.debug("PCR composite buffer to be hashed: {}", + Hex.encodeHexString(byteBuffer.array())); + byte[] computedDigest = messageDigest.digest(byteBuffer.array()); + LOGGER.debug("Calculated digest: {}", Hex.encodeHexString(computedDigest)); + return computedDigest; + } + /** * Returns the value of PcrInfoShort flattened into a byte array. The array contains the value * of PCR selection, the locality at release, and the composite hash. @@ -250,4 +295,22 @@ public class PcrInfoShort { return byteBuffer.array(); } + + /** + * Determines whether the TPM used to generate this pcr info is version 1.2 or not. + * + * @return whether the TPM used to generate this pcr info is version 1.2 or not + */ + public boolean isTpm1() { + // need to get an individual PCR and measure length to determine SHA1 v SHA 256 + List pcrs = this.getPcrComposite().getPcrValueList(); + if (pcrs.size() == 0) { + // it's the case of an empty pcrmask, so it doesn't matter + return false; + } + + Digest hash = pcrs.get(0).getHash(); + // check if the hash algorithm is SHA 1, if so it's TPM 1.2, if not it's TPM 2.0 + return hash.getAlgorithm() == DigestAlgorithm.SHA1; + } } diff --git a/HIRS_Utils/src/main/java/hirs/data/persist/tpm/QuoteSignature.java b/HIRS_Utils/src/main/java/hirs/data/persist/tpm/QuoteSignature.java index 469c9b5f..408f8703 100644 --- a/HIRS_Utils/src/main/java/hirs/data/persist/tpm/QuoteSignature.java +++ b/HIRS_Utils/src/main/java/hirs/data/persist/tpm/QuoteSignature.java @@ -52,11 +52,15 @@ import java.util.Arrays; name = "QuoteSignature", namespace = "http://www.trustedcomputinggroup.org/XML/SCHEMA/" + "Integrity_Report_v1_0#", - propOrder = {"signatureValue" }) + propOrder = {"rawQuote", "signatureValue" }) @Embeddable public class QuoteSignature { private static final int SIGNATURE_LENGTH = 10000; + @XmlElement(name = "RawQuote", required = false) + @Column(length = SIGNATURE_LENGTH) + private final byte[] rawQuote; + @XmlElement(name = "SignatureValue", required = true) @Column(length = SIGNATURE_LENGTH) private final byte[] signatureValue; @@ -65,6 +69,7 @@ public class QuoteSignature { * Default constructor necessary for marshalling/unmarshalling xml. */ protected QuoteSignature() { + this.rawQuote = new byte[0]; this.signatureValue = new byte[0]; } @@ -76,6 +81,23 @@ public class QuoteSignature { * SignatureValue that contains the Quote2 signature, may be null */ public QuoteSignature(final byte[] signatureValue) { + this(signatureValue, null); + } + /** + * Constructor used to create a QuoteSignature. The signature value may be + * null. + * + * @param signatureValue + * SignatureValue that contains the Quote2 signature, may be null + * @param rawQuote + * Value that was signed, may be null + */ + public QuoteSignature(final byte[] signatureValue, final byte[] rawQuote) { + if (rawQuote == null) { + this.rawQuote = null; + } else { + this.rawQuote = rawQuote.clone(); + } if (signatureValue == null) { this.signatureValue = null; } else { @@ -90,11 +112,24 @@ public class QuoteSignature { * */ public final byte[] getSignatureValue() { - if (signatureValue == null) { - return null; - } else { + if (signatureValue != null) { return signatureValue.clone(); } + + return null; + } + + /** + * Gets the value of the rawQuote property. + * + * @return possible object is a byte array containing the raw quote value, may return null + * + */ + public byte[] getRawQuote() { + if (rawQuote != null) { + return rawQuote.clone(); + } + return null; } @Override