Merge branch 'main' into v3_issue_847-update-hirs_attestationca-caportal-for-checkstyle2

This commit is contained in:
TheSilentCoder 2024-10-21 11:39:28 -04:00
commit 99188f17c1
47 changed files with 1569 additions and 1472 deletions

View File

@ -12,6 +12,7 @@ services:
hat:
image: ghcr.io/nsacyber/hirs/hat
container_name: hat
privileged: true
ports:
- 53:53/tcp
- 53:53/udp

View File

@ -23,14 +23,16 @@ import java.util.Properties;
public class BannerConfiguration {
private static final Path BANNER_PROPERTIES_PATH = FileSystems.getDefault()
.getPath("/opt/tomcat/webapps/HIRS_AttestationCAPortal", "WEB-INF", "classes", "banner.properties");
.getPath("/opt/tomcat/webapps/HIRS_AttestationCAPortal",
"WEB-INF", "classes", "banner.properties");
private static final String BANNER_COLOR = "banner.color";
private static final String BANNER_STRING = "banner.string";
private static final String BANNER_DYNAMIC = "banner.dynamic";
private static final String LEFT_CONTENT = "left.content";
private static final String RIGHT_CONTENT = "right.content";
private final ArrayList<String> leftContent = new ArrayList<>();
private final ArrayList<String> rightContent = new ArrayList<>();
@Getter
private String bannerColor = "";
@Getter
@ -38,21 +40,18 @@ public class BannerConfiguration {
@Getter
private String bannerDynamic = "";
private final ArrayList<String> leftContent = new ArrayList<>();
private final ArrayList<String> rightContent = new ArrayList<>();
/**
* Banner Configuration default constructor.
* Verify if the file exist, if it does it will get all the
* properties values and save them on the class.
*
* @throws IOException the banner level for the web site.
* @throws IOException the banner level for the website.
*/
public BannerConfiguration() throws IOException {
if (!Files.exists(BANNER_PROPERTIES_PATH)) {
log.info(String.format(
"No file found at %s. Banner will not display.",
BANNER_PROPERTIES_PATH.toString()
BANNER_PROPERTIES_PATH
));
return;
}
@ -69,8 +68,8 @@ public class BannerConfiguration {
/**
* This method applies any dynamically configuration found in the properties file,
* if it exists.
* @param bannerProps
* @return the banner level for the web site.
*
* @param bannerProps banner props
*/
private void setBannerProperties(final Properties bannerProps) {
@ -103,10 +102,7 @@ public class BannerConfiguration {
* @return if the banner was set.
*/
public Boolean getHasBanner() {
if (!bannerColor.isEmpty() || !bannerString.isEmpty()) {
return true;
}
return false;
return !bannerColor.isEmpty() || !bannerString.isEmpty();
}
/**

View File

@ -7,22 +7,24 @@ import java.math.BigInteger;
*/
public final class HexUtils {
/**
* Default private constructor so checkstyles doesn't complain
*/
private HexUtils() { }
/**
* The mathematical base for the hexadecimal representation.
*/
public static final int HEX_BASIS = 16;
/**
* An integer representation of the byte 0xff or 255.
*/
public static final int FF_BYTE = 0xff;
/**
* Default private constructor so checkstyles doesn't complain.
*/
private HexUtils() {
}
/**
* Converts a binary hex string to a byte array.
*
* @param s string to convert
* @return byte array representation of s
*/
@ -40,6 +42,7 @@ public final class HexUtils {
/**
* Converts a byte array to a hex represented binary string.
*
* @param b byte array to convert
* @return hex string representation of array
*/
@ -58,6 +61,7 @@ public final class HexUtils {
/**
* Converts an individual hex string to an integer.
*
* @param s an individual hex string
* @return an integer representation of a hex string
*/
@ -68,6 +72,7 @@ public final class HexUtils {
/**
* Takes a byte array returns a subset of the array.
*
* @param b the array to take a subset of
* @param start the first index to copy
* @param end the last index to copy (inclusive)
@ -81,6 +86,7 @@ public final class HexUtils {
/**
* Takes in a byte array and reverses the order.
*
* @param in byte array to reverse
* @return reversed byte array
*/
@ -94,6 +100,7 @@ public final class HexUtils {
/**
* Takes in a byte array and reverses the order then converts to an int.
*
* @param in byte array to reverse
* @return integer that represents the reversed byte array
*/
@ -104,6 +111,7 @@ public final class HexUtils {
/**
* Takes in a byte array of 4 bytes and returns a long.
*
* @param bytes byte array to convert
* @return long representation of the bytes
*/

View File

@ -21,9 +21,10 @@ import java.nio.file.Path;
public final class JsonUtils {
/**
* Default private constructor so checkstyles doesn't complain
* Default private constructor so checkstyles doesn't complain.
*/
private JsonUtils() { }
private JsonUtils() {
}
/**
* Getter for the JSON Object that is associated with the elementName value
@ -85,7 +86,7 @@ public final class JsonUtils {
JsonObject jsonObject = new JsonObject();
if (Files.notExists(jsonPath)) {
log.warn(String.format("No file found at %s.", jsonPath.toString()));
log.warn("No file found at {}.", jsonPath.toString());
} else {
try {
InputStream inputStream = new FileInputStream(jsonPath.toString());

View File

@ -25,29 +25,24 @@ import java.util.List;
@Log4j2
public final class PciIds {
/**
* Default private constructor so checkstyles doesn't complain
*/
private PciIds() { }
/**
* This pci ids file can be in different places on different distributions.
*/
public static final List<String> PCI_IDS_PATH =
Collections.unmodifiableList(new ArrayList<>() {
private static final long serialVersionUID = 1L;
{
add("/usr/share/hwdata/pci.ids");
add("/usr/share/misc/pci.ids");
add("/tmp/pci.ids");
}
});
/**
* The PCI IDs Database object.
*
* <p>
* This only needs to be loaded one time.
*
* <p>
* The pci ids library protects the data inside the object by making it immutable.
*/
public static final PciIdsDatabase DB = new PciIdsDatabase();
@ -65,7 +60,7 @@ public final class PciIds {
if (dbFile != null) {
InputStream is = null;
try {
is = new FileInputStream(new File(dbFile));
is = new FileInputStream(dbFile);
DB.loadStream(is);
} catch (IOException e) {
// DB will not be ready, hardware IDs will not be translated
@ -83,9 +78,16 @@ public final class PciIds {
}
}
/**
* Default private constructor so checkstyles doesn't complain.
*/
private PciIds() {
}
/**
* Look up the vendor name from the PCI IDs list, if the input string contains an ID.
* If any part of this fails, return the original manufacturer value.
*
* @param refManufacturer DERUTF8String, likely from a ComponentIdentifier
* @return DERUTF8String with the discovered vendor name, or the original manufacturer value.
*/
@ -103,6 +105,7 @@ public final class PciIds {
/**
* Look up the vendor name from the PCI IDs list, if the input string contains an ID.
* If any part of this fails, return the original manufacturer value.
*
* @param refManufacturer String, likely from a ComponentResult
* @return String with the discovered vendor name, or the original manufacturer value.
*/
@ -121,6 +124,7 @@ public final class PciIds {
* Look up the device name from the PCI IDs list, if the input strings contain IDs.
* The Device lookup requires the Vendor ID AND the Device ID to be valid values.
* If any part of this fails, return the original model value.
*
* @param refManufacturer ASN1UTF8String, likely from a ComponentIdentifier
* @param refModel ASN1UTF8String, likely from a ComponentIdentifier
* @return ASN1UTF8String with the discovered device name, or the original model value.
@ -146,6 +150,7 @@ public final class PciIds {
* Look up the device name from the PCI IDs list, if the input strings contain IDs.
* The Device lookup requires the Vendor ID AND the Device ID to be valid values.
* If any part of this fails, return the original model value.
*
* @param refManufacturer String, likely from a ComponentResult
* @param refModel String, likely from a ComponentResult
* @return String with the discovered device name, or the original model value.
@ -169,6 +174,7 @@ public final class PciIds {
/**
* Look up the device class name from the PCI IDs list, if the input string contains an ID.
* If any part of this fails, return the original manufacturer value.
*
* @param refClassCode String, formatted as 2 characters (1 byte) for each of the 3 categories
* Example "010802":
* Class: "01"
@ -184,9 +190,23 @@ public final class PciIds {
String classCode = refClassCode;
if (classCode != null && classCode.trim().matches("^[0-9A-Fa-f]{6}$")) {
String deviceClass = classCode.substring(0, 2).toLowerCase();
String deviceSubclass = classCode.substring(2, 4).toLowerCase();
String programInterface = classCode.substring(4, 6).toLowerCase();
final int startIndexOfDeviceClass = 0;
final int endIndexOfDeviceClass = 2;
String deviceClass =
classCode.substring(startIndexOfDeviceClass, endIndexOfDeviceClass).toLowerCase();
final int startIndexOfDeviceSubclass = 2;
final int endIndexOfDeviceSubclass = 4;
String deviceSubclass =
classCode.substring(startIndexOfDeviceSubclass, endIndexOfDeviceSubclass)
.toLowerCase();
final int startIndexOfProgramInterface = 4;
final int endIndexOfProgramInterface = 6;
final String programInterface =
classCode.substring(startIndexOfProgramInterface, endIndexOfProgramInterface)
.toLowerCase();
translatedClassCode.add(deviceClass);
translatedClassCode.add(deviceSubclass);
translatedClassCode.add(programInterface);

View File

@ -18,15 +18,31 @@ import java.util.Map;
@ToString
public class SwidResource {
@Getter
private static final boolean VALID_FILE_SIZE = false;
@Getter
@Setter
private String name, size, hashValue;
private String name;
@Getter
private String rimFormat, rimType, rimUriGlobal;
// private TpmWhiteListBaseline tpmWhiteList;
@Setter
private String size;
@Getter
@Setter
private String hashValue;
@Getter
private String rimFormat;
@Getter
private String rimType;
@Getter
private String rimUriGlobal;
// private TpmWhiteListBaseline tpmWhiteList;
private DigestAlgorithm digest = DigestAlgorithm.SHA1;
@Getter
private boolean validFileSize = false;
/**
* Default constructor.

View File

@ -15,8 +15,8 @@ import java.util.regex.Pattern;
* <p>
* Two classes were made to facilitate persisting them with Hibernate in different ways.
* To persist non-nullable entries in an embedded collection, use {@link hirs.utils.digest.Digest} (see
* {@link TPMBaseline} for reference.) To persist nullable entries, use {@link hirs.utils.digest.OptionalDigest}
* (see {@link ImaBlacklistRecord} for reference.)
* {@link TPMBaseline} for reference.) To persist nullable entries,
* use {@link hirs.utils.digest.OptionalDigest} (see {@link ImaBlacklistRecord} for reference.)
*/
@Log4j2
public abstract class AbstractDigest {
@ -45,30 +45,6 @@ public abstract class AbstractDigest {
*/
public static final int SHA512_DIGEST_LENGTH = 64;
/**
* Ensures the given algorithm type and digest byte array represent a valid digest.
* This includes ensuring they are both not null or empty and ensuring that the length of the
* digest matches the expected amount of data for the given algorithm.
*
* @param algorithm a digest algorithm
* @param digest the digest computed by this algorithm
* @throws IllegalArgumentException if the provided input does not represent a valid digest
*/
void validateInput(final DigestAlgorithm algorithm, final byte[] digest)
throws IllegalArgumentException {
if (algorithm == null) {
throw new IllegalArgumentException("Algorithm must not be null");
}
if (ArrayUtils.isEmpty(digest)) {
throw new IllegalArgumentException("Digest must have at least one byte");
}
if (digest.length != algorithm.getLengthInBytes()) {
throw new AbstractDigest.IllegalDigestLength(algorithm, digest);
}
}
/**
* This method will help class determine the algorithm associated with the
* pcr values given.
@ -114,6 +90,61 @@ public abstract class AbstractDigest {
return DigestAlgorithm.UNSPECIFIED;
}
/**
* Parses a {@link DigestAlgorithm} from a String returned by {@link AbstractDigest#toString()}.
*
* @param digest the digest string as computed above
* @return the DigestAlgorithm component of the String
*/
static DigestAlgorithm algorithmFromString(final String digest) {
return DigestAlgorithm.findByString(matchString(digest).group(1));
}
/**
* Parses a digest from a String returned by {@link AbstractDigest#toString()}.
*
* @param digest the digest string as computed above
* @return the byte array representing the actual digest
*/
static byte[] digestFromString(final String digest) {
return DatatypeConverter.parseHexBinary(matchString(digest).group(2));
}
private static Matcher matchString(final String digest) {
Pattern digestPattern = Pattern.compile("(.*) - 0x(.*)");
Matcher matcher = digestPattern.matcher(digest);
if (!matcher.matches()) {
String message = String.format("String \"%s\" did not match pattern \"%s\"", digest,
digestPattern);
throw new IllegalArgumentException(message);
}
return matcher;
}
/**
* Ensures the given algorithm type and digest byte array represent a valid digest.
* This includes ensuring they are both not null or empty and ensuring that the length of the
* digest matches the expected amount of data for the given algorithm.
*
* @param algorithm a digest algorithm
* @param digest the digest computed by this algorithm
* @throws IllegalArgumentException if the provided input does not represent a valid digest
*/
void validateInput(final DigestAlgorithm algorithm, final byte[] digest)
throws IllegalArgumentException {
if (algorithm == null) {
throw new IllegalArgumentException("Algorithm must not be null");
}
if (ArrayUtils.isEmpty(digest)) {
throw new IllegalArgumentException("Digest must have at least one byte");
}
if (digest.length != algorithm.getLengthInBytes()) {
throw new AbstractDigest.IllegalDigestLength(algorithm, digest);
}
}
/**
* Retrieves the <code>DigestAlgorithm</code> that identifies which hash
* function generated the digest.
@ -140,6 +171,7 @@ public abstract class AbstractDigest {
/**
* Compares this digest's hash with another digest's hash.
*
* @param otherDigest a Digest to compare to.
* @return the comparison result type.
*/
@ -155,37 +187,6 @@ public abstract class AbstractDigest {
return DigestComparisonResultType.MISMATCH;
}
/**
* Parses a {@link DigestAlgorithm} from a String returned by {@link AbstractDigest#toString()}.
*
* @param digest the digest string as computed above
* @return the DigestAlgorithm component of the String
*/
static DigestAlgorithm algorithmFromString(final String digest) {
return DigestAlgorithm.findByString(matchString(digest).group(1));
}
/**
* Parses a digest from a String returned by {@link AbstractDigest#toString()}.
*
* @param digest the digest string as computed above
* @return the byte array representing the actual digest
*/
static byte[] digestFromString(final String digest) {
return DatatypeConverter.parseHexBinary(matchString(digest).group(2));
}
private static Matcher matchString(final String digest) {
Pattern digestPattern = Pattern.compile("(.*) - 0x(.*)");
Matcher matcher = digestPattern.matcher(digest);
if (!matcher.matches()) {
String message = String.format("String \"%s\" did not match pattern \"%s\"", digest,
digestPattern.toString());
throw new IllegalArgumentException(message);
}
return matcher;
}
@Override
public final int hashCode() {
final int prime = 31;
@ -201,21 +202,15 @@ public abstract class AbstractDigest {
return true;
}
if (obj == null || !(obj instanceof AbstractDigest)) {
if (obj == null || !(obj instanceof AbstractDigest other)) {
return false;
}
AbstractDigest other = (AbstractDigest) obj;
if (getAlgorithm() != other.getAlgorithm()) {
return false;
}
if (!Arrays.equals(getDigest(), other.getDigest())) {
return false;
}
return true;
return Arrays.equals(getDigest(), other.getDigest());
}
/**

View File

@ -50,12 +50,11 @@ public enum DigestAlgorithm {
* options for standardAlgorithmName. Throws an IllegalArgumentException if no Enum exists with
* that value.
*
* @param standardAlgorithmName
* String value of the Enum
* @param standardAlgorithmName String value of the Enum
* @return DigestAlgorithm object
*/
public static DigestAlgorithm findByString(final String standardAlgorithmName) {
for (DigestAlgorithm algorithm: DigestAlgorithm.values()) {
for (DigestAlgorithm algorithm : DigestAlgorithm.values()) {
if (algorithm.getStandardAlgorithmName().equals(standardAlgorithmName)) {
return algorithm;
}

View File

@ -0,0 +1 @@
package hirs.utils.digest;

View File

@ -2,11 +2,6 @@ package hirs.utils.enums;
public final class DeviceInfoEnums {
/**
* Default private constructor so checkstyles doesn't complain
*/
private DeviceInfoEnums() { }
/**
* A variable used to describe unavailable hardware, firmware, or OS info.
*/
@ -23,4 +18,9 @@ public final class DeviceInfoEnums {
* Constant variable representing the various Long sized strings.
*/
public static final int LONG_STRING_LENGTH = 255;
/**
* Default private constructor so checkstyles doesn't complain.
*/
private DeviceInfoEnums() {
}
}

View File

@ -0,0 +1 @@
package hirs.utils.enums;

View File

@ -0,0 +1 @@
package hirs.utils.exception;

View File

@ -0,0 +1 @@
package hirs.utils;

View File

@ -5,10 +5,11 @@ import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.UnmarshalException;
import jakarta.xml.bind.Unmarshaller;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.jcajce.provider.asymmetric.X509;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@ -47,7 +48,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
@ -86,105 +87,29 @@ public class ReferenceManifestValidator {
private Document rim;
private Unmarshaller unmarshaller;
@Getter
private PublicKey publicKey;
private Schema schema;
@Getter
private String subjectKeyIdentifier;
@Setter
private String rimEventLog;
@Setter
private String trustStoreFile;
@Setter
private List<X509Certificate> trustStore;
private boolean signatureValid, supportRimValid;
/**
* Setter for the RIM to be validated. The ReferenceManifest object is converted into a
* Document for processing.
*
* @param rimBytes ReferenceManifest object bytes
*/
public void setRim(final byte[] rimBytes) {
try {
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(
new ByteArrayInputStream(rimBytes))));
this.rim = doc;
} catch (IOException e) {
log.error("Error while unmarshalling rim bytes: " + e.getMessage());
}
}
@Getter
private boolean signatureValid;
/**
* Setter for the swidtag XML to be validated. The XML is passed in via a filepath
* and converted into a Document for processing.
*
* @param path String filepath
*/
public void setRim(final String path) {
File swidtagFile = new File(path);
try {
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(swidtagFile)));
this.rim = doc;
} catch (IOException e) {
log.error("Error while unmarshalling rim bytes: " + e.getMessage());
}
}
/**
* Getter for signatureValid.
*
* @return true if valid, false if not.
*/
public boolean isSignatureValid() {
return signatureValid;
}
/**
* Getter for supportRimValid.
*
* @return true if valid, false if not.
*/
public boolean isSupportRimValid() {
return supportRimValid;
}
/**
* Getter for certificate PublicKey.
*
* @return PublicKey
*/
public PublicKey getPublicKey() {
return publicKey;
}
/**
* Getter for subjectKeyIdentifier.
*
* @return subjectKeyIdentifier
*/
public String getSubjectKeyIdentifier() {
return subjectKeyIdentifier;
}
/**
* Setter for the truststore file path.
* @param trustStoreFile the file path to reference
*/
public void setTrustStoreFile(String trustStoreFile) {
this.trustStoreFile = trustStoreFile;
}
/**
* Setter for truststore
* @param trustStore the List of X509Certificates
*/
public void setTrustStore(List<X509Certificate> trustStore) {
this.trustStore = trustStore;
}
/**
* Setter for rimel file path.
* @param rimEventLog the rimel file
*/
public void setRimEventLog(String rimEventLog) {
this.rimEventLog = rimEventLog;
}
@Getter
private boolean supportRimValid;
/**
* This default constructor creates the Schema object from SCHEMA_URL immediately to save
@ -209,6 +134,38 @@ public class ReferenceManifestValidator {
}
}
/**
* Setter for the RIM to be validated. The ReferenceManifest object is converted into a
* Document for processing.
*
* @param rimBytes ReferenceManifest object bytes
*/
public void setRim(final byte[] rimBytes) {
try {
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(
new ByteArrayInputStream(rimBytes))));
this.rim = doc;
} catch (IOException e) {
log.error("Error while unmarshalling rim bytes: {}", e.getMessage());
}
}
/**
* Setter for the swidtag XML to be validated. The XML is passed in via a filepath
* and converted into a Document for processing.
*
* @param path String filepath
*/
public void setRim(final String path) {
File swidtagFile = new File(path);
try {
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(swidtagFile)));
this.rim = doc;
} catch (IOException e) {
log.error("Error while unmarshalling rim bytes: {}", e.getMessage());
}
}
/**
* This method attempts to validate the signature element of the instance's RIM
* using a given cert. The cert is compared to either the RIM's embedded certificate
@ -257,7 +214,7 @@ public class ReferenceManifestValidator {
return signatureValid;
}
} catch (IOException e) {
log.warn("Error while parsing certificate data: " + e.getMessage());
log.warn("Error while parsing certificate data: {}", e.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
@ -267,25 +224,26 @@ public class ReferenceManifestValidator {
/**
* This method validates the rim with a public key cert.
*
* @param signingCertPath to the public key certificate used to sign the rim
* @return true if both the file element and signature are valid, false otherwise
*/
public boolean validateRim(String signingCertPath) {
public boolean validateRim(final String signingCertPath) {
Element fileElement = (Element) rim.getElementsByTagNameNS(
SwidTagConstants.SWIDTAG_NAMESPACE, "File").item(0);
X509Certificate signingCert = parseCertificatesFromPem(signingCertPath).get(0);
if (signingCert == null) {
return failWithError("Unable to parse the signing cert from " + signingCertPath);
}
String subjectKeyIdentifier = "";
String retrievedSubjectKeyIdentifier = "";
try {
subjectKeyIdentifier = getCertificateSubjectKeyIdentifier(signingCert);
retrievedSubjectKeyIdentifier = getCertificateSubjectKeyIdentifier(signingCert);
} catch (IOException e) {
return failWithError("Error while parsing SKID: " + e.getMessage());
}
boolean isSignatureValid = validateXmlSignature(signingCert.getPublicKey(),
subjectKeyIdentifier,
retrievedSubjectKeyIdentifier,
signingCert.getPublicKey().getEncoded());
return isSignatureValid && validateFile(fileElement);
}
@ -301,13 +259,15 @@ public class ReferenceManifestValidator {
String calculatedHash = getHashValue(input, SHA256);
supportRimValid = calculatedHash.equals(expected);
if (!supportRimValid) {
log.info("Unmatched support RIM hash! Expected: " + expected
+ ", actual: " + calculatedHash);
log.info("Unmatched support RIM hash! Expected: {}, actual: {}", expected, calculatedHash);
}
}
/**
* This method validates a hirs.swid.xjc.File from an indirect payload
* This method validates a hirs.swid.xjc.File from an indirect payload.
*
* @param file file extracted from element
* @return true if the provided file is valid, false otherwise
*/
private boolean validateFile(final Element file) {
String filepath;
@ -317,9 +277,9 @@ public class ReferenceManifestValidator {
filepath = file.getAttribute(SwidTagConstants.NAME);
}
if (getHashValue(filepath, "SHA256").equals(
file.getAttribute(SwidTagConstants._SHA256_HASH.getPrefix() + ":" +
SwidTagConstants._SHA256_HASH.getLocalPart()))) {
log.info("Support RIM hash verified for " + filepath);
file.getAttribute(SwidTagConstants._SHA256_HASH.getPrefix() + ":"
+ SwidTagConstants._SHA256_HASH.getLocalPart()))) {
log.info("Support RIM hash verified for {}", filepath);
return true;
} else {
return failWithError("Support RIM hash does not match Base RIM!");
@ -333,10 +293,10 @@ public class ReferenceManifestValidator {
* @return X509Certificate signing cert
*/
private X509Certificate getCertFromTruststore() throws IOException {
String subjectKeyIdentifier = getKeyName(rim);
String retrievedSubjectKeyIdentifier = getKeyName(rim);
for (X509Certificate trustedCert : trustStore) {
String trustedSubjectKeyIdentifier = getCertificateSubjectKeyIdentifier(trustedCert);
if (subjectKeyIdentifier.equals(trustedSubjectKeyIdentifier)) {
if (retrievedSubjectKeyIdentifier.equals(trustedSubjectKeyIdentifier)) {
return trustedCert;
}
}
@ -345,7 +305,7 @@ public class ReferenceManifestValidator {
}
/**
* This method calculates the digest of the file at filepath based on algorithm sha
* This method calculates the digest of the file at filepath based on algorithm sha.
*
* @param filepath the file to hash
* @param sha the algorithm to use
@ -359,11 +319,12 @@ public class ReferenceManifestValidator {
} catch (NoSuchAlgorithmException e) {
log.warn(e.getMessage());
} catch (IOException e) {
log.warn("Error reading " + filepath + " for hashing: " + e.getMessage());
log.warn("Error reading {} for hashing: {}", filepath, e.getMessage());
}
return null;
}
/**
* This method calculates the digest of a byte array based on the hashing algorithm passed in.
*
@ -401,9 +362,9 @@ public class ReferenceManifestValidator {
whySignatureInvalid(signature, context);
}
} catch (MarshalException e) {
log.warn("Error while unmarshalling XML signature: " + e.getMessage());
log.warn("Error while unmarshalling XML signature: {}", e.getMessage());
} catch (XMLSignatureException e) {
log.warn("Error while validating XML signature: " + e.getMessage());
log.warn("Error while validating XML signature: {}", e.getMessage());
}
return false;
@ -419,7 +380,7 @@ public class ReferenceManifestValidator {
* @throws XMLSignatureException
*/
private void whySignatureInvalid(final XMLSignature signature, final DOMValidateContext context)
throws XMLSignatureException{
throws XMLSignatureException {
boolean cryptoValidity = signature.getSignatureValue().validate(context);
if (cryptoValidity) {
log.error("Signature value is valid.");
@ -435,9 +396,9 @@ public class ReferenceManifestValidator {
refUri = "whole document";
}
if (refValidity) {
log.error("Reference for " + refUri + " is valid.");
log.error("Reference for {} is valid.", refUri);
} else {
log.error("Reference for " + refUri + " is invalid!");
log.error("Reference for {} is invalid!", refUri);
}
}
}
@ -445,6 +406,7 @@ public class ReferenceManifestValidator {
/**
* 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
@ -462,7 +424,7 @@ public class ReferenceManifestValidator {
boolean isChainCertValid;
do {
isChainCertValid = false;
log.info("Validating " + chainCert.getSubjectX500Principal().getName());
log.info("Validating {}", chainCert.getSubjectX500Principal().getName());
for (X509Certificate trustedCert : trustStore) {
boolean isIssuer = areYouMyIssuer(chainCert, trustedCert);
boolean isSigner = areYouMySigner(chainCert, trustedCert);
@ -490,13 +452,14 @@ public class ReferenceManifestValidator {
}
} while (isChainCertValid);
log.error("CA chain validation failed to validate "
+ chainCert.getSubjectX500Principal().getName() + ", " + errorMessage);
log.error("CA chain validation failed to validate {}, {}",
chainCert.getSubjectX500Principal().getName(), errorMessage);
return false;
}
/**
* 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
@ -512,6 +475,7 @@ public class ReferenceManifestValidator {
/**
* 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
@ -528,6 +492,7 @@ public class ReferenceManifestValidator {
/**
* 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
@ -562,6 +527,7 @@ public class ReferenceManifestValidator {
/**
* 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
*/
@ -569,128 +535,6 @@ public class ReferenceManifestValidator {
return cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal());
}
/**
* This internal class handles selecting an X509 certificate embedded in a KeyInfo element.
* It is passed as a parameter to a DOMValidateContext that uses it to validate
* an XML signature.
*/
public class X509KeySelector extends KeySelector {
PublicKey publicKey;
X509Certificate signingCert;
/**
* This method selects a public key for validation.
* PKs are parsed preferentially from the following elements:
* - X509Data
* - KeyValue
* The parsed PK is then verified based on the provided algorithm before
* being returned in a KeySelectorResult.
*
* @param keyinfo object containing the cert.
* @param purpose purpose.
* @param algorithm algorithm.
* @param context XMLCryptoContext.
* @return KeySelectorResult holding the PublicKey.
* @throws KeySelectorException exception.
*/
public KeySelectorResult select(final KeyInfo keyinfo,
final KeySelector.Purpose purpose,
final AlgorithmMethod algorithm,
final XMLCryptoContext context)
throws KeySelectorException {
Iterator keyinfoItr = keyinfo.getContent().iterator();
while (keyinfoItr.hasNext()) {
XMLStructure element = (XMLStructure) keyinfoItr.next();
if (element instanceof X509Data) {
X509Data data = (X509Data) element;
Iterator dataItr = data.getContent().iterator();
while (dataItr.hasNext()) {
Object object = dataItr.next();
if (object instanceof X509Certificate) {
X509Certificate embeddedCert = (X509Certificate) object;
try {
if (isCertChainValid(embeddedCert)) {
publicKey = ((X509Certificate) embeddedCert).getPublicKey();
signingCert = embeddedCert;
log.info("Certificate chain valid.");
}
} catch (Exception e) {
log.error("Certificate chain invalid: " + e.getMessage());
}
}
}
} else if (element instanceof KeyValue) {
try {
PublicKey pk = ((KeyValue) element).getPublicKey();
if (isPublicKeyTrusted(pk)) {
publicKey = pk;
try {
if (isCertChainValid(signingCert)) {
log.info("Certificate chain valid.");
} else {
log.error("Certificate chain invalid.");
}
} catch (Exception e) {
log.error("Certificate chain invalid: " + e.getMessage());
}
}
} catch (KeyException e) {
log.error("Unable to convert KeyValue data to PK.");
}
}
if (publicKey != null) {
if (areAlgorithmsEqual(algorithm.getAlgorithm(), publicKey.getAlgorithm())) {
return new ReferenceManifestValidator.X509KeySelector
.RIMKeySelectorResult(publicKey);
}
}
}
throw new KeySelectorException("No key found!");
}
/**
* This method checks that the signature and public key algorithms match.
* @param uri to match the signature algorithm
* @param name to match the public key algorithm
* @return true if both match, false otherwise
*/
public boolean areAlgorithmsEqual(String uri, String name) {
return uri.equals(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256)
&& name.equalsIgnoreCase("RSA");
}
/**
* 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;
}
/**
* This internal class creates a KeySelectorResult from the public key.
*/
private static class RIMKeySelectorResult implements KeySelectorResult {
private Key key;
RIMKeySelectorResult(final Key key) {
this.key = key;
}
public Key getKey() {
return key;
}
}
}
/**
* This method extracts certificate bytes from a string. The bytes are assumed to be
* PEM format, and a header and footer are concatenated with the input string to
@ -709,12 +553,10 @@ public class ReferenceManifestValidator {
+ System.lineSeparator()
+ pemString
+ System.lineSeparator()
+ certificateFooter).getBytes("UTF-8"));
+ certificateFooter).getBytes(StandardCharsets.UTF_8));
return (X509Certificate) factory.generateCertificate(inputStream);
} catch (CertificateException e) {
log.warn("Error creating CertificateFactory instance: " + e.getMessage());
} catch (UnsupportedEncodingException e) {
log.warn("Error while parsing cert from PEM string: " + e.getMessage());
log.warn("Error creating CertificateFactory instance: {}", e.getMessage());
}
return null;
@ -724,11 +566,12 @@ public class ReferenceManifestValidator {
* This method returns the X509Certificates found in a PEM file.
* Unchecked type case warnings are suppressed because the CertificateFactory
* implements X509Certificate objects explicitly.
*
* @param filename pem file
* @return a list containing all X509Certificates extracted
*/
@SuppressWarnings("unchecked")
private List<X509Certificate> parseCertificatesFromPem(String filename) {
private List<X509Certificate> parseCertificatesFromPem(final String filename) {
List<X509Certificate> certificates = null;
FileInputStream fis = null;
BufferedInputStream bis = null;
@ -742,14 +585,14 @@ public class ReferenceManifestValidator {
(List<X509Certificate>) certificateFactory.generateCertificates(bis);
}
if (certificates.size() < 1) {
if (certificates.isEmpty()) {
System.out.println("ERROR: No certificates parsed from " + filename);
}
bis.close();
} catch (CertificateException e) {
log.error("Error in certificate factory: " + e.getMessage());
log.error("Error in certificate factory: {}", e.getMessage());
} catch (IOException e) {
log.error("Error reading from input stream: " + e.getMessage());
log.error("Error reading from input stream: {}", e.getMessage());
} finally {
try {
if (fis != null) {
@ -759,7 +602,7 @@ public class ReferenceManifestValidator {
bis.close();
}
} catch (IOException e) {
log.warn("Error closing input stream: " + e.getMessage());
log.warn("Error closing input stream: {}", e.getMessage());
}
}
@ -854,11 +697,135 @@ public class ReferenceManifestValidator {
/**
* This method logs an error message and returns a false to signal failed validation.
*
* @param errorMessage String description of what went wrong
* @return false to represent failed validation
*/
private boolean failWithError(String errorMessage) {
private boolean failWithError(final String errorMessage) {
log.error(errorMessage);
return false;
}
/**
* This internal class handles selecting an X509 certificate embedded in a KeyInfo element.
* It is passed as a parameter to a DOMValidateContext that uses it to validate
* an XML signature.
*/
@Setter
@Getter
public class X509KeySelector extends KeySelector {
private PublicKey publicKey;
private X509Certificate signingCert;
/**
* This method selects a public key for validation.
* PKs are parsed preferentially from the following elements:
* - X509Data
* - KeyValue
* The parsed PK is then verified based on the provided algorithm before
* being returned in a KeySelectorResult.
*
* @param keyinfo object containing the cert.
* @param purpose purpose.
* @param algorithm algorithm.
* @param context XMLCryptoContext.
* @return KeySelectorResult holding the PublicKey.
* @throws KeySelectorException exception.
*/
public KeySelectorResult select(final KeyInfo keyinfo,
final KeySelector.Purpose purpose,
final AlgorithmMethod algorithm,
final XMLCryptoContext context)
throws KeySelectorException {
Iterator keyinfoItr = keyinfo.getContent().iterator();
while (keyinfoItr.hasNext()) {
XMLStructure element = (XMLStructure) keyinfoItr.next();
if (element instanceof X509Data data) {
Iterator dataItr = data.getContent().iterator();
while (dataItr.hasNext()) {
Object object = dataItr.next();
if (object instanceof X509Certificate embeddedCert) {
try {
if (isCertChainValid(embeddedCert)) {
publicKey = embeddedCert.getPublicKey();
signingCert = embeddedCert;
log.info("Certificate chain valid.");
}
} catch (Exception e) {
log.error("Certificate chain invalid: {}", e.getMessage());
}
}
}
} else if (element instanceof KeyValue) {
try {
PublicKey pk = ((KeyValue) element).getPublicKey();
if (isPublicKeyTrusted(pk)) {
publicKey = pk;
try {
if (isCertChainValid(signingCert)) {
log.info("Certificate chain valid.");
} else {
log.error("Certificate chain invalid.");
}
} catch (Exception e) {
log.error("Certificate chain invalid: {}", e.getMessage());
}
}
} catch (KeyException e) {
log.error("Unable to convert KeyValue data to PK.");
}
}
if (publicKey != null) {
if (areAlgorithmsEqual(algorithm.getAlgorithm(), publicKey.getAlgorithm())) {
return new ReferenceManifestValidator.X509KeySelector
.RIMKeySelectorResult(publicKey);
}
}
}
throw new KeySelectorException("No key found!");
}
/**
* This method checks that the signature and public key algorithms match.
*
* @param uri to match the signature algorithm
* @param name to match the public key algorithm
* @return true if both match, false otherwise
*/
public boolean areAlgorithmsEqual(final String uri, final String name) {
return uri.equals(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256)
&& name.equalsIgnoreCase("RSA");
}
/**
* 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;
}
/**
* This internal class creates a KeySelectorResult from the public key.
*/
@Getter
private static class RIMKeySelectorResult implements KeySelectorResult {
private final Key key;
RIMKeySelectorResult(final Key key) {
this.key = key;
}
}
}
}

View File

@ -0,0 +1 @@
package hirs.utils.rim;

View File

@ -8,26 +8,19 @@ import javax.xml.namespace.QName;
* class. It is expected that member properties of this class will expand as
* more functionality is added to SwidTagGateway.
*/
public class SwidTagConstants {
public final class SwidTagConstants {
/**
* Default private constructor so checkstyles doesn't complain
*/
private SwidTagConstants() { }
public static final String DEFAULT_KEYSTORE_FILE = "keystore.jks";//"/opt/hirs/rimtool/keystore.jks";
public static final String DEFAULT_KEYSTORE_FILE = "keystore.jks"; //"/opt/hirs/rimtool/keystore.jks";
public static final String DEFAULT_KEYSTORE_PASSWORD = "password";
public static final String DEFAULT_PRIVATE_KEY_ALIAS = "1";
public static final String DEFAULT_ATTRIBUTES_FILE = "/opt/hirs/rimtool/rim_fields.json";
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";
public static final String SCHEMA_PACKAGE = "hirs.swid.xjc";
public static final String SCHEMA_LANGUAGE = XMLConstants.W3C_XML_SCHEMA_NS_URI;
public static final String SCHEMA_URL = "swid_schema.xsd";
public static final String SWIDTAG_NAMESPACE = "http://standards.iso.org/iso/19770/-2/2015/schema.xsd";
public static final String SOFTWARE_IDENTITY = "SoftwareIdentity";
public static final String ENTITY = "Entity";
public static final String LINK = "Link";
@ -76,48 +69,43 @@ public class SwidTagConstants {
public static final String SUPPORT_RIM_FORMAT_MISSING = "supportRIMFormat missing";
public static final String SUPPORT_RIM_URI_GLOBAL = "supportRIMURIGlobal";
public static final String DATETIME = "dateTime";
public static final String NIST_NS = "http://csrc.nist.gov/ns/swid/2015-extensions/1.0";
public static final String TCG_NS = "https://trustedcomputinggroup.org/wp-content/uploads/TCG_RIM_Model";
public static final String RFC3852_NS = "https://www.ietf.org/rfc/rfc3852.txt";
public static final String RFC3339_NS = "https://www.ietf.org/rfc/rfc3339.txt";
public static final String N8060_PFX = "n8060";
public static final String RIM_PFX = "rim";
public static final String FX_SEPARATOR = ":";
public static final String RFC3852_PFX = "rcf3852";
public static final String RFC3339_PFX = "rcf3339";
public static final String _COLLOQUIAL_VERSION_STR = N8060_PFX + FX_SEPARATOR +
COLLOQUIAL_VERSION;
public static final String _PRODUCT_STR = N8060_PFX + FX_SEPARATOR +
PRODUCT;
public static final String _REVISION_STR = N8060_PFX + FX_SEPARATOR +
REVISION;
public static final String _EDITION_STR = N8060_PFX + FX_SEPARATOR +
EDITION;
public static final String _RIM_LINK_HASH_STR = RIM_PFX + FX_SEPARATOR +
RIM_LINK_HASH;
public static final String _BINDING_SPEC_STR = RIM_PFX + FX_SEPARATOR +
BINDING_SPEC;
public static final String _BINDING_SPEC_VERSION_STR = RIM_PFX + FX_SEPARATOR +
BINDING_SPEC_VERSION;
public static final String _PLATFORM_MANUFACTURER_STR = RIM_PFX + FX_SEPARATOR +
PLATFORM_MANUFACTURER_STR;
public static final String _PLATFORM_MANUFACTURER_ID_STR = RIM_PFX + FX_SEPARATOR +
PLATFORM_MANUFACTURER_ID;
public static final String _PLATFORM_MODEL_STR = RIM_PFX + FX_SEPARATOR +
PLATFORM_MODEL;
public static final String _PLATFORM_VERSION_STR = RIM_PFX + FX_SEPARATOR +
PLATFORM_VERSION;
public static final String _PAYLOAD_TYPE_STR = RIM_PFX + FX_SEPARATOR +
PAYLOAD_TYPE;
public static final String _PC_URI_LOCAL_STR = RIM_PFX + FX_SEPARATOR +
PC_URI_LOCAL;
public static final String _PC_URI_GLOBAL_STR = RIM_PFX + FX_SEPARATOR +
PC_URI_GLOBAL;
public static final String _COLLOQUIAL_VERSION_STR = N8060_PFX + FX_SEPARATOR
+ COLLOQUIAL_VERSION;
public static final String _PRODUCT_STR = N8060_PFX + FX_SEPARATOR
+ PRODUCT;
public static final String _REVISION_STR = N8060_PFX + FX_SEPARATOR
+ REVISION;
public static final String _EDITION_STR = N8060_PFX + FX_SEPARATOR
+ EDITION;
public static final String _RIM_LINK_HASH_STR = RIM_PFX + FX_SEPARATOR
+ RIM_LINK_HASH;
public static final String _BINDING_SPEC_STR = RIM_PFX + FX_SEPARATOR
+ BINDING_SPEC;
public static final String _BINDING_SPEC_VERSION_STR = RIM_PFX + FX_SEPARATOR
+ BINDING_SPEC_VERSION;
public static final String _PLATFORM_MANUFACTURER_STR = RIM_PFX + FX_SEPARATOR
+ PLATFORM_MANUFACTURER_STR;
public static final String _PLATFORM_MANUFACTURER_ID_STR = RIM_PFX + FX_SEPARATOR
+ PLATFORM_MANUFACTURER_ID;
public static final String _PLATFORM_MODEL_STR = RIM_PFX + FX_SEPARATOR
+ PLATFORM_MODEL;
public static final String _PLATFORM_VERSION_STR = RIM_PFX + FX_SEPARATOR
+ PLATFORM_VERSION;
public static final String _PAYLOAD_TYPE_STR = RIM_PFX + FX_SEPARATOR
+ PAYLOAD_TYPE;
public static final String _PC_URI_LOCAL_STR = RIM_PFX + FX_SEPARATOR
+ PC_URI_LOCAL;
public static final String _PC_URI_GLOBAL_STR = RIM_PFX + FX_SEPARATOR
+ PC_URI_GLOBAL;
public static final QName _SHA256_HASH = new QName(
"http://www.w3.org/2001/04/xmlenc#sha256", HASH, "SHA256");
public static final QName _COLLOQUIAL_VERSION = new QName(
@ -168,6 +156,11 @@ public class SwidTagConstants {
NIST_NS, "envVarSuffix", N8060_PFX);
public static final QName _N8060_PATHSEPARATOR = new QName(
NIST_NS, "pathSeparator", N8060_PFX);
public static final String CA_ISSUERS = "1.3.6.1.5.5.7.48.2";
/**
* Default private constructor so checkstyles doesn't complain.
*/
private SwidTagConstants() {
}
}

View File

@ -0,0 +1 @@
package hirs.utils.swid;

View File

@ -13,7 +13,7 @@ import java.io.IOException;
* Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER.
* DEVICE_SECURITY_EVENT_DATA_HEADER contains the measurement(s) and hash algorithm identifier
* returned by the SPDM "GET_MEASUREMENTS" function.
*
* <p>
* HEADERS defined by PFP v1.06 Rev 52:
* <p>
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER {
@ -62,8 +62,9 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
super(dsedBytes);
final int dsedBytesSrcIndex1 = 18;
byte[] lengthBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(dsedBytes, 18, lengthBytes, 0,
System.arraycopy(dsedBytes, dsedBytesSrcIndex1, lengthBytes, 0,
UefiConstants.SIZE_2);
length = HexUtils.leReverseInt(lengthBytes);
@ -72,18 +73,22 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
UefiConstants.SIZE_4);
spdmHashAlgo = HexUtils.leReverseInt(spdmHashAlgoBytes);
extractDeviceType(dsedBytes, 24);
final int dsedBytesStartByte = 24;
extractDeviceType(dsedBytes, dsedBytesStartByte);
// get the size of the SPDM Measurement Block
final int dsedBytesSrcIndex2 = 30;
byte[] sizeOfSpdmMeasBlockBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(dsedBytes, 30, sizeOfSpdmMeasBlockBytes, 0,
System.arraycopy(dsedBytes, dsedBytesSrcIndex2, sizeOfSpdmMeasBlockBytes, 0,
UefiConstants.SIZE_2);
int sizeOfSpdmMeas = HexUtils.leReverseInt(sizeOfSpdmMeasBlockBytes);
int sizeOfSpdmMeasBlock = sizeOfSpdmMeas + 4; // header is 4 bytes
final int sizeOfSpdmMeas = HexUtils.leReverseInt(sizeOfSpdmMeasBlockBytes);
final int offSetBytesForSpdm = 4;
final int sizeOfSpdmMeasBlock = sizeOfSpdmMeas + offSetBytesForSpdm; // header is 4 bytes
// extract the bytes that comprise the SPDM Measurement Block
final int dsedBytesSrcIndex3 = 28;
byte[] spdmMeasBlockBytes = new byte[sizeOfSpdmMeasBlock];
System.arraycopy(dsedBytes, 28, spdmMeasBlockBytes, 0,
System.arraycopy(dsedBytes, dsedBytesSrcIndex3, spdmMeasBlockBytes, 0,
sizeOfSpdmMeasBlock);
ByteArrayInputStream spdmMeasurementBlockData =
@ -96,7 +101,8 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
spdmMeasurementBlockInfo = " Error reading SPDM Measurement Block";
}
int devPathLenStartByte = 28 + sizeOfSpdmMeasBlock;
final int offSetBytesForDevPath = 28;
final int devPathLenStartByte = offSetBytesForDevPath + sizeOfSpdmMeasBlock;
extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte);
}

View File

@ -7,7 +7,7 @@ import lombok.Getter;
* Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER2.
* DEVICE_SECURITY_EVENT_DATA_HEADER2 contains the measurement(s) and hash algorithm identifier
* returned by the SPDM "GET_MEASUREMENTS" function.
*
* <p>
* HEADERS defined by PFP v1.06 Rev 52:
* <p>
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER2 {
@ -27,6 +27,32 @@ import lombok.Getter;
*/
public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
/**
* Auth state - success.
*/
public static final int AUTH_SUCCESS = 0;
/**
* Auth state - digital signature of the data is valid, but the public key certificate chain is not
* validated with the entry in the UEFI device signature variable.
*/
public static final int AUTH_NO_AUTHORITY = 1;
/**
* Auth state - digital signature of the measurement data is valid, but the reported device capabilities,
* negotiated parameters or certificate chains were not validated by a transcript.
*/
public static final int AUTH_NO_BINDING = 2;
/**
* Auth state - data has no digital signature.
*/
public static final int AUTH_FAIL_NO_SIG = 3;
/**
* Auth state - data is invalid.
*/
public static final int AUTH_FAIL_INVALID = 4;
/**
* Auth state - device is not an SPDM-capable device.
*/
public static final int AUTH_NO_SPDM = 0xFF;
/**
* Event auth state.
*/
@ -55,33 +81,6 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
@Getter
private String subHeaderUid = "";
/**
* Auth state - success.
*/
public static final int AUTH_SUCCESS = 0;
/**
* Auth state - digital signature of the data is valid, but the public key certificate chain is not
* validated with the entry in the UEFI device signature variable.
*/
public static final int AUTH_NO_AUTHORITY = 1;
/**
* Auth state - digital signature of the measurement data is valid, but the reported device capabilities,
* negotiated parameters or certificate chains were not validated by a transcript.
*/
public static final int AUTH_NO_BINDING = 2;
/**
* Auth state - data has no digital signature.
*/
public static final int AUTH_FAIL_NO_SIG = 3;
/**
* Auth state - data is invalid.
*/
public static final int AUTH_FAIL_INVALID = 4;
/**
* Auth state - device is not an SPDM-capable device.
*/
public static final int AUTH_NO_SPDM = 0xFF;
/**
* DeviceSecurityEventDataHeader2 Constructor.
*
@ -91,33 +90,43 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
super(dsedBytes);
final int dsedBytesSrcIndex = 18;
byte[] authStateBytes = new byte[1];
System.arraycopy(dsedBytes, 18, authStateBytes, 0, 1);
System.arraycopy(dsedBytes, dsedBytesSrcIndex, authStateBytes, 0, 1);
authState = HexUtils.leReverseInt(authStateBytes);
// byte[] reserved[Bytes]: 1 byte
byte[] lengthBytes = new byte[4];
System.arraycopy(dsedBytes, 20, lengthBytes, 0, 4);
final int dsedBytesSrcIndex2 = 20;
final int lengthBytesSize = 4;
byte[] lengthBytes = new byte[lengthBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex2, lengthBytes, 0, lengthBytesSize);
length = HexUtils.leReverseInt(lengthBytes);
extractDeviceType(dsedBytes, 24);
final int dsedBytesStartByte1 = 24;
extractDeviceType(dsedBytes, dsedBytesStartByte1);
byte[] subHeaderTypeBytes = new byte[4];
System.arraycopy(dsedBytes, 28, subHeaderTypeBytes, 0, 4);
final int dsedBytesSrcIndex3 = 28;
final int subHeaderTypeBytesSize = 4;
byte[] subHeaderTypeBytes = new byte[subHeaderTypeBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex3, subHeaderTypeBytes, 0, subHeaderTypeBytesSize);
subHeaderType = HexUtils.leReverseInt(subHeaderTypeBytes);
byte[] subHeaderLengthBytes = new byte[4];
System.arraycopy(dsedBytes, 32, subHeaderLengthBytes, 0, 4);
final int dsedBytesSrcIndex4 = 32;
final int subHeaderLengthBytesSize = 4;
byte[] subHeaderLengthBytes = new byte[subHeaderLengthBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex4, subHeaderLengthBytes, 0, subHeaderLengthBytesSize);
subHeaderLength = HexUtils.leReverseInt(subHeaderLengthBytes);
byte[] subHeaderUidBytes = new byte[8];
System.arraycopy(dsedBytes, 36, subHeaderUidBytes, 0, 8);
final int dsedBytesSrcIndex5 = 36;
final int subHeaderUidBytesSize = 8;
byte[] subHeaderUidBytes = new byte[subHeaderUidBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex5, subHeaderUidBytes, 0, subHeaderUidBytesSize);
subHeaderUidBytes = HexUtils.leReverseByte(subHeaderUidBytes);
subHeaderUid = HexUtils.byteArrayToHexString(subHeaderUidBytes);
int devPathLenStartByte = 44;
extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte);
final int dsedBytesStartByte2 = 44;
extractDevicePathAndFinalSize(dsedBytes, dsedBytesStartByte2);
}
/**
@ -139,22 +148,14 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
* @return a description of the auth state.
*/
public String getAuthStateString() {
switch (authState) {
case AUTH_SUCCESS:
return ("AUTH_SUCCESS");
case AUTH_NO_AUTHORITY:
return ("AUTH_NO_AUTHORITY");
case AUTH_NO_BINDING:
return ("AUTH_NO_BINDING");
case AUTH_FAIL_NO_SIG:
return ("AUTH_FAIL_NO_SIG");
case AUTH_FAIL_INVALID:
return ("AUTH_FAIL_INVALID");
case AUTH_NO_SPDM:
return ("AUTH_NO_SPDM");
default:
return ("Auth State unknown");
}
return switch (authState) {
case AUTH_SUCCESS -> ("AUTH_SUCCESS");
case AUTH_NO_AUTHORITY -> ("AUTH_NO_AUTHORITY");
case AUTH_NO_BINDING -> ("AUTH_NO_BINDING");
case AUTH_FAIL_NO_SIG -> ("AUTH_FAIL_NO_SIG");
case AUTH_FAIL_INVALID -> ("AUTH_FAIL_INVALID");
case AUTH_NO_SPDM -> ("AUTH_NO_SPDM");
default -> ("Auth State unknown");
};
}
}

View File

@ -78,28 +78,36 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
super(dSEDpciContextBytes);
final int dSEDpciContextBytesSrcIndex1 = 4;
byte[] pciVendorIdBytes = new byte[2];
System.arraycopy(dSEDpciContextBytes, 4, pciVendorIdBytes, 0, 2);
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex1, pciVendorIdBytes, 0, 2);
vendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciVendorIdBytes));
final int dSEDpciContextBytesSrcIndex2 = 6;
byte[] pciDeviceIdBytes = new byte[2];
System.arraycopy(dSEDpciContextBytes, 6, pciDeviceIdBytes, 0, 2);
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex2, pciDeviceIdBytes, 0, 2);
deviceId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciDeviceIdBytes));
final int dSEDpciContextBytesSrcIndex3 = 8;
byte[] pciRevisionIdBytes = new byte[1];
System.arraycopy(dSEDpciContextBytes, 8, pciRevisionIdBytes, 0, 1);
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex3, pciRevisionIdBytes, 0, 1);
revisionId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciRevisionIdBytes));
byte[] pciClassCodeBytes = new byte[3];
System.arraycopy(dSEDpciContextBytes, 9, pciClassCodeBytes, 0, 3);
final int dSEDpciContextBytesSrcIndex4 = 9;
final int pciClassCodeBytesSize = 3;
byte[] pciClassCodeBytes = new byte[pciClassCodeBytesSize];
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex4, pciClassCodeBytes, 0,
pciClassCodeBytesSize);
classCode = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciClassCodeBytes));
final int dSEDpciContextBytesSrcIndex5 = 12;
byte[] pciSubsystemVendorIdBytes = new byte[2];
System.arraycopy(dSEDpciContextBytes, 12, pciSubsystemVendorIdBytes, 0, 2);
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex5, pciSubsystemVendorIdBytes, 0, 2);
subsystemVendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemVendorIdBytes));
final int dSEDpciContextBytesSrcIndex6 = 14;
byte[] pciSubsystemIdBytes = new byte[2];
System.arraycopy(dSEDpciContextBytes, 14, pciSubsystemIdBytes, 0, 2);
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex6, pciSubsystemIdBytes, 0, 2);
subsystemId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemIdBytes));
}
@ -118,8 +126,9 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
dSEDpciContextInfo += " RevisionID = " + revisionId + "\n";
List<String> classCodeList = translateDeviceClass(classCode);
final int validClassCodeListSize = 3;
dSEDpciContextInfo += " Device Class: \n";
if (classCodeList.size() == 3) {
if (classCodeList.size() == validClassCodeListSize) {
dSEDpciContextInfo += " Class = " + classCodeList.get(0) + "\n";
dSEDpciContextInfo += " Subclass = " + classCodeList.get(1) + "\n";
dSEDpciContextInfo += " Programming Interface = " + classCodeList.get(2) + "\n";

View File

@ -61,16 +61,21 @@ public class DeviceSecurityEventDataSubHeaderCertChain extends DeviceSecurityEve
// byte[] reserved[Bytes]: 1 byte
byte[] spdmBaseHashAlgoBytes = new byte[4];
System.arraycopy(dsedSubHBytes, 4, spdmBaseHashAlgoBytes, 0, 4);
final int dsedSybHBytesSrcIndex1 = 4;
final int spdmBaseHashAlgoBytesSize = 4;
byte[] spdmBaseHashAlgoBytes = new byte[spdmBaseHashAlgoBytesSize];
System.arraycopy(dsedSubHBytes, dsedSybHBytesSrcIndex1, spdmBaseHashAlgoBytes, 0,
spdmBaseHashAlgoBytesSize);
spdmBaseHashAlgo = HexUtils.leReverseInt(spdmBaseHashAlgoBytes);
// get the size of the SPDM Cert Chain
int spdmCertChainSize = dsedSubHBytes.length - 8;
final int offsetForSpdmCertChain = 8;
int spdmCertChainSize = dsedSubHBytes.length - offsetForSpdmCertChain;
// extract the bytes that comprise the SPDM Cert Chain
final int dsedSybHBytesSrcIndex2 = 8;
byte[] spdmCertChainBytes = new byte[spdmCertChainSize];
System.arraycopy(dsedSubHBytes, 8, spdmCertChainBytes, 0,
System.arraycopy(dsedSubHBytes, dsedSybHBytesSrcIndex2, spdmCertChainBytes, 0,
spdmCertChainSize);
int spdmBaseHashAlgoSize = SpdmHa.tcgAlgIdToByteSize(spdmBaseHashAlgo);

View File

@ -22,7 +22,7 @@ import java.util.List;
* SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock[SpdmMeasurementBlockCount];
* } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK;
* <p>
*
* <p>
* SpdmMeasurementBlock is an array of SPDM_MEASUREMENT_BLOCKs
* The size of each block is the same and can be found by either:
* 1) 4 + SpdmMeasurementBlock MeasurementSize
@ -33,6 +33,10 @@ import java.util.List;
*/
public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends DeviceSecurityEventDataSubHeader {
/**
* List of SPDM Measurement Blocks.
*/
private final List<SpdmMeasurementBlock> spdmMeasurementBlockList;
/**
* SPDM version.
*/
@ -48,11 +52,6 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
*/
@Getter
private int spdmMeasurementHashAlgo = -1;
/**
* List of SPDM Measurement Blocks.
*/
private List<SpdmMeasurementBlock> spdmMeasurementBlockList;
/**
* Error reading SPDM Measurement Block.
*/
@ -77,16 +76,21 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
// byte[] reserved[Bytes]: 1 byte
byte[] spdmMeasurementHashAlgoBytes = new byte[4];
System.arraycopy(dsedSubHBytes, 4, spdmMeasurementHashAlgoBytes, 0, 4);
final int spdmMeasurementHashAlgoBytesSize = 4;
final int dsedSubHBytesSrcIndex1 = 4;
byte[] spdmMeasurementHashAlgoBytes = new byte[spdmMeasurementHashAlgoBytesSize];
System.arraycopy(dsedSubHBytes, dsedSubHBytesSrcIndex1, spdmMeasurementHashAlgoBytes, 0,
spdmMeasurementHashAlgoBytesSize);
spdmMeasurementHashAlgo = HexUtils.leReverseInt(spdmMeasurementHashAlgoBytes);
// get the total size of the SPDM Measurement Block List
int spdmMeasurementBlockListSize = dsedSubHBytes.length - 8;
final int offsetForspdmMeasurementBlockList = 8;
final int spdmMeasurementBlockListSize = dsedSubHBytes.length - offsetForspdmMeasurementBlockList;
// extract the bytes that comprise the SPDM Measurement Block List
final int dsedSubHBytesSrcIndex2 = 8;
byte[] spdmMeasurementBlockListBytes = new byte[spdmMeasurementBlockListSize];
System.arraycopy(dsedSubHBytes, 8, spdmMeasurementBlockListBytes, 0,
System.arraycopy(dsedSubHBytes, dsedSubHBytesSrcIndex2, spdmMeasurementBlockListBytes, 0,
spdmMeasurementBlockListSize);
ByteArrayInputStream spdmMeasurementBlockListData =

View File

@ -12,7 +12,7 @@ import java.nio.charset.StandardCharsets;
* The first 16 bytes of the event data header MUST be a String based identifier (Signature),
* NUL-terminated, per PFP. The only currently defined Signature is "SPDM Device Sec",
* which implies the data is a DEVICE_SECURITY_EVENT_DATA or ..DATA2.
*
* <p>
* HEADERS defined by PFP v1.06 Rev 52.
* Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures.
* <p>
@ -51,12 +51,16 @@ import java.nio.charset.StandardCharsets;
*/
public abstract class DeviceSecurityEventHeader {
/**
* UEFI Device Path Length.
*/
@Getter
private static final int DEVICE_PATH_LENGTH = 0;
/**
* Contains the size (in bytes) of the header.
*/
@Getter
private Integer dsedHeaderLength = 0;
/**
* Signature (text) data.
*/
@ -73,11 +77,6 @@ public abstract class DeviceSecurityEventHeader {
*/
@Getter
private int deviceType = -1;
/**
* UEFI Device Path Length.
*/
@Getter
private int devicePathLength = 0;
/**
* UEFI Device path.
*/
@ -129,21 +128,23 @@ public abstract class DeviceSecurityEventHeader {
int startByteUpdated = startByte;
// get the device path length
byte[] devicePathLengthBytes = new byte[8];
System.arraycopy(dsedBytes, startByteUpdated, devicePathLengthBytes, 0, 8);
int devicePathLength = HexUtils.leReverseInt(devicePathLengthBytes);
final int devicePathLengthBytesSize = 8;
byte[] devicePathLengthBytes = new byte[devicePathLengthBytesSize];
System.arraycopy(dsedBytes, startByteUpdated, devicePathLengthBytes, 0, devicePathLengthBytesSize);
int retrievedDevicePathLength = HexUtils.leReverseInt(devicePathLengthBytes);
// get the device path
if (devicePathLength > 0) {
startByteUpdated = startByteUpdated + 8;
byte[] devPathBytes = new byte[devicePathLength];
if (retrievedDevicePathLength > 0) {
final int startByteUpdatedOffset = 8;
startByteUpdated = startByteUpdated + startByteUpdatedOffset;
byte[] devPathBytes = new byte[retrievedDevicePathLength];
System.arraycopy(dsedBytes, startByteUpdated, devPathBytes,
0, devicePathLength);
0, retrievedDevicePathLength);
devicePath = new UefiDevicePath(devPathBytes);
}
// header total size
dsedHeaderLength = startByteUpdated + devicePathLength;
dsedHeaderLength = startByteUpdated + retrievedDevicePathLength;
}
/**
@ -154,16 +155,12 @@ public abstract class DeviceSecurityEventHeader {
* @return name of the device type
*/
public String deviceTypeToString(final int deviceTypeInt) {
switch (deviceTypeInt) {
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_NONE:
return "No device type";
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_PCI:
return "PCI";
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_USB:
return "USB";
default:
return "Unknown or invalid Device Type";
}
return switch (deviceTypeInt) {
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_NONE -> "No device type";
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_PCI -> "PCI";
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_USB -> "USB";
default -> "Unknown or invalid Device Type";
};
}
/**

View File

@ -6,11 +6,6 @@ package hirs.utils.tpm.eventlog.events;
*/
public final class EvConstants {
/**
* Default private constructor so checkstyles doesn't complain
*/
private EvConstants() { }
/**
* Type length = 4 bytes.
*/
@ -39,11 +34,11 @@ public final class EvConstants {
* Each PCR bank holds 24 registers.
*/
public static final int PCR_COUNT = 24;
// Event IDs
/**
* Pre boot cert Event ID.
*/
public static final int EV_PREBOOT_CERT = 0x00000000;
// Event IDs
/**
* POST Code Event ID.
*/
@ -180,4 +175,9 @@ public final class EvConstants {
* EFI SPDM Device Authority Event ID.
*/
public static final int EV_EFI_SPDM_DEVICE_AUTHORITY = 0x800000E4;
/**
* Default private constructor so checkstyles doesn't complain.
*/
private EvConstants() {
}
}

View File

@ -66,7 +66,7 @@ public class EvNoAction {
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
if (signature.contains("Spec ID Event03")) { // implies CryptAgileFormat
EvEfiSpecIdEvent specIDEvent = new EvEfiSpecIdEvent(eventData);
noActionInfo += specIDEventToString(specIDEvent).toString();
noActionInfo += specIDEventToString(specIDEvent);
bSpecIDEvent = true;
specVersion = String.format("%s.%s",
specIDEvent.getVersionMajor(),
@ -126,25 +126,21 @@ public class EvNoAction {
* @return a description of the locality.
*/
private String getLocality(final byte[] eventData) {
String localityInfo = "";
final int eventDataSrcIndex = 16;
byte[] localityBytes = new byte[1];
System.arraycopy(eventData, 16, localityBytes, 0, 1);
int locality = HexUtils.leReverseInt(localityBytes);
System.arraycopy(eventData, eventDataSrcIndex, localityBytes, 0, 1);
final int locality = HexUtils.leReverseInt(localityBytes);
switch (locality) {
case 0:
localityInfo += "Locality 0 without an H-CRTM sequence";
break;
case 3:
localityInfo += "Locality 3 without an H-CRTM sequence";
break;
case 4:
localityInfo += "Locality 4 with an H-CRTM sequence initialized";
break;
default:
localityInfo += "Unknown";
}
return localityInfo;
final int locality0 = 0;
final int locality3 = 3;
final int locality4 = 4;
return switch (locality) {
case locality0 -> "Locality 0 without an H-CRTM sequence";
case locality3 -> "Locality 3 without an H-CRTM sequence";
case locality4 -> "Locality 4 with an H-CRTM sequence initialized";
default -> "Unknown";
};
}
/**

View File

@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets;
* Class to process the NV_INDEX_DYNAMIC_EVENT_LOG_DATA per PFP.
* Per PFP, the first 16 bytes of the structure are a String based identifier (Signature),
* which are a NULL-terminated ASCII string "NvIndexDynamic".
*
* <p>
* HEADERS defined by PFP v1.06 Rev 52.
* Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures.
* <p>
@ -43,13 +43,16 @@ public class NvIndexDynamicEventLogData {
*/
public NvIndexDynamicEventLogData(final byte[] eventData) {
byte[] signatureBytes = new byte[16];
System.arraycopy(eventData, 0, signatureBytes, 0, 16);
final int signatureBytesSize = 16;
byte[] signatureBytes = new byte[signatureBytesSize];
System.arraycopy(eventData, 0, signatureBytes, 0, signatureBytesSize);
signature = new String(signatureBytes, StandardCharsets.UTF_8);
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
byte[] versionBytes = new byte[2];
System.arraycopy(eventData, 16, versionBytes, 0, 2);
final int versionBytesSize = 2;
final int eventDataSrcIndex1 = 16;
byte[] versionBytes = new byte[versionBytesSize];
System.arraycopy(eventData, eventDataSrcIndex1, versionBytes, 0, versionBytesSize);
String nvIndexVersion = HexUtils.byteArrayToHexString(versionBytes);
if (nvIndexVersion.isEmpty()) {
nvIndexVersion = "version not readable";
@ -58,23 +61,28 @@ public class NvIndexDynamicEventLogData {
nvIndexDynamicInfo += " Nv Index Dynamic Version = " + nvIndexVersion + "\n";
// 6 bytes of Reserved data
byte[] uidBytes = new byte[8];
System.arraycopy(eventData, 24, uidBytes, 0, 8);
final int uidBytesSize = 8;
final int eventDataSrcIndex2 = 24;
byte[] uidBytes = new byte[uidBytesSize];
System.arraycopy(eventData, eventDataSrcIndex2, uidBytes, 0, uidBytesSize);
String uid = HexUtils.byteArrayToHexString(uidBytes);
nvIndexDynamicInfo += " UID = " + uid + "\n";
byte[] descriptionSizeBytes = new byte[2];
System.arraycopy(eventData, 32, descriptionSizeBytes, 0, 2);
final int descriptionSizeBytesLength = 2;
final int eventDataSrcIndex3 = 32;
byte[] descriptionSizeBytes = new byte[descriptionSizeBytesLength];
System.arraycopy(eventData, eventDataSrcIndex3, descriptionSizeBytes, 0, descriptionSizeBytesLength);
int descriptionSize = HexUtils.leReverseInt(descriptionSizeBytes);
final int eventDataSrcIndex4 = 34;
byte[] descriptionBytes = new byte[descriptionSize];
System.arraycopy(eventData, 34, descriptionBytes, 0, descriptionSize);
System.arraycopy(eventData, eventDataSrcIndex4, descriptionBytes, 0, descriptionSize);
String description = new String(descriptionBytes, StandardCharsets.UTF_8);
description = description.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
nvIndexDynamicInfo += " Description = " + description + "\n";
int dataSizeStartByte = 34 + descriptionSize;
final int dataSizeOffset = 34;
int dataSizeStartByte = dataSizeOffset + descriptionSize;
byte[] dataSizeBytes = new byte[2];
System.arraycopy(eventData, dataSizeStartByte, dataSizeBytes, 0, 2);
int dataSize = HexUtils.leReverseInt(dataSizeBytes);

View File

@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets;
* Class to process the NV_INDEX_INSTANCE_EVENT_LOG_DATA per PFP.
* Per PFP, the first 16 bytes of the structure are a String based identifier (Signature),
* which are a NULL-terminated ASCII string "NvIndexInstance".
*
* <p>
* HEADERS defined by PFP v1.06 Rev 52.
* Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures.
* <p>
@ -45,13 +45,15 @@ public class NvIndexInstanceEventLogData {
*/
public NvIndexInstanceEventLogData(final byte[] eventData) {
byte[] signatureBytes = new byte[16];
System.arraycopy(eventData, 0, signatureBytes, 0, 16);
final int signatureBytesSize = 16;
byte[] signatureBytes = new byte[signatureBytesSize];
System.arraycopy(eventData, 0, signatureBytes, 0, signatureBytesSize);
signature = new String(signatureBytes, StandardCharsets.UTF_8);
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
final int eventDataSrcIndex1 = 16;
byte[] versionBytes = new byte[2];
System.arraycopy(eventData, 16, versionBytes, 0, 2);
System.arraycopy(eventData, eventDataSrcIndex1, versionBytes, 0, 2);
String nvIndexVersion = HexUtils.byteArrayToHexString(versionBytes);
if (nvIndexVersion == "") {
nvIndexVersion = "version not readable";
@ -60,14 +62,16 @@ public class NvIndexInstanceEventLogData {
nvIndexInstanceInfo += " Nv Index Instance Version = " + nvIndexVersion + "\n";
// 6 bytes of Reserved data
byte[] dsedSignatureBytes = new byte[16];
System.arraycopy(eventData, 24, dsedSignatureBytes, 0, 16);
final int eventDataSrcIndex2 = 24;
final int dsedSignatureBytesSize = 16;
byte[] dsedSignatureBytes = new byte[dsedSignatureBytesSize];
System.arraycopy(eventData, eventDataSrcIndex2, dsedSignatureBytes, 0, dsedSignatureBytesSize);
String dsedSignature = new String(dsedSignatureBytes, StandardCharsets.UTF_8);
dsedSignature = dsedSignature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
final int eventDataSrcIndex3 = 40;
byte[] dsedVersionBytes = new byte[2];
System.arraycopy(eventData, 40, dsedVersionBytes, 0, 2);
System.arraycopy(eventData, eventDataSrcIndex3, dsedVersionBytes, 0, 2);
String dsedVersion = HexUtils.byteArrayToHexString(dsedVersionBytes);
if (dsedVersion == "") {
dsedVersion = "version not readable";
@ -75,9 +79,10 @@ public class NvIndexInstanceEventLogData {
if (dsedSignature.contains("SPDM Device Sec2")) {
int dsedEventDataSize = eventData.length - 24;
final int eventDataSrcIndex4 = 24;
final int dsedEventDataSize = eventData.length - eventDataSrcIndex4;
byte[] dsedEventData = new byte[dsedEventDataSize];
System.arraycopy(eventData, 24, dsedEventData, 0, dsedEventDataSize);
System.arraycopy(eventData, eventDataSrcIndex4, dsedEventData, 0, dsedEventDataSize);
nvIndexInstanceInfo += " Signature = SPDM Device Sec2\n";
@ -89,7 +94,7 @@ public class NvIndexInstanceEventLogData {
+ dsedVersion + "\n";
}
} else {
nvIndexInstanceInfo = " Signature error: should be \'SPDM Device Sec2\' but is "
nvIndexInstanceInfo = " Signature error: should be 'SPDM Device Sec2' but is "
+ signature + "\n";
}
}

View File

@ -38,6 +38,10 @@ public class SpdmCertificateChain {
// * Length of the certificate chain to include all fields in this structure.
// */
//private int length = 0;
/**
* Array List of certs found in the chain.
*/
private final ArrayList<UefiX509Cert> certList = new ArrayList<UefiX509Cert>();
/**
* Root hash.
*/
@ -46,10 +50,6 @@ public class SpdmCertificateChain {
* Number of certs in the SPDM cert chain.
*/
private int numberOfCerts = 0;
/**
* Array List of certs found in the chain.
*/
private ArrayList<UefiX509Cert> certList = new ArrayList<UefiX509Cert>();
/**
* Human-readable description of any error associated with SPDM base hash alg.
*/
@ -76,11 +76,13 @@ public class SpdmCertificateChain {
// Reserved: 2 bytes
final int spdmCertChainBytesSrcIndex = 4;
rootHash = new byte[rootHashLength];
System.arraycopy(spdmCertChainBytes, 4, rootHash, 0, rootHashLength);
System.arraycopy(spdmCertChainBytes, spdmCertChainBytesSrcIndex, rootHash, 0, rootHashLength);
int certChainStartPos = 4 + rootHashLength;
int certChainLength = spdmCertChainBytes.length - certChainStartPos;
final int offsetForCertChain = 4;
final int certChainStartPos = offsetForCertChain + rootHashLength;
final int certChainLength = spdmCertChainBytes.length - certChainStartPos;
byte[] certChainBytes = new byte[certChainLength];
System.arraycopy(spdmCertChainBytes, certChainStartPos, certChainBytes, 0, certChainLength);
@ -113,10 +115,11 @@ public class SpdmCertificateChain {
byte[] certData = new byte[cLength];
certChainDataIS.read(certData);
// put the cert back together
byte[] certBlob = new byte[cLength + 4];
final int certBlobStartIndex = 4;
byte[] certBlob = new byte[cLength + certBlobStartIndex];
System.arraycopy(certType, 0, certBlob, 0, 2);
System.arraycopy(certLength, 0, certBlob, 2, 2);
System.arraycopy(certData, 0, certBlob, 4, cLength);
System.arraycopy(certData, 0, certBlob, certBlobStartIndex, cLength);
cert = new UefiX509Cert(certBlob);
//cert = new X509Certificate(certBlob);
certList.add(cert);

View File

@ -4,12 +4,7 @@ package hirs.utils.tpm.eventlog.spdm;
* Class for defining hash algorithms referenced in the DMTF SPDM specification.
* SPDM 1.3.0, Table 21, MeasurementHashAlgo.
*/
public class SpdmHa {
/**
* Default private constructor so checkstyles doesn't complain
*/
private SpdmHa() { }
public final class SpdmHa {
/**
* Spdm Hash Alg = Raw bit stream.
@ -40,6 +35,12 @@ public class SpdmHa {
*/
public static final int TPM_ALG_SHA3_512 = 64;
/**
* Default private constructor so checkstyles doesn't complain.
*/
private SpdmHa() {
}
/**
* Returns the hash name via a lookup.
* Lookup based upon SPDM Spec v1.03 section 10.4.
@ -48,32 +49,16 @@ public class SpdmHa {
* @return name of the algorithm
*/
public static String tcgAlgIdToString(final int algId) {
String alg;
switch (algId) {
case TPM_ALG_RAW:
alg = "Raw Bit Stream";
break;
case TPM_ALG_SHA_256:
alg = "TPM_ALG_SHA_256";
break;
case TPM_ALG_SHA_384:
alg = "TPM_ALG_SHA_384";
break;
case TPM_ALG_SHA_512:
alg = "TPM_ALG_SHA_512";
break;
case TPM_ALG_SHA3_256:
alg = "TPM_ALG_SHA3_256";
break;
case TPM_ALG_SHA3_384:
alg = "TPM_ALG_SHA3_384";
break;
case TPM_ALG_SHA3_512:
alg = "TPM_ALG_SHA3_512";
break;
default:
alg = "Unknown or invalid Hash";
}
String alg = switch (algId) {
case TPM_ALG_RAW -> "Raw Bit Stream";
case TPM_ALG_SHA_256 -> "TPM_ALG_SHA_256";
case TPM_ALG_SHA_384 -> "TPM_ALG_SHA_384";
case TPM_ALG_SHA_512 -> "TPM_ALG_SHA_512";
case TPM_ALG_SHA3_256 -> "TPM_ALG_SHA3_256";
case TPM_ALG_SHA3_384 -> "TPM_ALG_SHA3_384";
case TPM_ALG_SHA3_512 -> "TPM_ALG_SHA3_512";
default -> "Unknown or invalid Hash";
};
return alg;
}
@ -85,32 +70,17 @@ public class SpdmHa {
* @return size of the algorithm output
*/
public static int tcgAlgIdToByteSize(final int algId) {
int byteSize;
switch (algId) {
//case TPM_ALG_RAW: // add this when have more test data
// byteSize = ;
// break;
case TPM_ALG_SHA_256:
byteSize = 32;
break;
case TPM_ALG_SHA_384:
byteSize = 48;
break;
case TPM_ALG_SHA_512:
byteSize = 64;
break;
case TPM_ALG_SHA3_256:
byteSize = 32;
break;
case TPM_ALG_SHA3_384:
byteSize = 48;
break;
case TPM_ALG_SHA3_512:
byteSize = 64;
break;
default:
byteSize = -1;
}
return byteSize;
final int byteSize256 = 32;
final int byteSize384 = 48;
final int byteSize512 = 64;
return switch (algId) {
// case TPM_ALG_RAW: // add this when have more test data
// return ;
case TPM_ALG_SHA_256, TPM_ALG_SHA3_256 -> byteSize256;
case TPM_ALG_SHA_384, TPM_ALG_SHA3_384 -> byteSize384;
case TPM_ALG_SHA_512, TPM_ALG_SHA3_512 -> byteSize512;
default -> -1;
};
}
}

View File

@ -27,15 +27,70 @@ import lombok.Getter;
*/
public class SpdmMeasurement {
/**
* MEASUREMENT_VALUE_0 = Immutable ROM.
*/
private static final int MEASUREMENT_VALUE_0 = 0;
/**
* MEASUREMENT_VALUE_1 = Mutable firmware.
*/
private static final int MEASUREMENT_VALUE_1 = 1;
/**
* MEASUREMENT_VALUE_2 = Hardware configuration.
*/
private static final int MEASUREMENT_VALUE_2 = 2;
/**
* MEASUREMENT_VALUE_3 = Firmware configuration.
*/
private static final int MEASUREMENT_VALUE_3 = 3;
/**
* MEASUREMENT_VALUE_4 = Freeform measurement manifest.
*/
private static final int MEASUREMENT_VALUE_4 = 4;
/**
* MEASUREMENT_VALUE_5 = Structured representation of debug and device mode.
*/
private static final int MEASUREMENT_VALUE_5 = 5;
/**
* MEASUREMENT_VALUE_6 = Mutable firmware's version number.
*/
private static final int MEASUREMENT_VALUE_6 = 6;
/**
* MEASUREMENT_VALUE_7 = Mutable firmware's security version number.
*/
private static final int MEASUREMENT_VALUE_7 = 7;
/**
* MEASUREMENT_VALUE_8 = Hash-extended measurement.
*/
private static final int MEASUREMENT_VALUE_8 = 8;
/**
* MEASUREMENT_VALUE_9 = Informational.
*/
private static final int MEASUREMENT_VALUE_9 = 9;
/**
* MEASUREMENT_VALUE_10 = Structured measurement manifest.
*/
private static final int MEASUREMENT_VALUE_10 = 10;
/**
* Measurement value (digest).
*/
private final byte[] dmtfSpecMeasurementValue;
/**
* Measurement value type (such as mutable firmware, etc).
*/
@Getter
private int dmtfSpecMeasurementValueType = 0;
/**
* Measurement value (digest).
*/
private byte[] dmtfSpecMeasurementValue;
/**
* SpdmMeasurement Constructor.
@ -49,14 +104,16 @@ public class SpdmMeasurement {
1);
dmtfSpecMeasurementValueType = HexUtils.leReverseInt(dmtfSpecMeasurementValueTypeBytes);
// in future, can crosscheck this value size + 3 with the spdm block MeasurementSize size
// in the future, can crosscheck this value size + 3 with the spdm block MeasurementSize size
byte[] dmtfSpecMeasurementValueSizeBytes = new byte[2];
System.arraycopy(spdmMeasBytes, 1, dmtfSpecMeasurementValueSizeBytes, 0,
2);
int dmtfSpecMeasurementValueSize = HexUtils.leReverseInt(dmtfSpecMeasurementValueSizeBytes);
dmtfSpecMeasurementValue = new byte[dmtfSpecMeasurementValueSize];
System.arraycopy(spdmMeasBytes, 3, dmtfSpecMeasurementValue, 0,
final int sourceIndex = 3;
System.arraycopy(spdmMeasBytes, sourceIndex, dmtfSpecMeasurementValue, 0,
dmtfSpecMeasurementValueSize);
}
@ -64,50 +121,23 @@ public class SpdmMeasurement {
* Lookup for SPDM measurement value type.
*
* @param measValType the numerical representation of the measurement value type.
*
* @return a description of the measurement value type.
*/
public String dmtfSpecMeasurementValueTypeToString(final int measValType) {
String measValTypeStr;
switch (measValType) {
case 0:
measValTypeStr = "Immutable ROM";
break;
case 1:
measValTypeStr = "Mutable firmware";
break;
case 2:
measValTypeStr = "Hardware configuration";
break;
case 3:
measValTypeStr = "Firmware configuration";
break;
case 4:
measValTypeStr = "Freeform measurement manifest";
break;
case 5:
measValTypeStr = "Structured representation of debug and device mode";
break;
case 6:
measValTypeStr = "Mutable firmware's version number";
break;
case 7:
measValTypeStr = "Mutable firmware's security version number";
break;
case 8:
measValTypeStr = "Hash-extended measurement";
break;
case 9:
measValTypeStr = "Informational";
break;
case 10:
measValTypeStr = "Structured measurement manifest";
break;
default:
measValTypeStr = "Unknown or invalid DMTF Spec Measurement Value Type";
}
return measValTypeStr;
return switch (measValType) {
case MEASUREMENT_VALUE_0 -> "Immutable ROM";
case MEASUREMENT_VALUE_1 -> "Mutable firmware";
case MEASUREMENT_VALUE_2 -> "Hardware configuration";
case MEASUREMENT_VALUE_3 -> "Firmware configuration";
case MEASUREMENT_VALUE_4 -> "Freeform measurement manifest";
case MEASUREMENT_VALUE_5 -> "Structured representation of debug and device mode";
case MEASUREMENT_VALUE_6 -> "Mutable firmware's version number";
case MEASUREMENT_VALUE_7 -> "Mutable firmware's security version number";
case MEASUREMENT_VALUE_8 -> "Hash-extended measurement";
case MEASUREMENT_VALUE_9 -> "Informational";
case MEASUREMENT_VALUE_10 -> "Structured measurement manifest";
default -> "Unknown or invalid DMTF Spec Measurement Value Type";
};
}
/**

View File

@ -7,11 +7,6 @@ package hirs.utils.tpm.eventlog.uefi;
*/
public final class UefiConstants {
/**
* Default private constructor so checkstyles doesn't complain
*/
private UefiConstants() { }
/**
* 2 byte size.
*/
@ -287,4 +282,9 @@ public final class UefiConstants {
* file status, where file is not accessible (either not found, or no access permission).
*/
public static final String FILESTATUS_NOT_ACCESSIBLE = "fileNotAccessible";
/**
* Default private constructor so checkstyles doesn't complain.
*/
private UefiConstants() {
}
}

View File

@ -1,436 +1,20 @@
package hirs.data.persist;
import java.util.Arrays;
import hirs.utils.digest.Digest;
import hirs.utils.digest.DigestAlgorithm;
import hirs.utils.digest.DigestComparisonResultType;
import org.apache.commons.codec.digest.DigestUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
/**
* Unit tests for the <code>Digest</code> class.
*/
public class DigestTest {
private static final int DIGEST_LENGTH_BYTES = 20;
/**
* Tests that constructor throws a <code>IllegalArgumentException</code> when a
* null <code>DigestAlgorithm</code> is passed into constructor.
*/
@Test
public final void nullAlgorithm() {
final byte[] digest = getTestDigest(16);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(null, digest));
}
/**
* Tests that constructor throws a <code>IllegalArgumentException</code> when a
* null digest is passed into constructor.
*/
@Test
public final void nullDigest() {
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.MD2, null));
}
/**
* Tests that constructor throws a <code>IllegalArgumentException</code> when an
* digest that is an empty array is passed into constructor.
*/
@Test
public final void emptyArrayDigest() {
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.MD2, new byte[0]));
}
/**
* Tests that MD2 digest can be created.
*/
@Test
public final void md2() {
final byte[] digest = getTestDigest(16);
final Digest d = new Digest(DigestAlgorithm.MD2, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that an MD2 digest can be recreated from a string.
*/
@Test
public final void testFromStringMD2() {
final byte[] digestBytes = getTestDigest(16);
Digest digest = new Digest(DigestAlgorithm.MD2, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that MD2 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void md2IllegalDigest() {
final byte[] digest = getTestDigest(17);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.MD2, digest));
}
/**
* Tests that MD5 digest can be created.
*/
@Test
public final void md5() {
final byte[] digest = getTestDigest(16);
final Digest d = new Digest(DigestAlgorithm.MD5, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that an MD5 digest can be recreated from a string.
*/
@Test
public final void testFromStringMD5() {
final byte[] digestBytes = getTestDigest(16);
Digest digest = new Digest(DigestAlgorithm.MD5, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that MD5 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void md5IllegalDigest() {
final byte[] digest = getTestDigest(17);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.MD5, digest));
}
/**
* Tests that SHA1 digest can be created.
*/
@Test
public final void sha1() {
final byte[] digest = getTestDigest(20);
final Digest d = new Digest(DigestAlgorithm.SHA1, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that SHA1 digest can be recreated from a string.
*/
@Test
public final void testFromStringSHA1() {
final byte[] digestBytes = getTestDigest(20);
Digest digest = new Digest(DigestAlgorithm.SHA1, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that SHA1 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void sha1IllegalDigest() {
final byte[] digest = getTestDigest(21);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.SHA1, digest));
}
/**
* Tests that SHA256 digest can be created.
*/
@Test
public final void sha256() {
final byte[] digest = getTestDigest(32);
final Digest d = new Digest(DigestAlgorithm.SHA256, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that SHA256 digest can be recreated from a string.
*/
@Test
public final void testFromStringSHA256() {
final byte[] digestBytes = getTestDigest(32);
Digest digest = new Digest(DigestAlgorithm.SHA256, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that SHA256 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void sha256IllegalDigest() {
final byte[] digest = getTestDigest(33);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.SHA256, digest));
}
/**
* Tests that SHA384 digest can be created.
*/
@Test
public final void sha384() {
final byte[] digest = getTestDigest(48);
final Digest d = new Digest(DigestAlgorithm.SHA384, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that SHA384 digest can be recreated from a string.
*/
@Test
public final void testFromStringSHA384() {
final byte[] digestBytes = getTestDigest(48);
Digest digest = new Digest(DigestAlgorithm.SHA384, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that SHA384 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void sha384IllegalDigest() {
final byte[] digest = getTestDigest(49);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.SHA384, digest));
}
/**
* Tests that SHA512 digest can be created.
*/
@Test
public final void sha512() {
final byte[] digest = getTestDigest(64);
final Digest d = new Digest(DigestAlgorithm.SHA512, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that SHA512 digest can be recreated from a string.
*/
@Test
public final void testFromStringSHA512() {
final byte[] digestBytes = getTestDigest(64);
Digest digest = new Digest(DigestAlgorithm.SHA512, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that SHA512 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void sha512IllegalDigest() {
final byte[] digest = getTestDigest(65);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.SHA512, digest));
}
/**
* Tests that the correct <code>DigestAlgorithm</code> is returned by
* {@link Digest#getAlgorithm()}.
*/
@Test
public final void testGetAlgorithm() {
final Digest d = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
Assertions.assertEquals(d.getAlgorithm(), DigestAlgorithm.SHA1);
}
/**
* Tests that the bytes of the digest are created and do not affect the
* underlying state of the <code>Digest</code> instance.
*/
@Test
public final void testGetDigest() {
final Digest d = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
final byte[] digestBytes = d.getDigest();
final byte[] testBytes = getTestDigest(20);
Assertions.assertArrayEquals(digestBytes, testBytes);
digestBytes[0] = (byte) (digestBytes[0] + 1);
Assertions.assertArrayEquals(d.getDigest(), testBytes);
Assertions.assertFalse(Arrays.equals(d.getDigest(), digestBytes));
}
/**
* Tests that two <code>Digest</code>s have equal hash code for same
* algorithm and digest.
*/
@Test
public final void testHashCodeEqual() {
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
Assertions.assertEquals(d2.hashCode(), d1.hashCode());
}
/**
* Tests that two <code>Digest</code>s indicate MATCH when compared.
*/
@Test
public final void testMatchedComparison() {
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
}
/**
* Tests that two <code>Digest</code>s have unequal hash code for same
* digest but different algorithm.
*/
@Test
public final void testHashCodeNotEqualAlgorithm() {
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(16));
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(16));
Assertions.assertNotEquals(d2.hashCode(), d1.hashCode());
}
/**
* Tests that two <code>Digest</code>s indicate MISMATCH when compared.
*/
@Test
public final void testMismatchAlgorithm() {
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(16));
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(16));
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
}
/**
* Tests that two <code>Digest</code>s have unequal hash code for same
* algorithm but different digest.
*/
@Test
public final void testHashCodeNotEqualDigest() {
final byte[] digest = getTestDigest(20);
final Digest d1 = new Digest(DigestAlgorithm.SHA1, digest);
digest[0] += 1;
final Digest d2 = new Digest(DigestAlgorithm.SHA1, digest);
Assertions.assertNotEquals(d2.hashCode(), d1.hashCode());
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
}
/**
* Tests that two <code>Digest</code>s are equal for same algorithm and
* digest.
*/
@Test
public final void testEqual() {
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
Assertions.assertEquals(d2, d1);
}
/**
* Tests that two <code>Digest</code>s are unequal for same digest but
* different algorithm.
*/
@Test
public final void testNotEqualAlgorithm() {
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(16));
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(16));
Assertions.assertNotEquals(d2, d1);
}
/**
* Tests that two <code>Digest</code>s are unequal for same algorithm but
* different digest.
*/
@Test
public final void testNotEqualDigest() {
final byte[] digest = getTestDigest(20);
final Digest d1 = new Digest(DigestAlgorithm.SHA1, digest);
digest[0] += 1;
final Digest d2 = new Digest(DigestAlgorithm.SHA1, digest);
Assertions.assertNotEquals(d2, d1);
}
/**
* Tests that comparing a null Digest to a Digest indicates an UNKNOWN
* comparison type.
*/
@Test
public final void testCompareToNull() {
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(16));
Assertions.assertEquals(DigestComparisonResultType.UNKNOWN, d1.compare(null));
}
/**
* Tests that comparing two Digests with hashes with values of zero gives a MATCH
* comparison result.
*/
@Test
public final void testCompareToDigestWithBothZeroizedHash() {
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(20));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(20));
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
}
/**
* Tests that comparing two Digests, one with a hash of value zero, gives a MISMATCH
* comparison result.
*/
@Test
public final void testCompareToDigestWithOneZeroizedHash() {
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(20));
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
}
/**
* Tests that comparing two Digests with a hash of no data gives a MATCH
* comparison result.
*/
@Test
public final void testCompareToDigestWithBothEmptyHash() {
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
}
/**
* Tests that comparing two Digests, one with a hash of no data, gives a MISMATCH
* comparison result.
*/
@Test
public final void testCompareToDigestWithOneEmptyHash() {
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
}
/**
* Tests that if someone tries to recreate a Digest using an invalid String, an error is thrown.
*/
@Test
public final void testFromStringInvalid() {
String invalidDigestString = "SHA1 00000000000000000000";
Assertions.assertThrows(IllegalArgumentException.class,
() -> Digest.fromString(invalidDigestString));
}
/**
* Get a test SHA1 digest.
*
@ -464,7 +48,455 @@ public class DigestTest {
return new byte[count];
}
/**
* Tests that constructor throws a <code>IllegalArgumentException</code> when a
* null <code>DigestAlgorithm</code> is passed into constructor.
*/
@Test
public final void nullAlgorithm() {
final int count = 16;
final byte[] digest = getTestDigest(count);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(null, digest));
}
/**
* Tests that constructor throws a <code>IllegalArgumentException</code> when a
* null digest is passed into constructor.
*/
@Test
public final void nullDigest() {
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.MD2, null));
}
/**
* Tests that constructor throws a <code>IllegalArgumentException</code> when an
* digest that is an empty array is passed into constructor.
*/
@Test
public final void emptyArrayDigest() {
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.MD2, new byte[0]));
}
/**
* Tests that MD2 digest can be created.
*/
@Test
public final void md2() {
final int count = 16;
final byte[] digest = getTestDigest(count);
final Digest d = new Digest(DigestAlgorithm.MD2, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that an MD2 digest can be recreated from a string.
*/
@Test
public final void testFromStringMD2() {
final int count = 16;
final byte[] digestBytes = getTestDigest(count);
Digest digest = new Digest(DigestAlgorithm.MD2, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that MD2 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void md2IllegalDigest() {
final int count = 17;
final byte[] digest = getTestDigest(count);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.MD2, digest));
}
/**
* Tests that MD5 digest can be created.
*/
@Test
public final void md5() {
final int count = 16;
final byte[] digest = getTestDigest(count);
final Digest d = new Digest(DigestAlgorithm.MD5, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that an MD5 digest can be recreated from a string.
*/
@Test
public final void testFromStringMD5() {
final int count = 16;
final byte[] digestBytes = getTestDigest(count);
Digest digest = new Digest(DigestAlgorithm.MD5, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that MD5 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void md5IllegalDigest() {
final int count = 17;
final byte[] digest = getTestDigest(count);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.MD5, digest));
}
/**
* Tests that SHA1 digest can be created.
*/
@Test
public final void sha1() {
final int count = 20;
final byte[] digest = getTestDigest(count);
final Digest d = new Digest(DigestAlgorithm.SHA1, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that SHA1 digest can be recreated from a string.
*/
@Test
public final void testFromStringSHA1() {
final int count = 20;
final byte[] digestBytes = getTestDigest(count);
Digest digest = new Digest(DigestAlgorithm.SHA1, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that SHA1 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void sha1IllegalDigest() {
final int count = 21;
final byte[] digest = getTestDigest(count);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.SHA1, digest));
}
/**
* Tests that SHA256 digest can be created.
*/
@Test
public final void sha256() {
final int count = 32;
final byte[] digest = getTestDigest(count);
final Digest d = new Digest(DigestAlgorithm.SHA256, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that SHA256 digest can be recreated from a string.
*/
@Test
public final void testFromStringSHA256() {
final int count = 32;
final byte[] digestBytes = getTestDigest(count);
Digest digest = new Digest(DigestAlgorithm.SHA256, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that SHA256 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void sha256IllegalDigest() {
final int count = 33;
final byte[] digest = getTestDigest(count);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.SHA256, digest));
}
/**
* Tests that SHA384 digest can be created.
*/
@Test
public final void sha384() {
final int count = 48;
final byte[] digest = getTestDigest(count);
final Digest d = new Digest(DigestAlgorithm.SHA384, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that SHA384 digest can be recreated from a string.
*/
@Test
public final void testFromStringSHA384() {
final int count = 48;
final byte[] digestBytes = getTestDigest(count);
Digest digest = new Digest(DigestAlgorithm.SHA384, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that SHA384 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void sha384IllegalDigest() {
final int count = 49;
final byte[] digest = getTestDigest(count);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.SHA384, digest));
}
/**
* Tests that SHA512 digest can be created.
*/
@Test
public final void sha512() {
final int count = 64;
final byte[] digest = getTestDigest(count);
final Digest d = new Digest(DigestAlgorithm.SHA512, digest);
Assertions.assertNotNull(d);
}
/**
* Tests that SHA512 digest can be recreated from a string.
*/
@Test
public final void testFromStringSHA512() {
final int count = 64;
final byte[] digestBytes = getTestDigest(count);
Digest digest = new Digest(DigestAlgorithm.SHA512, digestBytes);
String digestString = digest.toString();
Digest digestFromString = Digest.fromString(digestString);
Assertions.assertEquals(digest, digestFromString);
}
/**
* Tests that SHA512 digest cannot be created with a digest that has extra
* bytes.
*/
@Test
public final void sha512IllegalDigest() {
final int count = 65;
final byte[] digest = getTestDigest(count);
Assertions.assertThrows(IllegalArgumentException.class,
() -> new Digest(DigestAlgorithm.SHA512, digest));
}
/**
* Tests that the correct <code>DigestAlgorithm</code> is returned by
* {@link Digest#getAlgorithm()}.
*/
@Test
public final void testGetAlgorithm() {
final int count = 20;
final Digest d = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
Assertions.assertEquals(d.getAlgorithm(), DigestAlgorithm.SHA1);
}
/**
* Tests that the bytes of the digest are created and do not affect the
* underlying state of the <code>Digest</code> instance.
*/
@Test
public final void testGetDigest() {
final int count = 20;
final Digest d = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
final byte[] digestBytes = d.getDigest();
final byte[] testBytes = getTestDigest(count);
Assertions.assertArrayEquals(digestBytes, testBytes);
digestBytes[0] = (byte) (digestBytes[0] + 1);
Assertions.assertArrayEquals(d.getDigest(), testBytes);
Assertions.assertFalse(Arrays.equals(d.getDigest(), digestBytes));
}
/**
* Tests that two <code>Digest</code>s have equal hash code for same
* algorithm and digest.
*/
@Test
public final void testHashCodeEqual() {
final int count = 20;
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
Assertions.assertEquals(d2.hashCode(), d1.hashCode());
}
/**
* Tests that two <code>Digest</code>s indicate MATCH when compared.
*/
@Test
public final void testMatchedComparison() {
final int count = 20;
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
}
/**
* Tests that two <code>Digest</code>s have unequal hash code for same
* digest but different algorithm.
*/
@Test
public final void testHashCodeNotEqualAlgorithm() {
final int count = 16;
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(count));
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(count));
Assertions.assertNotEquals(d2.hashCode(), d1.hashCode());
}
/**
* Tests that two <code>Digest</code>s indicate MISMATCH when compared.
*/
@Test
public final void testMismatchAlgorithm() {
final int count = 16;
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(count));
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(count));
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
}
/**
* Tests that two <code>Digest</code>s have unequal hash code for same
* algorithm but different digest.
*/
@Test
public final void testHashCodeNotEqualDigest() {
final int count = 20;
final byte[] digest = getTestDigest(count);
final Digest d1 = new Digest(DigestAlgorithm.SHA1, digest);
digest[0] += 1;
final Digest d2 = new Digest(DigestAlgorithm.SHA1, digest);
Assertions.assertNotEquals(d2.hashCode(), d1.hashCode());
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
}
/**
* Tests that two <code>Digest</code>s are equal for same algorithm and
* digest.
*/
@Test
public final void testEqual() {
final int count = 20;
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
Assertions.assertEquals(d2, d1);
}
/**
* Tests that two <code>Digest</code>s are unequal for same digest but
* different algorithm.
*/
@Test
public final void testNotEqualAlgorithm() {
final int count = 16;
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(count));
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(count));
Assertions.assertNotEquals(d2, d1);
}
/**
* Tests that two <code>Digest</code>s are unequal for same algorithm but
* different digest.
*/
@Test
public final void testNotEqualDigest() {
final int count = 20;
final byte[] digest = getTestDigest(count);
final Digest d1 = new Digest(DigestAlgorithm.SHA1, digest);
digest[0] += 1;
final Digest d2 = new Digest(DigestAlgorithm.SHA1, digest);
Assertions.assertNotEquals(d2, d1);
}
/**
* Tests that comparing a null Digest to a Digest indicates an UNKNOWN
* comparison type.
*/
@Test
public final void testCompareToNull() {
final int count = 16;
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(count));
Assertions.assertEquals(DigestComparisonResultType.UNKNOWN, d1.compare(null));
}
/**
* Tests that comparing two Digests with hashes with values of zero gives a MATCH
* comparison result.
*/
@Test
public final void testCompareToDigestWithBothZeroizedHash() {
final int count = 20;
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(count));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(count));
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
}
/**
* Tests that comparing two Digests, one with a hash of value zero, gives a MISMATCH
* comparison result.
*/
@Test
public final void testCompareToDigestWithOneZeroizedHash() {
final int count = 20;
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(count));
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
}
/**
* Tests that comparing two Digests with a hash of no data gives a MATCH
* comparison result.
*/
@Test
public final void testCompareToDigestWithBothEmptyHash() {
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
}
/**
* Tests that comparing two Digests, one with a hash of no data, gives a MISMATCH
* comparison result.
*/
@Test
public final void testCompareToDigestWithOneEmptyHash() {
final int count = 20;
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
}
/**
* Tests that if someone tries to recreate a Digest using an invalid String, an error is thrown.
*/
@Test
public final void testFromStringInvalid() {
String invalidDigestString = "SHA1 00000000000000000000";
Assertions.assertThrows(IllegalArgumentException.class,
() -> Digest.fromString(invalidDigestString));
}
private byte[] getEmptySHA1Digest() {
return DigestUtils.sha1(new byte[]{});
return DigestUtils.sha1(new byte[] {});
}
}

View File

@ -2,11 +2,11 @@ package hirs.data.persist;
import hirs.attestationca.persist.entity.userdefined.info.FirmwareInfo;
import org.apache.commons.lang3.StringUtils;
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
/**
* FirmwareInfoTest is a unit test class for FirmwareInfo.
*/
@ -15,18 +15,20 @@ public class FirmwareInfoTest {
private static final String BIOS_VENDOR = "test bios vendor";
private static final String BIOS_VERSION = "test bios version";
private static final String BIOS_RELEASE_DATE = "test bios release date";
private static final int PRIMARY_SIZE = 257;
private static final int SECONDARY_SIZE = 33;
private static final String LONG_BIOS_VENDOR = StringUtils.rightPad(
"test bios vendor",
257
BIOS_VENDOR,
PRIMARY_SIZE
);
private static final String LONG_BIOS_VERSION = StringUtils.rightPad(
"test bios version",
257
BIOS_VERSION,
PRIMARY_SIZE
);
private static final String LONG_BIOS_RELEASE_DATE = StringUtils.rightPad(
"test bios release date",
33
BIOS_RELEASE_DATE,
SECONDARY_SIZE
);
/**
@ -44,8 +46,8 @@ public class FirmwareInfoTest {
public final void firmwareInfoNoParams() {
FirmwareInfo firmwareInfo = new FirmwareInfo();
Assertions.assertEquals(NOT_SPECIFIED, firmwareInfo.getBiosVendor());
Assertions.assertEquals(NOT_SPECIFIED,firmwareInfo.getBiosVersion());
Assertions.assertEquals(NOT_SPECIFIED,firmwareInfo.getBiosReleaseDate());
Assertions.assertEquals(NOT_SPECIFIED, firmwareInfo.getBiosVersion());
Assertions.assertEquals(NOT_SPECIFIED, firmwareInfo.getBiosReleaseDate());
}
/**

View File

@ -1,12 +1,12 @@
package hirs.data.persist;
import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo;
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
/**
* HardwareInfoTest is a unit test class for HardwareInfo.
*/
@ -18,30 +18,32 @@ public class HardwareInfoTest {
private static final String SERIAL_NUMBER = "test serial number";
private static final String CHASSIS_SERIAL_NUMBER = "test chassis serial number";
private static final String BASEBOARD_SERIAL_NUMBER = "test baseboard serial number";
private static final int PRIMARY_SIZE = 257;
private static final int SECONDARY_SIZE = 65;
private static final String LONG_MANUFACTURER = StringUtils.rightPad(
"test manufacturer",
257
MANUFACTURER,
PRIMARY_SIZE
);
private static final String LONG_PRODUCT_NAME = StringUtils.rightPad(
"test product name",
257
PRODUCT_NAME,
PRIMARY_SIZE
);
private static final String LONG_VERSION = StringUtils.rightPad(
"test version",
65
VERSION,
SECONDARY_SIZE
);
private static final String LONG_SERIAL_NUMBER = StringUtils.rightPad(
"test serial number",
257
SERIAL_NUMBER,
PRIMARY_SIZE
);
private static final String LONG_CHASSIS_SERIAL_NUMBER = StringUtils.rightPad(
"test chassis serial number",
257
CHASSIS_SERIAL_NUMBER,
PRIMARY_SIZE
);
private static final String LONG_BASEBOARD_SERIAL_NUMBER = StringUtils.rightPad(
"test baseboard serial number",
257
BASEBOARD_SERIAL_NUMBER,
PRIMARY_SIZE
);
/**

View File

@ -1,12 +1,12 @@
package hirs.data.persist;
import hirs.attestationca.persist.entity.userdefined.info.NetworkInfo;
import java.net.InetAddress;
import java.net.UnknownHostException;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* NetworkInfoTest is a unit test class for NetworkInfo.
*/
@ -17,6 +17,15 @@ public class NetworkInfoTest {
private static final byte[] MAC_ADDRESS = new byte[] {11, 22, 33, 44, 55,
66};
private static InetAddress getTestIpAddress() {
try {
final byte[] byteAddress = new byte[] {127, 0, 0, 1};
return InetAddress.getByAddress(byteAddress);
} catch (UnknownHostException e) {
return null;
}
}
/**
* Tests instantiation of a NetworkInfo object.
*/
@ -103,14 +112,14 @@ public class NetworkInfoTest {
* Tests that hashcodes generated by NetworkInfo objects with different IP
* addresses are not equal.
*
* @throws UnknownHostException
* in case the InetAddress is not created correctly
* @throws UnknownHostException in case the InetAddress is not created correctly
*/
@Test
public final void testHashCodeNotEqualsIpAddress()
throws UnknownHostException {
final byte[] byteAddress = new byte[] {127, 0, 0, 2};
final InetAddress ipAddress2 =
InetAddress.getByAddress(new byte[] {127, 0, 0, 2});
InetAddress.getByAddress(byteAddress);
NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
NetworkInfo ni2 = new NetworkInfo(HOSTNAME, ipAddress2, MAC_ADDRESS);
Assertions.assertNotEquals(ni2.hashCode(), ni1.hashCode());
@ -155,13 +164,13 @@ public class NetworkInfoTest {
* Tests that two NetworkInfo objects are not equal if they have different
* IP addresses.
*
* @throws UnknownHostException
* in case InetAddress is not created correctly
* @throws UnknownHostException in case InetAddress is not created correctly
*/
@Test
public final void testNotEqualsIpAddress() throws UnknownHostException {
final byte[] byteAddress = new byte[] {127, 0, 0, 2};
final InetAddress ipAddress2 =
InetAddress.getByAddress(new byte[] {127, 0, 0, 2});
InetAddress.getByAddress(byteAddress);
NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
NetworkInfo ni2 = new NetworkInfo(HOSTNAME, ipAddress2, MAC_ADDRESS);
Assertions.assertNotEquals(ni2, ni1);
@ -178,12 +187,4 @@ public class NetworkInfoTest {
NetworkInfo ni2 = new NetworkInfo(HOSTNAME, IP_ADDRESS, macAddress2);
Assertions.assertNotEquals(ni2, ni1);
}
private static InetAddress getTestIpAddress() {
try {
return InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
} catch (UnknownHostException e) {
return null;
}
}
}

View File

@ -1,12 +1,12 @@
package hirs.data.persist;
import hirs.attestationca.persist.entity.userdefined.info.OSInfo;
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
/**
* OSInfoTest is a unit test class for OSInfo.
*/
@ -17,10 +17,12 @@ public class OSInfoTest {
private static final String OS_ARCH = "test osArch";
private static final String DISTRIBUTION = "test distribution";
private static final String DISTRIBUTION_RELEASE = "test distribution release";
private static final int PRIMARY_SIZE = 257;
private static final int SECONDARY_SIZE = 33;
private static final String LONG_OS_NAME = StringUtils.rightPad("test os", 257);
private static final String LONG_OS_VERSION = StringUtils.rightPad("test osVersion", 257);
private static final String LONG_OS_ARCH = StringUtils.rightPad("test osArch", 33);
private static final String LONG_OS_NAME = StringUtils.rightPad(OS_NAME, PRIMARY_SIZE);
private static final String LONG_OS_VERSION = StringUtils.rightPad(OS_VERSION, PRIMARY_SIZE);
private static final String LONG_OS_ARCH = StringUtils.rightPad(OS_ARCH, SECONDARY_SIZE);
/**
* Tests instantiation of an OSInfo object.

View File

@ -0,0 +1 @@
package hirs.data.persist;

View File

@ -1,25 +1,29 @@
package hirs.tpm.eventlog.uefi;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import com.eclipsesource.json.JsonObject;
import hirs.utils.HexUtils;
import hirs.utils.JsonUtils;
import hirs.utils.tpm.eventlog.uefi.*;
import hirs.utils.tpm.eventlog.uefi.UefiDevicePath;
import hirs.utils.tpm.eventlog.uefi.UefiFirmware;
import hirs.utils.tpm.eventlog.uefi.UefiGuid;
import hirs.utils.tpm.eventlog.uefi.UefiPartition;
import hirs.utils.tpm.eventlog.uefi.UefiVariable;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import hirs.utils.HexUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
/**
* Class for testing TCG Event Log processing of UEFI defined Data.
*/
@ -70,7 +74,7 @@ public class UefiProcessingTest {
Path jsonPath = Paths.get(this.getClass()
.getResource(JSON_FILE).toURI());
String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_VARIABLE_BOOT),
"UTF-8");
StandardCharsets.UTF_8);
byte[] uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt);
UefiVariable uefiVariable = new UefiVariable(uefiVariableBytes);
UefiGuid guid = uefiVariable.getUefiVarGuid();
@ -83,7 +87,7 @@ public class UefiProcessingTest {
uefiTxt = IOUtils.toString(this.getClass()
.getResourceAsStream(UEFI_VARIABLE_BOOT_SECURE_BOOT),
"UTF-8");
StandardCharsets.UTF_8);
uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt);
uefiVariable = new UefiVariable(uefiVariableBytes);
guid = uefiVariable.getUefiVarGuid();
@ -94,7 +98,7 @@ public class UefiProcessingTest {
Assertions.assertEquals("SecureBoot", varName);
uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(
UEFI_VARIABLE_BOOT_DRIVER_CONFIG_KEK), "UTF-8");
UEFI_VARIABLE_BOOT_DRIVER_CONFIG_KEK), StandardCharsets.UTF_8);
uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt);
uefiVariable = new UefiVariable(uefiVariableBytes);
varName = uefiVariable.getEfiVarName();
@ -116,7 +120,7 @@ public class UefiProcessingTest {
Path jsonPath = Paths.get(this.getClass()
.getResource(JSON_FILE).toURI());
String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_GPT_EVENT),
"UTF-8");
StandardCharsets.UTF_8);
byte[] uefiPartitionBytes = HexUtils.hexStringToByteArray(uefiTxt);
UefiPartition gptPart = new UefiPartition(uefiPartitionBytes);
String gptPartName = gptPart.getPartitionName();
@ -143,13 +147,17 @@ public class UefiProcessingTest {
CertificateException, NoSuchAlgorithmException {
LOGGER.debug("Testing the parsing of Uefi Firmware Blob");
String uefiTxt = IOUtils.toString(this.getClass()
.getResourceAsStream(UEFI_FW_BLOB), "UTF-8");
.getResourceAsStream(UEFI_FW_BLOB), StandardCharsets.UTF_8);
byte[] uefiFwBlobBytes = HexUtils.hexStringToByteArray(uefiTxt);
UefiFirmware uefiFWBlob = new UefiFirmware(uefiFwBlobBytes);
int fwAddress = uefiFWBlob.getPhysicalBlobAddress();
int fwLength = uefiFWBlob.getBlobLength();
Assertions.assertEquals(1797287936, fwAddress);
Assertions.assertEquals(851968, fwLength);
final int expectedFwAddress = 1797287936;
Assertions.assertEquals(expectedFwAddress, fwAddress);
final int expectedFwLength = 851968;
Assertions.assertEquals(expectedFwLength, fwLength);
}
/**
@ -162,7 +170,7 @@ public class UefiProcessingTest {
public final void testUefiDevicePath() throws IOException, URISyntaxException {
LOGGER.debug("Testing the parsing of Uefi Device Path");
String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_DEVICE_PATH),
"UTF-8");
StandardCharsets.UTF_8);
byte[] uefiFwBlobBytes = HexUtils.hexStringToByteArray(uefiTxt);
UefiDevicePath uefiDevPath = new UefiDevicePath(uefiFwBlobBytes);
String devPathType = uefiDevPath.getType();

View File

@ -0,0 +1 @@
package hirs.tpm.eventlog.uefi;

View File

@ -2,8 +2,9 @@ package hirs.utils;
import org.apache.logging.log4j.util.Strings;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
* Tests methods in the (@link BouncyCastleUtils) utility class.

View File

@ -1,6 +1,7 @@
package hirs.utils;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -14,11 +15,10 @@ public class HexUtilsTest {
*/
@Test
public void testHexStringToByteArray() {
String s = "abcd1234";
byte[] target = {-85, -51, 18, 52};
byte[] b = HexUtils.hexStringToByteArray(s);
assertArrayEquals(b, target);
final String testString = "abcd1234";
final byte[] expectedBytes = {-85, -51, 18, 52};
final byte[] actualBytes = HexUtils.hexStringToByteArray(testString);
assertArrayEquals(expectedBytes, actualBytes);
}
/**
@ -26,11 +26,10 @@ public class HexUtilsTest {
*/
@Test
public void testByteArrayToHexString() {
String target = "abcd1234";
byte[] b = {-85, -51, 18, 52};
String s = HexUtils.byteArrayToHexString(b);
assertEquals(s, target);
final byte[] byteArray = {-85, -51, 18, 52};
final String expectedString = "abcd1234";
final String actualString = HexUtils.byteArrayToHexString(byteArray);
assertEquals(expectedString, actualString);
}
/**
@ -38,11 +37,10 @@ public class HexUtilsTest {
*/
@Test
public void testByteArrayToHexStringConditional() {
String target = "abcd0100";
byte[] b = {-85, -51, 1, 0};
String s = HexUtils.byteArrayToHexString(b);
assertEquals(s, target);
final byte[] byteArray = {-85, -51, 1, 0};
final String expectedHexString = "abcd0100";
final String actualHexString = HexUtils.byteArrayToHexString(byteArray);
assertEquals(expectedHexString, actualHexString);
}
/**
@ -50,9 +48,10 @@ public class HexUtilsTest {
*/
@Test
public void testHexToInt() {
String s = "ff";
Integer i = HexUtils.hexToInt(s);
assertEquals((int) i, HexUtils.FF_BYTE);
final String testString = "ff";
final int expectedInt = HexUtils.FF_BYTE;
final Integer actualInt = HexUtils.hexToInt(testString);
assertEquals(expectedInt, (int) actualInt);
}
/**
@ -60,14 +59,11 @@ public class HexUtilsTest {
*/
@Test
public void testSubarray() {
byte[] b = {-85, -51, 18, 52};
byte[] target = {-51, 18};
byte[] sub = HexUtils.subarray(b, 1, 2);
assertArrayEquals(sub, target);
final byte[] b = {-85, -51, 18, 52};
final byte[] expectedSubArray = {-51, 18};
final byte[] actualSubArray = HexUtils.subarray(b, 1, 2);
assertArrayEquals(expectedSubArray, actualSubArray);
}
}

View File

@ -1,11 +1,12 @@
package hirs.utils;
import org.apache.logging.log4j.Logger;
import org.mockito.Mockito;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertNull;
import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.times;
/**

View File

@ -0,0 +1 @@
package hirs.utils;

View File

@ -1,20 +1,20 @@
package hirs.utils.tpm.eventlog;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.util.Arrays;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import static hirs.utils.tpm.eventlog.TCGEventLog.PCR_COUNT;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue;
@ -36,7 +36,6 @@ public class TCGEventLogTest {
@BeforeAll
public static final void setup() {
LOGGER.debug("retrieving session factory");
}
/**
@ -49,6 +48,7 @@ public class TCGEventLogTest {
/**
* Tests the processing of a crypto agile event log.
*
* @throws IOException when processing the test fails
* @throws NoSuchAlgorithmException if an unknown algorithm is encountered.
* @throws CertificateException if a certificate fails to parse.
@ -57,28 +57,33 @@ public class TCGEventLogTest {
public final void testCryptoAgileTCGEventLog() throws IOException, CertificateException,
NoSuchAlgorithmException {
LOGGER.debug("Testing the parsing of a Crypto Agile formatted TCG Event Log");
InputStream log, pcrs;
try {
// setup
final InputStream log = this.getClass().getResourceAsStream(DEFAULT_EVENT_LOG);
final InputStream pcrs = this.getClass().getResourceAsStream(DEFAULT_EXPECTED_PCRS);
final byte[] rawLogBytes = IOUtils.toByteArray(log);
final TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
final String[] pcrFromLog = evlog.getExpectedPCRValues();
final Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
final String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
boolean testPass = true;
log = this.getClass().getResourceAsStream(DEFAULT_EVENT_LOG);
byte[] rawLogBytes = IOUtils.toByteArray(log);
TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
String[] pcrFromLog = evlog.getExpectedPCRValues();
pcrs = this.getClass().getResourceAsStream(DEFAULT_EXPECTED_PCRS);
Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
// Test 1 get all PCRs
for (int i = 0; i < 24; i++) {
for (int i = 0; i < PCR_COUNT; i++) {
if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) {
testPass = false;
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR " + i);
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR {}", i);
}
}
assertTrue(testPass);
// Test 2 get an individual PCR
String pcr3 = evlog.getExpectedPCRValue(3);
assertThat(pcrFromLog[3], equalTo(pcr3));
final int pcrIndex = 3;
String pcr3 = evlog.getExpectedPCRValue(pcrIndex);
assertThat(pcrFromLog[pcrIndex], equalTo(pcr3));
// Test 3 check the Algorithm String Identifier used in the log
String algStr = evlog.getEventLogHashAlgorithm();
@ -89,10 +94,14 @@ public class TCGEventLogTest {
assertThat(TcgTpmtHa.TPM_ALG_SHA256, equalTo(id));
LOGGER.debug("OK. Parsing of a Crypto Agile Format Success");
} catch (Throwable throwable) {
throw throwable;
}
}
/**
* Tests the processing of a SHA1 formatted Event log.
*
* @throws IOException when processing the test fails
* @throws NoSuchAlgorithmException if an unknown algorithm is encountered.
* @throws CertificateException if a certificate fails to parse.
@ -101,21 +110,24 @@ public class TCGEventLogTest {
public final void testSHA1TCGEventLog() throws IOException, CertificateException,
NoSuchAlgorithmException {
LOGGER.debug("Testing the parsing of a SHA1 formated TCG Event Log");
InputStream log, pcrs;
try {
// setup
final InputStream log = this.getClass().getResourceAsStream(SHA1_EVENT_LOG);
final InputStream pcrs = this.getClass().getResourceAsStream(SHA1_EXPECTED_PCRS);
final byte[] rawLogBytes = IOUtils.toByteArray(log);
final TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
final String[] pcrFromLog = evlog.getExpectedPCRValues();
final Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
final String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
boolean testPass = true;
log = this.getClass().getResourceAsStream(SHA1_EVENT_LOG);
byte[] rawLogBytes = IOUtils.toByteArray(log);
TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
String[] pcrFromLog = evlog.getExpectedPCRValues();
pcrs = this.getClass().getResourceAsStream(SHA1_EXPECTED_PCRS);
Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
// Test 1 get all PCRs
for (int i = 0; i < 24; i++) {
for (int i = 0; i < PCR_COUNT; i++) {
if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) {
testPass = false;
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR " + i);
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR {}", i);
}
}
assertTrue(testPass);
@ -133,6 +145,8 @@ public class TCGEventLogTest {
assertThat(TcgTpmtHa.TPM_ALG_SHA1, equalTo(id));
LOGGER.debug("OK. Parsing of a SHA1 formatted TCG Event Log Success");
} catch (Throwable throwable) {
throw throwable;
}
}
}

View File

@ -0,0 +1 @@
package hirs.utils.tpm.eventlog;

View File

@ -1,5 +1,4 @@
import java.util.concurrent.TimeUnit
import org.gradle.api.tasks.Copy
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
@ -8,7 +7,7 @@ plugins {
}
// Global checkstyle file
ext.checkstyleConfigFile = new File(rootDir, "/config/checkstyle/sun_checks.xml")
ext.checkstyleConfigFile = new File(rootDir, "/config/checkstyle/sun_checks.xml")
subprojects {
apply plugin: "com.github.spotbugs"
@ -19,13 +18,12 @@ subprojects {
tasks.withType(com.github.spotbugs.snom.SpotBugsTask) {
reports {
html {
enabled = true
}
html.required = true
}
}
}
dependencies {
repositories {
// Use Maven Central for resolving dependencies.
@ -36,10 +34,10 @@ dependencies {
def projectVersion = rootProject.file('VERSION').text.trim()
def buildTime = { ->
Date latestdate = new Date();
def time = latestdate.getTime();
long seconds = TimeUnit.MILLISECONDS.toSeconds(time);
return seconds;
Date latestdate = new Date()
def time = latestdate.getTime()
long seconds = TimeUnit.MILLISECONDS.toSeconds(time)
return seconds
}
def gitHash = { ->