Merge pull request #846 from nsacyber/v3_issue_844-update-hirs_utils-for-checkstyle

[#844] Update HIRS/Utils For Checkstyle
This commit is contained in:
iadgovuser26 2024-10-21 10:46:31 -04:00 committed by GitHub
commit d908fda065
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
47 changed files with 1581 additions and 1475 deletions

View File

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

View File

@ -7,22 +7,24 @@ import java.math.BigInteger;
*/ */
public final class HexUtils { public final class HexUtils {
/**
* Default private constructor so checkstyles doesn't complain
*/
private HexUtils() { }
/** /**
* The mathematical base for the hexadecimal representation. * The mathematical base for the hexadecimal representation.
*/ */
public static final int HEX_BASIS = 16; public static final int HEX_BASIS = 16;
/** /**
* An integer representation of the byte 0xff or 255. * An integer representation of the byte 0xff or 255.
*/ */
public static final int FF_BYTE = 0xff; 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. * Converts a binary hex string to a byte array.
*
* @param s string to convert * @param s string to convert
* @return byte array representation of s * @return byte array representation of s
*/ */
@ -40,6 +42,7 @@ public final class HexUtils {
/** /**
* Converts a byte array to a hex represented binary string. * Converts a byte array to a hex represented binary string.
*
* @param b byte array to convert * @param b byte array to convert
* @return hex string representation of array * @return hex string representation of array
*/ */
@ -58,6 +61,7 @@ public final class HexUtils {
/** /**
* Converts an individual hex string to an integer. * Converts an individual hex string to an integer.
*
* @param s an individual hex string * @param s an individual hex string
* @return an integer representation of a hex string * @return an integer representation of a hex string
*/ */
@ -68,9 +72,10 @@ public final class HexUtils {
/** /**
* Takes a byte array returns a subset of the array. * Takes a byte array returns a subset of the array.
* @param b the array to take a subset of *
* @param b the array to take a subset of
* @param start the first index to copy * @param start the first index to copy
* @param end the last index to copy (inclusive) * @param end the last index to copy (inclusive)
* @return a new array of bytes from start to end * @return a new array of bytes from start to end
*/ */
public static byte[] subarray(final byte[] b, final int start, final int end) { public static byte[] subarray(final byte[] b, final int start, final int end) {
@ -81,20 +86,22 @@ public final class HexUtils {
/** /**
* Takes in a byte array and reverses the order. * Takes in a byte array and reverses the order.
* @param in byte array to reverse *
* @param in byte array to reverse
* @return reversed byte array * @return reversed byte array
*/ */
public static byte[] leReverseByte(final byte[] in) { public static byte[] leReverseByte(final byte[] in) {
byte[] finished = new byte[in.length]; byte[] finished = new byte[in.length];
for (int i = 0; i < finished.length; i++) { for (int i = 0; i < finished.length; i++) {
finished[i] = in[(in.length - 1) - i]; finished[i] = in[(in.length - 1) - i];
} }
return finished; return finished;
} }
/** /**
* Takes in a byte array and reverses the order then converts to an int. * Takes in a byte array and reverses the order then converts to an int.
* @param in byte array to reverse *
* @param in byte array to reverse
* @return integer that represents the reversed byte array * @return integer that represents the reversed byte array
*/ */
public static int leReverseInt(final byte[] in) { public static int leReverseInt(final byte[] in) {
@ -104,12 +111,13 @@ public final class HexUtils {
/** /**
* Takes in a byte array of 4 bytes and returns a long. * Takes in a byte array of 4 bytes and returns a long.
* @param bytes byte array to convert *
* @param bytes byte array to convert
* @return long representation of the bytes * @return long representation of the bytes
*/ */
public static long bytesToLong(final byte[] bytes) { public static long bytesToLong(final byte[] bytes) {
BigInteger lValue = new BigInteger(bytes); BigInteger lValue = new BigInteger(bytes);
return lValue.abs().longValue(); return lValue.abs().longValue();
} }
} }

View File

@ -21,16 +21,17 @@ import java.nio.file.Path;
public final class JsonUtils { 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 * Getter for the JSON Object that is associated with the elementName value
* mapped in the associated JSON file. * mapped in the associated JSON file.
* Default {@link java.nio.charset.Charset} is UTF 8 * Default {@link java.nio.charset.Charset} is UTF 8
* *
* @param jsonPath the object holding the location of the file to parse. * @param jsonPath the object holding the location of the file to parse.
* @param elementName the specific object to pull from the file * @param elementName the specific object to pull from the file
* @return a JSON object * @return a JSON object
*/ */
@ -44,9 +45,9 @@ public final class JsonUtils {
* mapped in the associated JSON file. * mapped in the associated JSON file.
* Default {@link java.nio.charset.Charset} is UTF 8 * Default {@link java.nio.charset.Charset} is UTF 8
* *
* @param jsonPath the object holding the location of the file to parse. * @param jsonPath the object holding the location of the file to parse.
* @param elementName the specific object to pull from the file * @param elementName the specific object to pull from the file
* @param charset the character set to use * @param charset the character set to use
* @return a JSON object * @return a JSON object
*/ */
public static JsonObject getSpecificJsonObject(final Path jsonPath, public static JsonObject getSpecificJsonObject(final Path jsonPath,
@ -77,7 +78,7 @@ public final class JsonUtils {
* Getter for the JSON Object that is mapped in the associated JSON file. * Getter for the JSON Object that is mapped in the associated JSON file.
* *
* @param jsonPath the object holding the location of the file to parse. * @param jsonPath the object holding the location of the file to parse.
* @param charset the character set to use * @param charset the character set to use
* @return a JSON object * @return a JSON object
*/ */
public static JsonObject getJsonObject(final Path jsonPath, final Charset charset) { public static JsonObject getJsonObject(final Path jsonPath, final Charset charset) {
@ -85,7 +86,7 @@ public final class JsonUtils {
JsonObject jsonObject = new JsonObject(); JsonObject jsonObject = new JsonObject();
if (Files.notExists(jsonPath)) { if (Files.notExists(jsonPath)) {
log.warn(String.format("No file found at %s.", jsonPath.toString())); log.warn("No file found at {}.", jsonPath.toString());
} else { } else {
try { try {
InputStream inputStream = new FileInputStream(jsonPath.toString()); InputStream inputStream = new FileInputStream(jsonPath.toString());
@ -106,7 +107,7 @@ public final class JsonUtils {
* Default {@link java.nio.charset.Charset} is UTF 8 * Default {@link java.nio.charset.Charset} is UTF 8
* *
* @param jsonFilename the object holding the name of the file in classpath to parse. * @param jsonFilename the object holding the name of the file in classpath to parse.
* @param elementName the specific object to pull from the file * @param elementName the specific object to pull from the file
* @return a JSON object * @return a JSON object
*/ */
public static JsonObject getSpecificJsonObject(final String jsonFilename, final String elementName) { public static JsonObject getSpecificJsonObject(final String jsonFilename, final String elementName) {
@ -120,8 +121,8 @@ public final class JsonUtils {
* Default {@link java.nio.charset.Charset} is UTF 8 * Default {@link java.nio.charset.Charset} is UTF 8
* *
* @param jsonFilename the object holding the name of the file in classpath to parse. * @param jsonFilename the object holding the name of the file in classpath to parse.
* @param elementName the specific object to pull from the file * @param elementName the specific object to pull from the file
* @param charset the character set to use * @param charset the character set to use
* @return a JSON object * @return a JSON object
*/ */
public static JsonObject getSpecificJsonObject(final String jsonFilename, public static JsonObject getSpecificJsonObject(final String jsonFilename,
@ -152,7 +153,7 @@ public final class JsonUtils {
* Getter for the JSON Object that is mapped in the associated JSON file. * Getter for the JSON Object that is mapped in the associated JSON file.
* *
* @param jsonFilename the object holding the name of the file in classpath to parse. * @param jsonFilename the object holding the name of the file in classpath to parse.
* @param charset the character set to use * @param charset the character set to use
* @return a JSON object * @return a JSON object
*/ */
public static JsonObject getJsonObject(final String jsonFilename, final Charset charset) { public static JsonObject getJsonObject(final String jsonFilename, final Charset charset) {

View File

@ -25,29 +25,24 @@ import java.util.List;
@Log4j2 @Log4j2
public final class PciIds { 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. * This pci ids file can be in different places on different distributions.
*/ */
public static final List<String> PCI_IDS_PATH = public static final List<String> PCI_IDS_PATH =
Collections.unmodifiableList(new ArrayList<>() { Collections.unmodifiableList(new ArrayList<>() {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
{ {
add("/usr/share/hwdata/pci.ids"); add("/usr/share/hwdata/pci.ids");
add("/usr/share/misc/pci.ids"); add("/usr/share/misc/pci.ids");
add("/tmp/pci.ids"); add("/tmp/pci.ids");
} }
}); });
/** /**
* The PCI IDs Database object. * The PCI IDs Database object.
* * <p>
* This only needs to be loaded one time. * This only needs to be loaded one time.
* * <p>
* The pci ids library protects the data inside the object by making it immutable. * The pci ids library protects the data inside the object by making it immutable.
*/ */
public static final PciIdsDatabase DB = new PciIdsDatabase(); public static final PciIdsDatabase DB = new PciIdsDatabase();
@ -65,7 +60,7 @@ public final class PciIds {
if (dbFile != null) { if (dbFile != null) {
InputStream is = null; InputStream is = null;
try { try {
is = new FileInputStream(new File(dbFile)); is = new FileInputStream(dbFile);
DB.loadStream(is); DB.loadStream(is);
} catch (IOException e) { } catch (IOException e) {
// DB will not be ready, hardware IDs will not be translated // 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. * 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. * If any part of this fails, return the original manufacturer value.
*
* @param refManufacturer DERUTF8String, likely from a ComponentIdentifier * @param refManufacturer DERUTF8String, likely from a ComponentIdentifier
* @return DERUTF8String with the discovered vendor name, or the original manufacturer value. * @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. * 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. * If any part of this fails, return the original manufacturer value.
*
* @param refManufacturer String, likely from a ComponentResult * @param refManufacturer String, likely from a ComponentResult
* @return String with the discovered vendor name, or the original manufacturer value. * @return String with the discovered vendor name, or the original manufacturer value.
*/ */
@ -121,8 +124,9 @@ public final class PciIds {
* Look up the device name from the PCI IDs list, if the input strings contain IDs. * 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. * 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. * If any part of this fails, return the original model value.
*
* @param refManufacturer ASN1UTF8String, likely from a ComponentIdentifier * @param refManufacturer ASN1UTF8String, likely from a ComponentIdentifier
* @param refModel ASN1UTF8String, likely from a ComponentIdentifier * @param refModel ASN1UTF8String, likely from a ComponentIdentifier
* @return ASN1UTF8String with the discovered device name, or the original model value. * @return ASN1UTF8String with the discovered device name, or the original model value.
*/ */
public static ASN1UTF8String translateDevice(final ASN1UTF8String refManufacturer, public static ASN1UTF8String translateDevice(final ASN1UTF8String refManufacturer,
@ -146,8 +150,9 @@ public final class PciIds {
* Look up the device name from the PCI IDs list, if the input strings contain IDs. * 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. * 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. * If any part of this fails, return the original model value.
*
* @param refManufacturer String, likely from a ComponentResult * @param refManufacturer String, likely from a ComponentResult
* @param refModel String, likely from a ComponentResult * @param refModel String, likely from a ComponentResult
* @return String with the discovered device name, or the original model value. * @return String with the discovered device name, or the original model value.
*/ */
public static String translateDevice(final String refManufacturer, public static String translateDevice(final String refManufacturer,
@ -169,24 +174,39 @@ public final class PciIds {
/** /**
* Look up the device class name from the PCI IDs list, if the input string contains an ID. * 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. * 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 * @param refClassCode String, formatted as 2 characters (1 byte) for each of the 3 categories
* Example "010802": * Example "010802":
* Class: "01" * Class: "01"
* Subclass: "08" * Subclass: "08"
* Programming Interface: "02" * Programming Interface: "02"
* @return List<String> 3-element list with the class code * @return List<String> 3-element list with the class code
* 1st element: human-readable description of Class * 1st element: human-readable description of Class
* 2nd element: human-readable description of Subclass * 2nd element: human-readable description of Subclass
* 3rd element: human-readable description of Programming Interface * 3rd element: human-readable description of Programming Interface
*/ */
public static List<String> translateDeviceClass(final String refClassCode) { public static List<String> translateDeviceClass(final String refClassCode) {
List<String> translatedClassCode = new ArrayList<>(); List<String> translatedClassCode = new ArrayList<>();
String classCode = refClassCode; String classCode = refClassCode;
if (classCode != null && classCode.trim().matches("^[0-9A-Fa-f]{6}$")) { if (classCode != null && classCode.trim().matches("^[0-9A-Fa-f]{6}$")) {
String deviceClass = classCode.substring(0, 2).toLowerCase(); final int startIndexOfDeviceClass = 0;
String deviceSubclass = classCode.substring(2, 4).toLowerCase(); final int endIndexOfDeviceClass = 2;
String programInterface = classCode.substring(4, 6).toLowerCase(); 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(deviceClass);
translatedClassCode.add(deviceSubclass); translatedClassCode.add(deviceSubclass);
translatedClassCode.add(programInterface); translatedClassCode.add(programInterface);

View File

@ -18,15 +18,31 @@ import java.util.Map;
@ToString @ToString
public class SwidResource { public class SwidResource {
@Getter
private static final boolean VALID_FILE_SIZE = false;
@Getter @Getter
@Setter @Setter
private String name, size, hashValue; private String name;
@Getter @Getter
private String rimFormat, rimType, rimUriGlobal; @Setter
// private TpmWhiteListBaseline tpmWhiteList; 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; private DigestAlgorithm digest = DigestAlgorithm.SHA1;
@Getter
private boolean validFileSize = false;
/** /**
* Default constructor. * Default constructor.
@ -43,7 +59,7 @@ public class SwidResource {
/** /**
* The main constructor that processes a {@code hirs.utils.xjc.File}. * The main constructor that processes a {@code hirs.utils.xjc.File}.
* *
* @param file {@link File} * @param file {@link File}
* @param digest algorithm associated with pcr values * @param digest algorithm associated with pcr values
*/ */
public SwidResource(final File file, final DigestAlgorithm digest) { public SwidResource(final File file, final DigestAlgorithm digest) {
@ -81,4 +97,4 @@ public class SwidResource {
this.digest = digest; this.digest = digest;
// tpmWhiteList = new TpmWhiteListBaseline(this.name); // tpmWhiteList = new TpmWhiteListBaseline(this.name);
} }
} }

View File

@ -15,8 +15,8 @@ import java.util.regex.Pattern;
* <p> * <p>
* Two classes were made to facilitate persisting them with Hibernate in different ways. * 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 * 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} * {@link TPMBaseline} for reference.) To persist nullable entries,
* (see {@link ImaBlacklistRecord} for reference.) * use {@link hirs.utils.digest.OptionalDigest} (see {@link ImaBlacklistRecord} for reference.)
*/ */
@Log4j2 @Log4j2
public abstract class AbstractDigest { public abstract class AbstractDigest {
@ -45,30 +45,6 @@ public abstract class AbstractDigest {
*/ */
public static final int SHA512_DIGEST_LENGTH = 64; 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 * This method will help class determine the algorithm associated with the
* pcr values given. * pcr values given.
@ -114,6 +90,61 @@ public abstract class AbstractDigest {
return DigestAlgorithm.UNSPECIFIED; 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 * Retrieves the <code>DigestAlgorithm</code> that identifies which hash
* function generated the digest. * function generated the digest.
@ -140,6 +171,7 @@ public abstract class AbstractDigest {
/** /**
* Compares this digest's hash with another digest's hash. * Compares this digest's hash with another digest's hash.
*
* @param otherDigest a Digest to compare to. * @param otherDigest a Digest to compare to.
* @return the comparison result type. * @return the comparison result type.
*/ */
@ -155,37 +187,6 @@ public abstract class AbstractDigest {
return DigestComparisonResultType.MISMATCH; 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 @Override
public final int hashCode() { public final int hashCode() {
final int prime = 31; final int prime = 31;
@ -201,21 +202,15 @@ public abstract class AbstractDigest {
return true; return true;
} }
if (obj == null || !(obj instanceof AbstractDigest)) { if (obj == null || !(obj instanceof AbstractDigest other)) {
return false; return false;
} }
AbstractDigest other = (AbstractDigest) obj;
if (getAlgorithm() != other.getAlgorithm()) { if (getAlgorithm() != other.getAlgorithm()) {
return false; return false;
} }
if (!Arrays.equals(getDigest(), other.getDigest())) { return Arrays.equals(getDigest(), other.getDigest());
return false;
}
return true;
} }
/** /**

View File

@ -50,12 +50,11 @@ public enum DigestAlgorithm {
* options for standardAlgorithmName. Throws an IllegalArgumentException if no Enum exists with * options for standardAlgorithmName. Throws an IllegalArgumentException if no Enum exists with
* that value. * that value.
* *
* @param standardAlgorithmName * @param standardAlgorithmName String value of the Enum
* String value of the Enum
* @return DigestAlgorithm object * @return DigestAlgorithm object
*/ */
public static DigestAlgorithm findByString(final String standardAlgorithmName) { public static DigestAlgorithm findByString(final String standardAlgorithmName) {
for (DigestAlgorithm algorithm: DigestAlgorithm.values()) { for (DigestAlgorithm algorithm : DigestAlgorithm.values()) {
if (algorithm.getStandardAlgorithmName().equals(standardAlgorithmName)) { if (algorithm.getStandardAlgorithmName().equals(standardAlgorithmName)) {
return algorithm; return algorithm;
} }
@ -63,4 +62,4 @@ public enum DigestAlgorithm {
throw new IllegalArgumentException(String.format("No constant with text \"%s\" found", throw new IllegalArgumentException(String.format("No constant with text \"%s\" found",
standardAlgorithmName)); standardAlgorithmName));
} }
} }

View File

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

View File

@ -2,11 +2,6 @@ package hirs.utils.enums;
public final class DeviceInfoEnums { 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. * 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. * Constant variable representing the various Long sized strings.
*/ */
public static final int LONG_STRING_LENGTH = 255; 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.JAXBException;
import jakarta.xml.bind.UnmarshalException; import jakarta.xml.bind.UnmarshalException;
import jakarta.xml.bind.Unmarshaller; import jakarta.xml.bind.Unmarshaller;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2; import lombok.extern.log4j.Log4j2;
import org.bouncycastle.asn1.x509.Extension; import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.jcajce.provider.asymmetric.X509;
import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Element; import org.w3c.dom.Element;
@ -47,7 +48,7 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
@ -86,105 +87,29 @@ public class ReferenceManifestValidator {
private Document rim; private Document rim;
private Unmarshaller unmarshaller; private Unmarshaller unmarshaller;
@Getter
private PublicKey publicKey; private PublicKey publicKey;
private Schema schema; private Schema schema;
@Getter
private String subjectKeyIdentifier; private String subjectKeyIdentifier;
@Setter
private String rimEventLog; private String rimEventLog;
@Setter
private String trustStoreFile; private String trustStoreFile;
@Setter
private List<X509Certificate> trustStore; private List<X509Certificate> trustStore;
private boolean signatureValid, supportRimValid;
/** @Getter
* Setter for the RIM to be validated. The ReferenceManifest object is converted into a private boolean signatureValid;
* 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
* Setter for the swidtag XML to be validated. The XML is passed in via a filepath private boolean supportRimValid;
* 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;
}
/** /**
* This default constructor creates the Schema object from SCHEMA_URL immediately to save * This default constructor creates the Schema object from SCHEMA_URL immediately to save
@ -209,15 +134,47 @@ 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 * 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 * using a given cert. The cert is compared to either the RIM's embedded certificate
* or the RIM's subject key identifier. If the cert is matched then validation proceeds, * or the RIM's subject key identifier. If the cert is matched then validation proceeds,
* otherwise validation ends. * otherwise validation ends.
* *
* @param publicKey public key from the CA credential * @param publicKey public key from the CA credential
* @param subjectKeyIdString string version of the subjet key id of the CA credential * @param subjectKeyIdString string version of the subjet key id of the CA credential
* @param encodedPublicKey the encoded public key * @param encodedPublicKey the encoded public key
* @return true if the signature element is validated, false otherwise * @return true if the signature element is validated, false otherwise
*/ */
@SuppressWarnings("magicnumber") @SuppressWarnings("magicnumber")
@ -257,7 +214,7 @@ public class ReferenceManifestValidator {
return signatureValid; return signatureValid;
} }
} catch (IOException e) { } catch (IOException e) {
log.warn("Error while parsing certificate data: " + e.getMessage()); log.warn("Error while parsing certificate data: {}", e.getMessage());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -267,26 +224,27 @@ public class ReferenceManifestValidator {
/** /**
* This method validates the rim with a public key cert. * This method validates the rim with a public key cert.
*
* @param signingCertPath to the public key certificate used to sign the rim * @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 * @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( Element fileElement = (Element) rim.getElementsByTagNameNS(
SwidTagConstants.SWIDTAG_NAMESPACE, "File").item(0); SwidTagConstants.SWIDTAG_NAMESPACE, "File").item(0);
X509Certificate signingCert = parseCertificatesFromPem(signingCertPath).get(0); X509Certificate signingCert = parseCertificatesFromPem(signingCertPath).get(0);
if (signingCert == null) { if (signingCert == null) {
return failWithError("Unable to parse the signing cert from " + signingCertPath); return failWithError("Unable to parse the signing cert from " + signingCertPath);
} }
String subjectKeyIdentifier = ""; String retrievedSubjectKeyIdentifier = "";
try { try {
subjectKeyIdentifier = getCertificateSubjectKeyIdentifier(signingCert); retrievedSubjectKeyIdentifier = getCertificateSubjectKeyIdentifier(signingCert);
} catch (IOException e) { } catch (IOException e) {
return failWithError("Error while parsing SKID: " + e.getMessage()); return failWithError("Error while parsing SKID: " + e.getMessage());
} }
boolean isSignatureValid = validateXmlSignature(signingCert.getPublicKey(), boolean isSignatureValid = validateXmlSignature(signingCert.getPublicKey(),
subjectKeyIdentifier, retrievedSubjectKeyIdentifier,
signingCert.getPublicKey().getEncoded()); signingCert.getPublicKey().getEncoded());
return isSignatureValid && validateFile(fileElement); return isSignatureValid && validateFile(fileElement);
} }
@ -301,13 +259,15 @@ public class ReferenceManifestValidator {
String calculatedHash = getHashValue(input, SHA256); String calculatedHash = getHashValue(input, SHA256);
supportRimValid = calculatedHash.equals(expected); supportRimValid = calculatedHash.equals(expected);
if (!supportRimValid) { if (!supportRimValid) {
log.info("Unmatched support RIM hash! Expected: " + expected log.info("Unmatched support RIM hash! Expected: {}, actual: {}", expected, calculatedHash);
+ ", actual: " + 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) { private boolean validateFile(final Element file) {
String filepath; String filepath;
@ -317,9 +277,9 @@ public class ReferenceManifestValidator {
filepath = file.getAttribute(SwidTagConstants.NAME); filepath = file.getAttribute(SwidTagConstants.NAME);
} }
if (getHashValue(filepath, "SHA256").equals( if (getHashValue(filepath, "SHA256").equals(
file.getAttribute(SwidTagConstants._SHA256_HASH.getPrefix() + ":" + file.getAttribute(SwidTagConstants._SHA256_HASH.getPrefix() + ":"
SwidTagConstants._SHA256_HASH.getLocalPart()))) { + SwidTagConstants._SHA256_HASH.getLocalPart()))) {
log.info("Support RIM hash verified for " + filepath); log.info("Support RIM hash verified for {}", filepath);
return true; return true;
} else { } else {
return failWithError("Support RIM hash does not match Base RIM!"); return failWithError("Support RIM hash does not match Base RIM!");
@ -333,10 +293,10 @@ public class ReferenceManifestValidator {
* @return X509Certificate signing cert * @return X509Certificate signing cert
*/ */
private X509Certificate getCertFromTruststore() throws IOException { private X509Certificate getCertFromTruststore() throws IOException {
String subjectKeyIdentifier = getKeyName(rim); String retrievedSubjectKeyIdentifier = getKeyName(rim);
for (X509Certificate trustedCert : trustStore) { for (X509Certificate trustedCert : trustStore) {
String trustedSubjectKeyIdentifier = getCertificateSubjectKeyIdentifier(trustedCert); String trustedSubjectKeyIdentifier = getCertificateSubjectKeyIdentifier(trustedCert);
if (subjectKeyIdentifier.equals(trustedSubjectKeyIdentifier)) { if (retrievedSubjectKeyIdentifier.equals(trustedSubjectKeyIdentifier)) {
return trustedCert; return trustedCert;
} }
} }
@ -345,10 +305,10 @@ 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 filepath the file to hash
* @param sha the algorithm to use * @param sha the algorithm to use
* @return String digest * @return String digest
*/ */
private String getHashValue(final String filepath, final String sha) { private String getHashValue(final String filepath, final String sha) {
@ -359,11 +319,12 @@ public class ReferenceManifestValidator {
} catch (NoSuchAlgorithmException e) { } catch (NoSuchAlgorithmException e) {
log.warn(e.getMessage()); log.warn(e.getMessage());
} catch (IOException e) { } catch (IOException e) {
log.warn("Error reading " + filepath + " for hashing: " + e.getMessage()); log.warn("Error reading {} for hashing: {}", filepath, e.getMessage());
} }
return null; return null;
} }
/** /**
* This method calculates the digest of a byte array based on the hashing algorithm passed in. * 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); whySignatureInvalid(signature, context);
} }
} catch (MarshalException e) { } catch (MarshalException e) {
log.warn("Error while unmarshalling XML signature: " + e.getMessage()); log.warn("Error while unmarshalling XML signature: {}", e.getMessage());
} catch (XMLSignatureException e) { } catch (XMLSignatureException e) {
log.warn("Error while validating XML signature: " + e.getMessage()); log.warn("Error while validating XML signature: {}", e.getMessage());
} }
return false; return false;
@ -415,11 +376,11 @@ public class ReferenceManifestValidator {
* results are logged. * results are logged.
* *
* @param signature the signature that failed to validate * @param signature the signature that failed to validate
* @param context the context used for validation * @param context the context used for validation
* @throws XMLSignatureException * @throws XMLSignatureException
*/ */
private void whySignatureInvalid(final XMLSignature signature, final DOMValidateContext context) private void whySignatureInvalid(final XMLSignature signature, final DOMValidateContext context)
throws XMLSignatureException{ throws XMLSignatureException {
boolean cryptoValidity = signature.getSignatureValue().validate(context); boolean cryptoValidity = signature.getSignatureValue().validate(context);
if (cryptoValidity) { if (cryptoValidity) {
log.error("Signature value is valid."); log.error("Signature value is valid.");
@ -435,9 +396,9 @@ public class ReferenceManifestValidator {
refUri = "whole document"; refUri = "whole document";
} }
if (refValidity) { if (refValidity) {
log.error("Reference for " + refUri + " is valid."); log.error("Reference for {} is valid.", refUri);
} else { } 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 * 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. * over until a root CA is found, otherwise an error is returned.
*
* @param cert the certificate at the start of the chain * @param cert the certificate at the start of the chain
* @return true if the chain is valid * @return true if the chain is valid
* @throws Exception if a valid chain is not found in the truststore * @throws Exception if a valid chain is not found in the truststore
@ -462,7 +424,7 @@ public class ReferenceManifestValidator {
boolean isChainCertValid; boolean isChainCertValid;
do { do {
isChainCertValid = false; isChainCertValid = false;
log.info("Validating " + chainCert.getSubjectX500Principal().getName()); log.info("Validating {}", chainCert.getSubjectX500Principal().getName());
for (X509Certificate trustedCert : trustStore) { for (X509Certificate trustedCert : trustStore) {
boolean isIssuer = areYouMyIssuer(chainCert, trustedCert); boolean isIssuer = areYouMyIssuer(chainCert, trustedCert);
boolean isSigner = areYouMySigner(chainCert, trustedCert); boolean isSigner = areYouMySigner(chainCert, trustedCert);
@ -490,14 +452,15 @@ public class ReferenceManifestValidator {
} }
} while (isChainCertValid); } while (isChainCertValid);
log.error("CA chain validation failed to validate " log.error("CA chain validation failed to validate {}, {}",
+ chainCert.getSubjectX500Principal().getName() + ", " + errorMessage); chainCert.getSubjectX500Principal().getName(), errorMessage);
return false; return false;
} }
/** /**
* This method checks if cert's issuerDN matches issuer's subjectDN. * This method checks if cert's issuerDN matches issuer's subjectDN.
* @param cert the signed certificate *
* @param cert the signed certificate
* @param issuer the signing certificate * @param issuer the signing certificate
* @return true if they match, false if not * @return true if they match, false if not
* @throws Exception if either argument is null * @throws Exception if either argument is null
@ -512,7 +475,8 @@ public class ReferenceManifestValidator {
/** /**
* This method checks if cert's issuerDN matches issuer's subjectDN. * This method checks if cert's issuerDN matches issuer's subjectDN.
* @param cert the signed certificate *
* @param cert the signed certificate
* @param issuer the signing certificate * @param issuer the signing certificate
* @return true if they match, false if not * @return true if they match, false if not
* @throws Exception if either argument is null * @throws Exception if either argument is null
@ -528,7 +492,8 @@ public class ReferenceManifestValidator {
/** /**
* This method checks if cert's signature matches signer's public key. * This method checks if cert's signature matches signer's public key.
* @param cert the signed certificate *
* @param cert the signed certificate
* @param signer the signing certificate * @param signer the signing certificate
* @return true if they match * @return true if they match
* @throws Exception if an error occurs or there is no match * @throws Exception if an error occurs or there is no match
@ -562,6 +527,7 @@ public class ReferenceManifestValidator {
/** /**
* This method checks if a given certificate is self signed or not. * This method checks if a given certificate is self signed or not.
*
* @param cert the cert to check * @param cert the cert to check
* @return true if self signed, false if not * @return true if self signed, false if not
*/ */
@ -569,128 +535,6 @@ public class ReferenceManifestValidator {
return cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal()); 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 * 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 * PEM format, and a header and footer are concatenated with the input string to
@ -709,12 +553,10 @@ public class ReferenceManifestValidator {
+ System.lineSeparator() + System.lineSeparator()
+ pemString + pemString
+ System.lineSeparator() + System.lineSeparator()
+ certificateFooter).getBytes("UTF-8")); + certificateFooter).getBytes(StandardCharsets.UTF_8));
return (X509Certificate) factory.generateCertificate(inputStream); return (X509Certificate) factory.generateCertificate(inputStream);
} catch (CertificateException e) { } catch (CertificateException e) {
log.warn("Error creating CertificateFactory instance: " + e.getMessage()); log.warn("Error creating CertificateFactory instance: {}", e.getMessage());
} catch (UnsupportedEncodingException e) {
log.warn("Error while parsing cert from PEM string: " + e.getMessage());
} }
return null; return null;
@ -724,11 +566,12 @@ public class ReferenceManifestValidator {
* This method returns the X509Certificates found in a PEM file. * This method returns the X509Certificates found in a PEM file.
* Unchecked type case warnings are suppressed because the CertificateFactory * Unchecked type case warnings are suppressed because the CertificateFactory
* implements X509Certificate objects explicitly. * implements X509Certificate objects explicitly.
*
* @param filename pem file * @param filename pem file
* @return a list containing all X509Certificates extracted * @return a list containing all X509Certificates extracted
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private List<X509Certificate> parseCertificatesFromPem(String filename) { private List<X509Certificate> parseCertificatesFromPem(final String filename) {
List<X509Certificate> certificates = null; List<X509Certificate> certificates = null;
FileInputStream fis = null; FileInputStream fis = null;
BufferedInputStream bis = null; BufferedInputStream bis = null;
@ -742,14 +585,14 @@ public class ReferenceManifestValidator {
(List<X509Certificate>) certificateFactory.generateCertificates(bis); (List<X509Certificate>) certificateFactory.generateCertificates(bis);
} }
if (certificates.size() < 1) { if (certificates.isEmpty()) {
System.out.println("ERROR: No certificates parsed from " + filename); System.out.println("ERROR: No certificates parsed from " + filename);
} }
bis.close(); bis.close();
} catch (CertificateException e) { } catch (CertificateException e) {
log.error("Error in certificate factory: " + e.getMessage()); log.error("Error in certificate factory: {}", e.getMessage());
} catch (IOException e) { } catch (IOException e) {
log.error("Error reading from input stream: " + e.getMessage()); log.error("Error reading from input stream: {}", e.getMessage());
} finally { } finally {
try { try {
if (fis != null) { if (fis != null) {
@ -759,7 +602,7 @@ public class ReferenceManifestValidator {
bis.close(); bis.close();
} }
} catch (IOException e) { } 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. * This method logs an error message and returns a false to signal failed validation.
*
* @param errorMessage String description of what went wrong * @param errorMessage String description of what went wrong
* @return false to represent failed validation * @return false to represent failed validation
*/ */
private boolean failWithError(String errorMessage) { private boolean failWithError(final String errorMessage) {
log.error(errorMessage); log.error(errorMessage);
return false; 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 * class. It is expected that member properties of this class will expand as
* more functionality is added to SwidTagGateway. * more functionality is added to SwidTagGateway.
*/ */
public class SwidTagConstants { public final class SwidTagConstants {
/** public static final String DEFAULT_KEYSTORE_FILE = "keystore.jks"; //"/opt/hirs/rimtool/keystore.jks";
* 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_PASSWORD = "password"; public static final String DEFAULT_KEYSTORE_PASSWORD = "password";
public static final String DEFAULT_PRIVATE_KEY_ALIAS = "1"; 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_ATTRIBUTES_FILE = "/opt/hirs/rimtool/rim_fields.json";
public static final String DEFAULT_ENGLISH = "en"; public static final String DEFAULT_ENGLISH = "en";
public static final String SIGNATURE_ALGORITHM_RSA_SHA256 =
public static final String SIGNATURE_ALGORITHM_RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#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_PACKAGE = "hirs.swid.xjc";
public static final String SCHEMA_LANGUAGE = XMLConstants.W3C_XML_SCHEMA_NS_URI; 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 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 SWIDTAG_NAMESPACE = "http://standards.iso.org/iso/19770/-2/2015/schema.xsd";
public static final String SOFTWARE_IDENTITY = "SoftwareIdentity"; public static final String SOFTWARE_IDENTITY = "SoftwareIdentity";
public static final String ENTITY = "Entity"; public static final String ENTITY = "Entity";
public static final String LINK = "Link"; 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_FORMAT_MISSING = "supportRIMFormat missing";
public static final String SUPPORT_RIM_URI_GLOBAL = "supportRIMURIGlobal"; public static final String SUPPORT_RIM_URI_GLOBAL = "supportRIMURIGlobal";
public static final String DATETIME = "dateTime"; 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 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 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 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 RFC3339_NS = "https://www.ietf.org/rfc/rfc3339.txt";
public static final String N8060_PFX = "n8060"; public static final String N8060_PFX = "n8060";
public static final String RIM_PFX = "rim"; public static final String RIM_PFX = "rim";
public static final String FX_SEPARATOR = ":"; public static final String FX_SEPARATOR = ":";
public static final String RFC3852_PFX = "rcf3852"; public static final String RFC3852_PFX = "rcf3852";
public static final String RFC3339_PFX = "rcf3339"; public static final String RFC3339_PFX = "rcf3339";
public static final String _COLLOQUIAL_VERSION_STR = N8060_PFX + FX_SEPARATOR
public static final String _COLLOQUIAL_VERSION_STR = N8060_PFX + FX_SEPARATOR + + COLLOQUIAL_VERSION;
COLLOQUIAL_VERSION; public static final String _PRODUCT_STR = N8060_PFX + FX_SEPARATOR
public static final String _PRODUCT_STR = N8060_PFX + FX_SEPARATOR + + PRODUCT;
PRODUCT; public static final String _REVISION_STR = N8060_PFX + FX_SEPARATOR
public static final String _REVISION_STR = N8060_PFX + FX_SEPARATOR + + REVISION;
REVISION; public static final String _EDITION_STR = N8060_PFX + FX_SEPARATOR
public static final String _EDITION_STR = N8060_PFX + FX_SEPARATOR + + EDITION;
EDITION; public static final String _RIM_LINK_HASH_STR = RIM_PFX + FX_SEPARATOR
public static final String _RIM_LINK_HASH_STR = RIM_PFX + FX_SEPARATOR + + RIM_LINK_HASH;
RIM_LINK_HASH; public static final String _BINDING_SPEC_STR = RIM_PFX + FX_SEPARATOR
public static final String _BINDING_SPEC_STR = RIM_PFX + FX_SEPARATOR + + BINDING_SPEC;
BINDING_SPEC; public static final String _BINDING_SPEC_VERSION_STR = RIM_PFX + FX_SEPARATOR
public static final String _BINDING_SPEC_VERSION_STR = RIM_PFX + FX_SEPARATOR + + BINDING_SPEC_VERSION;
BINDING_SPEC_VERSION; public static final String _PLATFORM_MANUFACTURER_STR = RIM_PFX + FX_SEPARATOR
public static final String _PLATFORM_MANUFACTURER_STR = RIM_PFX + FX_SEPARATOR + + PLATFORM_MANUFACTURER_STR;
PLATFORM_MANUFACTURER_STR; public static final String _PLATFORM_MANUFACTURER_ID_STR = RIM_PFX + FX_SEPARATOR
public static final String _PLATFORM_MANUFACTURER_ID_STR = RIM_PFX + FX_SEPARATOR + + PLATFORM_MANUFACTURER_ID;
PLATFORM_MANUFACTURER_ID; public static final String _PLATFORM_MODEL_STR = RIM_PFX + FX_SEPARATOR
public static final String _PLATFORM_MODEL_STR = RIM_PFX + FX_SEPARATOR + + PLATFORM_MODEL;
PLATFORM_MODEL; public static final String _PLATFORM_VERSION_STR = RIM_PFX + FX_SEPARATOR
public static final String _PLATFORM_VERSION_STR = RIM_PFX + FX_SEPARATOR + + PLATFORM_VERSION;
PLATFORM_VERSION; public static final String _PAYLOAD_TYPE_STR = RIM_PFX + FX_SEPARATOR
public static final String _PAYLOAD_TYPE_STR = RIM_PFX + FX_SEPARATOR + + PAYLOAD_TYPE;
PAYLOAD_TYPE; public static final String _PC_URI_LOCAL_STR = RIM_PFX + FX_SEPARATOR
public static final String _PC_URI_LOCAL_STR = RIM_PFX + FX_SEPARATOR + + PC_URI_LOCAL;
PC_URI_LOCAL; public static final String _PC_URI_GLOBAL_STR = RIM_PFX + FX_SEPARATOR
public static final String _PC_URI_GLOBAL_STR = RIM_PFX + FX_SEPARATOR + + PC_URI_GLOBAL;
PC_URI_GLOBAL;
public static final QName _SHA256_HASH = new QName( public static final QName _SHA256_HASH = new QName(
"http://www.w3.org/2001/04/xmlenc#sha256", HASH, "SHA256"); "http://www.w3.org/2001/04/xmlenc#sha256", HASH, "SHA256");
public static final QName _COLLOQUIAL_VERSION = new QName( public static final QName _COLLOQUIAL_VERSION = new QName(
@ -168,6 +156,11 @@ public class SwidTagConstants {
NIST_NS, "envVarSuffix", N8060_PFX); NIST_NS, "envVarSuffix", N8060_PFX);
public static final QName _N8060_PATHSEPARATOR = new QName( public static final QName _N8060_PATHSEPARATOR = new QName(
NIST_NS, "pathSeparator", N8060_PFX); NIST_NS, "pathSeparator", N8060_PFX);
public static final String CA_ISSUERS = "1.3.6.1.5.5.7.48.2"; 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,18 +13,18 @@ import java.io.IOException;
* Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER. * Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER.
* DEVICE_SECURITY_EVENT_DATA_HEADER contains the measurement(s) and hash algorithm identifier * DEVICE_SECURITY_EVENT_DATA_HEADER contains the measurement(s) and hash algorithm identifier
* returned by the SPDM "GET_MEASUREMENTS" function. * returned by the SPDM "GET_MEASUREMENTS" function.
* * <p>
* HEADERS defined by PFP v1.06 Rev 52: * HEADERS defined by PFP v1.06 Rev 52:
* <p> * <p>
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER { * typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER {
* UINT8 Signature[16]; * UINT8 Signature[16];
* UINT16 Version; * UINT16 Version;
* UINT16 Length; * UINT16 Length;
* UINT32 SpdmHashAlg; * UINT32 SpdmHashAlg;
* UINT32 DeviceType; * UINT32 DeviceType;
* SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock; * SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock;
* UINT64 DevicePathLength; * UINT64 DevicePathLength;
* UNIT8 DevicePath[DevicePathLength] * UNIT8 DevicePath[DevicePathLength]
* } DEVICE_SECURITY_EVENT_DATA_HEADER; * } DEVICE_SECURITY_EVENT_DATA_HEADER;
* <p> * <p>
* Assumption: there is only 1 SpdmMeasurementBlock per event. Need more test patterns to verify. * Assumption: there is only 1 SpdmMeasurementBlock per event. Need more test patterns to verify.
@ -62,8 +62,9 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
super(dsedBytes); super(dsedBytes);
final int dsedBytesSrcIndex1 = 18;
byte[] lengthBytes = new byte[UefiConstants.SIZE_2]; byte[] lengthBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(dsedBytes, 18, lengthBytes, 0, System.arraycopy(dsedBytes, dsedBytesSrcIndex1, lengthBytes, 0,
UefiConstants.SIZE_2); UefiConstants.SIZE_2);
length = HexUtils.leReverseInt(lengthBytes); length = HexUtils.leReverseInt(lengthBytes);
@ -72,18 +73,22 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
UefiConstants.SIZE_4); UefiConstants.SIZE_4);
spdmHashAlgo = HexUtils.leReverseInt(spdmHashAlgoBytes); spdmHashAlgo = HexUtils.leReverseInt(spdmHashAlgoBytes);
extractDeviceType(dsedBytes, 24); final int dsedBytesStartByte = 24;
extractDeviceType(dsedBytes, dsedBytesStartByte);
// get the size of the SPDM Measurement Block // get the size of the SPDM Measurement Block
final int dsedBytesSrcIndex2 = 30;
byte[] sizeOfSpdmMeasBlockBytes = new byte[UefiConstants.SIZE_2]; byte[] sizeOfSpdmMeasBlockBytes = new byte[UefiConstants.SIZE_2];
System.arraycopy(dsedBytes, 30, sizeOfSpdmMeasBlockBytes, 0, System.arraycopy(dsedBytes, dsedBytesSrcIndex2, sizeOfSpdmMeasBlockBytes, 0,
UefiConstants.SIZE_2); UefiConstants.SIZE_2);
int sizeOfSpdmMeas = HexUtils.leReverseInt(sizeOfSpdmMeasBlockBytes); final int sizeOfSpdmMeas = HexUtils.leReverseInt(sizeOfSpdmMeasBlockBytes);
int sizeOfSpdmMeasBlock = sizeOfSpdmMeas + 4; // header is 4 bytes final int offSetBytesForSpdm = 4;
final int sizeOfSpdmMeasBlock = sizeOfSpdmMeas + offSetBytesForSpdm; // header is 4 bytes
// extract the bytes that comprise the SPDM Measurement Block // extract the bytes that comprise the SPDM Measurement Block
final int dsedBytesSrcIndex3 = 28;
byte[] spdmMeasBlockBytes = new byte[sizeOfSpdmMeasBlock]; byte[] spdmMeasBlockBytes = new byte[sizeOfSpdmMeasBlock];
System.arraycopy(dsedBytes, 28, spdmMeasBlockBytes, 0, System.arraycopy(dsedBytes, dsedBytesSrcIndex3, spdmMeasBlockBytes, 0,
sizeOfSpdmMeasBlock); sizeOfSpdmMeasBlock);
ByteArrayInputStream spdmMeasurementBlockData = ByteArrayInputStream spdmMeasurementBlockData =
@ -96,7 +101,8 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
spdmMeasurementBlockInfo = " Error reading SPDM Measurement Block"; spdmMeasurementBlockInfo = " Error reading SPDM Measurement Block";
} }
int devPathLenStartByte = 28 + sizeOfSpdmMeasBlock; final int offSetBytesForDevPath = 28;
final int devPathLenStartByte = offSetBytesForDevPath + sizeOfSpdmMeasBlock;
extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte); extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte);
} }

View File

@ -7,26 +7,52 @@ import lombok.Getter;
* Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER2. * Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER2.
* DEVICE_SECURITY_EVENT_DATA_HEADER2 contains the measurement(s) and hash algorithm identifier * DEVICE_SECURITY_EVENT_DATA_HEADER2 contains the measurement(s) and hash algorithm identifier
* returned by the SPDM "GET_MEASUREMENTS" function. * returned by the SPDM "GET_MEASUREMENTS" function.
* * <p>
* HEADERS defined by PFP v1.06 Rev 52: * HEADERS defined by PFP v1.06 Rev 52:
* <p> * <p>
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER2 { * typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER2 {
* UINT8 Signature[16]; * UINT8 Signature[16];
* UINT16 Version; * UINT16 Version;
* UINT8 AuthState; * UINT8 AuthState;
* UINT8 Reserved * UINT8 Reserved
* UINT32 Length; * UINT32 Length;
* UINT32 DeviceType; * UINT32 DeviceType;
* UINT32 SubHeaderType; * UINT32 SubHeaderType;
* UINT32 SubHeaderLength; * UINT32 SubHeaderLength;
* UINT64 SubHeaderUID; * UINT64 SubHeaderUID;
* UINT64 DevicePathLength; * UINT64 DevicePathLength;
* UNIT8 DevicePath[DevicePathLength] * UNIT8 DevicePath[DevicePathLength]
* } DEVICE_SECURITY_EVENT_DATA_HEADER2; * } DEVICE_SECURITY_EVENT_DATA_HEADER2;
* <p> * <p>
*/ */
public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader { 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. * Event auth state.
*/ */
@ -55,33 +81,6 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
@Getter @Getter
private String subHeaderUid = ""; 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. * DeviceSecurityEventDataHeader2 Constructor.
* *
@ -91,33 +90,43 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
super(dsedBytes); super(dsedBytes);
final int dsedBytesSrcIndex = 18;
byte[] authStateBytes = new byte[1]; byte[] authStateBytes = new byte[1];
System.arraycopy(dsedBytes, 18, authStateBytes, 0, 1); System.arraycopy(dsedBytes, dsedBytesSrcIndex, authStateBytes, 0, 1);
authState = HexUtils.leReverseInt(authStateBytes); authState = HexUtils.leReverseInt(authStateBytes);
// byte[] reserved[Bytes]: 1 byte // byte[] reserved[Bytes]: 1 byte
byte[] lengthBytes = new byte[4]; final int dsedBytesSrcIndex2 = 20;
System.arraycopy(dsedBytes, 20, lengthBytes, 0, 4); final int lengthBytesSize = 4;
byte[] lengthBytes = new byte[lengthBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex2, lengthBytes, 0, lengthBytesSize);
length = HexUtils.leReverseInt(lengthBytes); length = HexUtils.leReverseInt(lengthBytes);
extractDeviceType(dsedBytes, 24); final int dsedBytesStartByte1 = 24;
extractDeviceType(dsedBytes, dsedBytesStartByte1);
byte[] subHeaderTypeBytes = new byte[4]; final int dsedBytesSrcIndex3 = 28;
System.arraycopy(dsedBytes, 28, subHeaderTypeBytes, 0, 4); final int subHeaderTypeBytesSize = 4;
byte[] subHeaderTypeBytes = new byte[subHeaderTypeBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex3, subHeaderTypeBytes, 0, subHeaderTypeBytesSize);
subHeaderType = HexUtils.leReverseInt(subHeaderTypeBytes); subHeaderType = HexUtils.leReverseInt(subHeaderTypeBytes);
byte[] subHeaderLengthBytes = new byte[4]; final int dsedBytesSrcIndex4 = 32;
System.arraycopy(dsedBytes, 32, subHeaderLengthBytes, 0, 4); final int subHeaderLengthBytesSize = 4;
byte[] subHeaderLengthBytes = new byte[subHeaderLengthBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex4, subHeaderLengthBytes, 0, subHeaderLengthBytesSize);
subHeaderLength = HexUtils.leReverseInt(subHeaderLengthBytes); subHeaderLength = HexUtils.leReverseInt(subHeaderLengthBytes);
byte[] subHeaderUidBytes = new byte[8]; final int dsedBytesSrcIndex5 = 36;
System.arraycopy(dsedBytes, 36, subHeaderUidBytes, 0, 8); final int subHeaderUidBytesSize = 8;
byte[] subHeaderUidBytes = new byte[subHeaderUidBytesSize];
System.arraycopy(dsedBytes, dsedBytesSrcIndex5, subHeaderUidBytes, 0, subHeaderUidBytesSize);
subHeaderUidBytes = HexUtils.leReverseByte(subHeaderUidBytes); subHeaderUidBytes = HexUtils.leReverseByte(subHeaderUidBytes);
subHeaderUid = HexUtils.byteArrayToHexString(subHeaderUidBytes); subHeaderUid = HexUtils.byteArrayToHexString(subHeaderUidBytes);
int devPathLenStartByte = 44; final int dsedBytesStartByte2 = 44;
extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte); extractDevicePathAndFinalSize(dsedBytes, dsedBytesStartByte2);
} }
/** /**
@ -139,22 +148,14 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
* @return a description of the auth state. * @return a description of the auth state.
*/ */
public String getAuthStateString() { public String getAuthStateString() {
return switch (authState) {
switch (authState) { case AUTH_SUCCESS -> ("AUTH_SUCCESS");
case AUTH_SUCCESS: case AUTH_NO_AUTHORITY -> ("AUTH_NO_AUTHORITY");
return ("AUTH_SUCCESS"); case AUTH_NO_BINDING -> ("AUTH_NO_BINDING");
case AUTH_NO_AUTHORITY: case AUTH_FAIL_NO_SIG -> ("AUTH_FAIL_NO_SIG");
return ("AUTH_NO_AUTHORITY"); case AUTH_FAIL_INVALID -> ("AUTH_FAIL_INVALID");
case AUTH_NO_BINDING: case AUTH_NO_SPDM -> ("AUTH_NO_SPDM");
return ("AUTH_NO_BINDING"); default -> ("Auth State unknown");
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");
}
} }
} }

View File

@ -13,27 +13,27 @@ import static hirs.utils.PciIds.translateVendor;
* Class to process the DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT event per PFP. * Class to process the DEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT event per PFP.
* <p> * <p>
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT { * typedef struct tdDEVICE_SECURITY_EVENT_DATA_PCI_CONTEXT {
* UINT16 Version; * UINT16 Version;
* UINT16 Length; * UINT16 Length;
* UINT16 VendorId; * UINT16 VendorId;
* UINT16 DeviceId; * UINT16 DeviceId;
* UINT16 RevisionId; * UINT16 RevisionId;
* UINT16 ClassCode[3]; * UINT16 ClassCode[3];
* UINT16 SubsystemVendorId; * UINT16 SubsystemVendorId;
* UINT16 SubsystemId; * UINT16 SubsystemId;
* <p> * <p>
* The following fields are defined by the PCI Express Base Specification rev4.0 v1.0. * The following fields are defined by the PCI Express Base Specification rev4.0 v1.0.
* VendorId * VendorId
* DeviceId * DeviceId
* RevisionId * RevisionId
* ClassCode * ClassCode
* SubsystemVendorId * SubsystemVendorId
* SubsystemId * SubsystemId
* Vendor id and device id are registered to specific manufacturers. * Vendor id and device id are registered to specific manufacturers.
* https://admin.pci-ids.ucw.cz/read/PC/ * https://admin.pci-ids.ucw.cz/read/PC/
* Ex. vendor id 8086 and device id 0b60: https://admin.pci-ids.ucw.cz/read/PC/8086/0b60 * Ex. vendor id 8086 and device id 0b60: https://admin.pci-ids.ucw.cz/read/PC/8086/0b60
* Class code can be looked up on the web. * Class code can be looked up on the web.
* https://admin.pci-ids.ucw.cz/read/PD/ * https://admin.pci-ids.ucw.cz/read/PD/
* The revision ID is controlled by the vendor and cannot be looked up. * The revision ID is controlled by the vendor and cannot be looked up.
*/ */
public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDeviceContext { public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDeviceContext {
@ -78,28 +78,36 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
super(dSEDpciContextBytes); super(dSEDpciContextBytes);
final int dSEDpciContextBytesSrcIndex1 = 4;
byte[] pciVendorIdBytes = new byte[2]; 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)); vendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciVendorIdBytes));
final int dSEDpciContextBytesSrcIndex2 = 6;
byte[] pciDeviceIdBytes = new byte[2]; 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)); deviceId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciDeviceIdBytes));
final int dSEDpciContextBytesSrcIndex3 = 8;
byte[] pciRevisionIdBytes = new byte[1]; 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)); revisionId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciRevisionIdBytes));
byte[] pciClassCodeBytes = new byte[3]; final int dSEDpciContextBytesSrcIndex4 = 9;
System.arraycopy(dSEDpciContextBytes, 9, pciClassCodeBytes, 0, 3); final int pciClassCodeBytesSize = 3;
byte[] pciClassCodeBytes = new byte[pciClassCodeBytesSize];
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex4, pciClassCodeBytes, 0,
pciClassCodeBytesSize);
classCode = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciClassCodeBytes)); classCode = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciClassCodeBytes));
final int dSEDpciContextBytesSrcIndex5 = 12;
byte[] pciSubsystemVendorIdBytes = new byte[2]; 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)); subsystemVendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemVendorIdBytes));
final int dSEDpciContextBytesSrcIndex6 = 14;
byte[] pciSubsystemIdBytes = new byte[2]; 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)); subsystemId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemIdBytes));
} }
@ -118,8 +126,9 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
dSEDpciContextInfo += " RevisionID = " + revisionId + "\n"; dSEDpciContextInfo += " RevisionID = " + revisionId + "\n";
List<String> classCodeList = translateDeviceClass(classCode); List<String> classCodeList = translateDeviceClass(classCode);
final int validClassCodeListSize = 3;
dSEDpciContextInfo += " Device Class: \n"; dSEDpciContextInfo += " Device Class: \n";
if (classCodeList.size() == 3) { if (classCodeList.size() == validClassCodeListSize) {
dSEDpciContextInfo += " Class = " + classCodeList.get(0) + "\n"; dSEDpciContextInfo += " Class = " + classCodeList.get(0) + "\n";
dSEDpciContextInfo += " Subclass = " + classCodeList.get(1) + "\n"; dSEDpciContextInfo += " Subclass = " + classCodeList.get(1) + "\n";
dSEDpciContextInfo += " Programming Interface = " + classCodeList.get(2) + "\n"; dSEDpciContextInfo += " Programming Interface = " + classCodeList.get(2) + "\n";

View File

@ -9,11 +9,11 @@ import hirs.utils.tpm.eventlog.spdm.SpdmHa;
* *
* <p> * <p>
* typedef union tdDEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN { * typedef union tdDEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN {
* UINT16 SpdmVersion; * UINT16 SpdmVersion;
* UINT8 SpdmSlotId; * UINT8 SpdmSlotId;
* UINT8 Reserved; * UINT8 Reserved;
* UINT32 SpdmBaseHashAlgo; * UINT32 SpdmBaseHashAlgo;
* SPDM_CERT_CHAIN SpdmCertChain; * SPDM_CERT_CHAIN SpdmCertChain;
* } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN; * } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN;
* <p> * <p>
* SpdmVersion: SpdmBaseHashAlgo * SpdmVersion: SpdmBaseHashAlgo
@ -61,16 +61,21 @@ public class DeviceSecurityEventDataSubHeaderCertChain extends DeviceSecurityEve
// byte[] reserved[Bytes]: 1 byte // byte[] reserved[Bytes]: 1 byte
byte[] spdmBaseHashAlgoBytes = new byte[4]; final int dsedSybHBytesSrcIndex1 = 4;
System.arraycopy(dsedSubHBytes, 4, spdmBaseHashAlgoBytes, 0, 4); final int spdmBaseHashAlgoBytesSize = 4;
byte[] spdmBaseHashAlgoBytes = new byte[spdmBaseHashAlgoBytesSize];
System.arraycopy(dsedSubHBytes, dsedSybHBytesSrcIndex1, spdmBaseHashAlgoBytes, 0,
spdmBaseHashAlgoBytesSize);
spdmBaseHashAlgo = HexUtils.leReverseInt(spdmBaseHashAlgoBytes); spdmBaseHashAlgo = HexUtils.leReverseInt(spdmBaseHashAlgoBytes);
// get the size of the SPDM Cert Chain // 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 // extract the bytes that comprise the SPDM Cert Chain
final int dsedSybHBytesSrcIndex2 = 8;
byte[] spdmCertChainBytes = new byte[spdmCertChainSize]; byte[] spdmCertChainBytes = new byte[spdmCertChainSize];
System.arraycopy(dsedSubHBytes, 8, spdmCertChainBytes, 0, System.arraycopy(dsedSubHBytes, dsedSybHBytesSrcIndex2, spdmCertChainBytes, 0,
spdmCertChainSize); spdmCertChainSize);
int spdmBaseHashAlgoSize = SpdmHa.tcgAlgIdToByteSize(spdmBaseHashAlgo); int spdmBaseHashAlgoSize = SpdmHa.tcgAlgIdToByteSize(spdmBaseHashAlgo);

View File

@ -15,24 +15,28 @@ import java.util.List;
* *
* <p> * <p>
* typedef union tdDEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK { * typedef union tdDEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK {
* UINT16 SpdmVersion; * UINT16 SpdmVersion;
* UINT8 SpdmMeasurementBlockCount; * UINT8 SpdmMeasurementBlockCount;
* UINT8 Reserved; * UINT8 Reserved;
* UINT32 SpdmMeasurementHashAlgo; * UINT32 SpdmMeasurementHashAlgo;
* SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock[SpdmMeasurementBlockCount]; * SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock[SpdmMeasurementBlockCount];
* } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK; * } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK;
* <p> * <p>
* * <p>
* SpdmMeasurementBlock is an array of SPDM_MEASUREMENT_BLOCKs * SpdmMeasurementBlock is an array of SPDM_MEASUREMENT_BLOCKs
* The size of each block is the same and can be found by either: * The size of each block is the same and can be found by either:
* 1) 4 + SpdmMeasurementBlock MeasurementSize * 1) 4 + SpdmMeasurementBlock MeasurementSize
* OR * OR
* 2) 4 + hash length of the hash algorithm found in * 2) 4 + hash length of the hash algorithm found in
* DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK SpdmMeasurementHashAlgo * DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK SpdmMeasurementHashAlgo
* where 4 is the size of the SpdmMeasurementBlock header * where 4 is the size of the SpdmMeasurementBlock header
*/ */
public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends DeviceSecurityEventDataSubHeader { public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends DeviceSecurityEventDataSubHeader {
/**
* List of SPDM Measurement Blocks.
*/
private final List<SpdmMeasurementBlock> spdmMeasurementBlockList;
/** /**
* SPDM version. * SPDM version.
*/ */
@ -48,11 +52,6 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
*/ */
@Getter @Getter
private int spdmMeasurementHashAlgo = -1; private int spdmMeasurementHashAlgo = -1;
/**
* List of SPDM Measurement Blocks.
*/
private List<SpdmMeasurementBlock> spdmMeasurementBlockList;
/** /**
* Error reading SPDM Measurement Block. * Error reading SPDM Measurement Block.
*/ */
@ -77,16 +76,21 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
// byte[] reserved[Bytes]: 1 byte // byte[] reserved[Bytes]: 1 byte
byte[] spdmMeasurementHashAlgoBytes = new byte[4]; final int spdmMeasurementHashAlgoBytesSize = 4;
System.arraycopy(dsedSubHBytes, 4, spdmMeasurementHashAlgoBytes, 0, 4); final int dsedSubHBytesSrcIndex1 = 4;
byte[] spdmMeasurementHashAlgoBytes = new byte[spdmMeasurementHashAlgoBytesSize];
System.arraycopy(dsedSubHBytes, dsedSubHBytesSrcIndex1, spdmMeasurementHashAlgoBytes, 0,
spdmMeasurementHashAlgoBytesSize);
spdmMeasurementHashAlgo = HexUtils.leReverseInt(spdmMeasurementHashAlgoBytes); spdmMeasurementHashAlgo = HexUtils.leReverseInt(spdmMeasurementHashAlgoBytes);
// get the total size of the SPDM Measurement Block List // 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 // extract the bytes that comprise the SPDM Measurement Block List
final int dsedSubHBytesSrcIndex2 = 8;
byte[] spdmMeasurementBlockListBytes = new byte[spdmMeasurementBlockListSize]; byte[] spdmMeasurementBlockListBytes = new byte[spdmMeasurementBlockListSize];
System.arraycopy(dsedSubHBytes, 8, spdmMeasurementBlockListBytes, 0, System.arraycopy(dsedSubHBytes, dsedSubHBytesSrcIndex2, spdmMeasurementBlockListBytes, 0,
spdmMeasurementBlockListSize); spdmMeasurementBlockListSize);
ByteArrayInputStream spdmMeasurementBlockListData = ByteArrayInputStream spdmMeasurementBlockListData =

View File

@ -12,51 +12,55 @@ import java.nio.charset.StandardCharsets;
* The first 16 bytes of the event data header MUST be a String based identifier (Signature), * 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", * 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. * which implies the data is a DEVICE_SECURITY_EVENT_DATA or ..DATA2.
* * <p>
* HEADERS defined by PFP v1.06 Rev 52. * HEADERS defined by PFP v1.06 Rev 52.
* Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures. * Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures.
* <p> * <p>
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER { * typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER {
* UINT8 Signature[16]; * UINT8 Signature[16];
* UINT16 Version; * UINT16 Version;
* UINT16 Length; * UINT16 Length;
* UINT32 SpdmHashAlg; * UINT32 SpdmHashAlg;
* UINT32 DeviceType; * UINT32 DeviceType;
* SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock; * SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock;
* UINT64 DevicePathLength; * UINT64 DevicePathLength;
* UNIT8 DevicePath[DevicePathLength] * UNIT8 DevicePath[DevicePathLength]
* } DEVICE_SECURITY_EVENT_DATA_HEADER; * } DEVICE_SECURITY_EVENT_DATA_HEADER;
* <p> * <p>
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER2 { - NOT IMPLEMENTED YET * typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER2 { - NOT IMPLEMENTED YET
* UINT8 Signature[16]; * UINT8 Signature[16];
* UINT16 Version; * UINT16 Version;
* UINT8 AuthState; * UINT8 AuthState;
* UINT8 Reserved; * UINT8 Reserved;
* UINT32 Length; * UINT32 Length;
* UINT32 DeviceType; * UINT32 DeviceType;
* UINT32 SubHeaderType; * UINT32 SubHeaderType;
* UINT32 SubHeaderLength; * UINT32 SubHeaderLength;
* UINT32 SubHeaderUID; * UINT32 SubHeaderUID;
* UINT64 DevicePathLength; * UINT64 DevicePathLength;
* UNIT8 DevicePath[DevicePathLength] * UNIT8 DevicePath[DevicePathLength]
* } DEVICE_SECURITY_EVENT_DATA_HEADER2; * } DEVICE_SECURITY_EVENT_DATA_HEADER2;
* <p> * <p>
* Fields common to both ..HEADER and ..HEADER2: * Fields common to both ..HEADER and ..HEADER2:
* Signature * Signature
* Version * Version
* DeviceType * DeviceType
* DevicePathLength * DevicePathLength
* DevicePath * DevicePath
* <p> * <p>
*/ */
public abstract class DeviceSecurityEventHeader { 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. * Contains the size (in bytes) of the header.
*/ */
@Getter @Getter
private Integer dsedHeaderLength = 0; private Integer dsedHeaderLength = 0;
/** /**
* Signature (text) data. * Signature (text) data.
*/ */
@ -73,11 +77,6 @@ public abstract class DeviceSecurityEventHeader {
*/ */
@Getter @Getter
private int deviceType = -1; private int deviceType = -1;
/**
* UEFI Device Path Length.
*/
@Getter
private int devicePathLength = 0;
/** /**
* UEFI Device path. * UEFI Device path.
*/ */
@ -129,21 +128,23 @@ public abstract class DeviceSecurityEventHeader {
int startByteUpdated = startByte; int startByteUpdated = startByte;
// get the device path length // get the device path length
byte[] devicePathLengthBytes = new byte[8]; final int devicePathLengthBytesSize = 8;
System.arraycopy(dsedBytes, startByteUpdated, devicePathLengthBytes, 0, 8); byte[] devicePathLengthBytes = new byte[devicePathLengthBytesSize];
int devicePathLength = HexUtils.leReverseInt(devicePathLengthBytes); System.arraycopy(dsedBytes, startByteUpdated, devicePathLengthBytes, 0, devicePathLengthBytesSize);
int retrievedDevicePathLength = HexUtils.leReverseInt(devicePathLengthBytes);
// get the device path // get the device path
if (devicePathLength > 0) { if (retrievedDevicePathLength > 0) {
startByteUpdated = startByteUpdated + 8; final int startByteUpdatedOffset = 8;
byte[] devPathBytes = new byte[devicePathLength]; startByteUpdated = startByteUpdated + startByteUpdatedOffset;
byte[] devPathBytes = new byte[retrievedDevicePathLength];
System.arraycopy(dsedBytes, startByteUpdated, devPathBytes, System.arraycopy(dsedBytes, startByteUpdated, devPathBytes,
0, devicePathLength); 0, retrievedDevicePathLength);
devicePath = new UefiDevicePath(devPathBytes); devicePath = new UefiDevicePath(devPathBytes);
} }
// header total size // header total size
dsedHeaderLength = startByteUpdated + devicePathLength; dsedHeaderLength = startByteUpdated + retrievedDevicePathLength;
} }
/** /**
@ -154,16 +155,12 @@ public abstract class DeviceSecurityEventHeader {
* @return name of the device type * @return name of the device type
*/ */
public String deviceTypeToString(final int deviceTypeInt) { public String deviceTypeToString(final int deviceTypeInt) {
switch (deviceTypeInt) { return switch (deviceTypeInt) {
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_NONE: case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_NONE -> "No device type";
return "No device type"; case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_PCI -> "PCI";
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_PCI: case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_USB -> "USB";
return "PCI"; default -> "Unknown or invalid Device Type";
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_USB: };
return "USB";
default:
return "Unknown or invalid Device Type";
}
} }
/** /**

View File

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

View File

@ -11,16 +11,16 @@ import java.nio.charset.StandardCharsets;
* Class to process the EV_NO_ACTION event. * Class to process the EV_NO_ACTION event.
* The first 16 bytes of the event data MUST be a String based identifier (Signature). * The first 16 bytes of the event data MUST be a String based identifier (Signature).
* Currently defined Signatures are * Currently defined Signatures are
* "Spec ID Event03" * "Spec ID Event03"
* - implies the data is a TCG_EfiSpecIDEvent * - implies the data is a TCG_EfiSpecIDEvent
* - TCG_EfiSpecIDEvent is the first event in a TPM Event Log and is used to determine * - TCG_EfiSpecIDEvent is the first event in a TPM Event Log and is used to determine
* if the format of the Log (SHA1 vs Crypto Agile). * if the format of the Log (SHA1 vs Crypto Agile).
* "StartupLocality" * "StartupLocality"
* - implies the data represents locality info (use lookup to interpret) * - implies the data represents locality info (use lookup to interpret)
* "NvIndexInstance" * "NvIndexInstance"
* - implies the data is a NV_INDEX_INSTANCE_EVENT_LOG_DATA * - implies the data is a NV_INDEX_INSTANCE_EVENT_LOG_DATA
* "NvIndexDynamic" * "NvIndexDynamic"
* - implies the data is a NV_INDEX_DYNAMIC_EVENT_LOG_DATA * - implies the data is a NV_INDEX_DYNAMIC_EVENT_LOG_DATA
* <p> * <p>
* Notes: * Notes:
* 1. First 16 bytes of the structure is an ASCII with a fixed Length of 16 * 1. First 16 bytes of the structure is an ASCII with a fixed Length of 16
@ -66,7 +66,7 @@ public class EvNoAction {
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
if (signature.contains("Spec ID Event03")) { // implies CryptAgileFormat if (signature.contains("Spec ID Event03")) { // implies CryptAgileFormat
EvEfiSpecIdEvent specIDEvent = new EvEfiSpecIdEvent(eventData); EvEfiSpecIdEvent specIDEvent = new EvEfiSpecIdEvent(eventData);
noActionInfo += specIDEventToString(specIDEvent).toString(); noActionInfo += specIDEventToString(specIDEvent);
bSpecIDEvent = true; bSpecIDEvent = true;
specVersion = String.format("%s.%s", specVersion = String.format("%s.%s",
specIDEvent.getVersionMajor(), specIDEvent.getVersionMajor(),
@ -126,25 +126,21 @@ public class EvNoAction {
* @return a description of the locality. * @return a description of the locality.
*/ */
private String getLocality(final byte[] eventData) { private String getLocality(final byte[] eventData) {
String localityInfo = ""; final int eventDataSrcIndex = 16;
byte[] localityBytes = new byte[1]; byte[] localityBytes = new byte[1];
System.arraycopy(eventData, 16, localityBytes, 0, 1); System.arraycopy(eventData, eventDataSrcIndex, localityBytes, 0, 1);
int locality = HexUtils.leReverseInt(localityBytes); final int locality = HexUtils.leReverseInt(localityBytes);
switch (locality) { final int locality0 = 0;
case 0: final int locality3 = 3;
localityInfo += "Locality 0 without an H-CRTM sequence"; final int locality4 = 4;
break;
case 3: return switch (locality) {
localityInfo += "Locality 3 without an H-CRTM sequence"; case locality0 -> "Locality 0 without an H-CRTM sequence";
break; case locality3 -> "Locality 3 without an H-CRTM sequence";
case 4: case locality4 -> "Locality 4 with an H-CRTM sequence initialized";
localityInfo += "Locality 4 with an H-CRTM sequence initialized"; default -> "Unknown";
break; };
default:
localityInfo += "Unknown";
}
return localityInfo;
} }
/** /**

View File

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

View File

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

View File

@ -15,22 +15,22 @@ import java.util.ArrayList;
* <p> * <p>
* Certificate chain format, defined by SPDM v1.03, Sect 10.6.1, Table 33: * Certificate chain format, defined by SPDM v1.03, Sect 10.6.1, Table 33:
* Certificate chain format { * Certificate chain format {
* Length 2 bytes; * Length 2 bytes;
* Reserved 2 bytes; * Reserved 2 bytes;
* RootHash <H> bytes; * RootHash <H> bytes;
* Certificates <Length> - (4 + <H>) bytes; * Certificates <Length> - (4 + <H>) bytes;
* } * }
* <p> * <p>
* Length: total length of cert chain including all fields in this block * Length: total length of cert chain including all fields in this block
* H: the output size of the hash algorithm selected by the most recent ALGORITHMS response * H: the output size of the hash algorithm selected by the most recent ALGORITHMS response
* this field shall be in hash byte order * this field shall be in hash byte order
* hash algorithm is included in the DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN * hash algorithm is included in the DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN
* structure as the member "SpdmBaseHashAlg" * structure as the member "SpdmBaseHashAlg"
* RootHash: the digest of the Root Certificate. * RootHash: the digest of the Root Certificate.
* size is determined by hash algorithm selected by the most recent SPDM ALGORITHMS response; * size is determined by hash algorithm selected by the most recent SPDM ALGORITHMS response;
* the hash algorithm is the DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN SpdmBaseHashAlgo * the hash algorithm is the DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_CERT_CHAIN SpdmBaseHashAlgo
* Certificates: Complete cert chain consisting of 1 or more ASN.1 DER-encoded X.509 v3 certs * Certificates: Complete cert chain consisting of 1 or more ASN.1 DER-encoded X.509 v3 certs
* this field shall be in Encoded ASN.1 byte order * this field shall be in Encoded ASN.1 byte order
*/ */
public class SpdmCertificateChain { public class SpdmCertificateChain {
@ -38,6 +38,10 @@ public class SpdmCertificateChain {
// * Length of the certificate chain to include all fields in this structure. // * Length of the certificate chain to include all fields in this structure.
// */ // */
//private int length = 0; //private int length = 0;
/**
* Array List of certs found in the chain.
*/
private final ArrayList<UefiX509Cert> certList = new ArrayList<UefiX509Cert>();
/** /**
* Root hash. * Root hash.
*/ */
@ -46,10 +50,6 @@ public class SpdmCertificateChain {
* Number of certs in the SPDM cert chain. * Number of certs in the SPDM cert chain.
*/ */
private int numberOfCerts = 0; 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. * Human-readable description of any error associated with SPDM base hash alg.
*/ */
@ -63,7 +63,7 @@ public class SpdmCertificateChain {
* SpdmCertificateChain Constructor. * SpdmCertificateChain Constructor.
* *
* @param spdmCertChainBytes byte array holding the SPDM Cert Chain bytes. * @param spdmCertChainBytes byte array holding the SPDM Cert Chain bytes.
* @param rootHashLength length of RootHash. * @param rootHashLength length of RootHash.
*/ */
public SpdmCertificateChain(final byte[] spdmCertChainBytes, final int rootHashLength) { public SpdmCertificateChain(final byte[] spdmCertChainBytes, final int rootHashLength) {
@ -76,11 +76,13 @@ public class SpdmCertificateChain {
// Reserved: 2 bytes // Reserved: 2 bytes
final int spdmCertChainBytesSrcIndex = 4;
rootHash = new byte[rootHashLength]; rootHash = new byte[rootHashLength];
System.arraycopy(spdmCertChainBytes, 4, rootHash, 0, rootHashLength); System.arraycopy(spdmCertChainBytes, spdmCertChainBytesSrcIndex, rootHash, 0, rootHashLength);
int certChainStartPos = 4 + rootHashLength; final int offsetForCertChain = 4;
int certChainLength = spdmCertChainBytes.length - certChainStartPos; final int certChainStartPos = offsetForCertChain + rootHashLength;
final int certChainLength = spdmCertChainBytes.length - certChainStartPos;
byte[] certChainBytes = new byte[certChainLength]; byte[] certChainBytes = new byte[certChainLength];
System.arraycopy(spdmCertChainBytes, certChainStartPos, certChainBytes, 0, certChainLength); System.arraycopy(spdmCertChainBytes, certChainStartPos, certChainBytes, 0, certChainLength);
@ -93,7 +95,7 @@ public class SpdmCertificateChain {
* *
* @param certChainData Byte array holding the cert chain data * @param certChainData Byte array holding the cert chain data
*/ */
private void processCertChain(final byte[] certChainData) { private void processCertChain(final byte[] certChainData) {
UefiX509Cert cert = null; UefiX509Cert cert = null;
@ -113,10 +115,11 @@ public class SpdmCertificateChain {
byte[] certData = new byte[cLength]; byte[] certData = new byte[cLength];
certChainDataIS.read(certData); certChainDataIS.read(certData);
// put the cert back together // 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(certType, 0, certBlob, 0, 2);
System.arraycopy(certLength, 0, certBlob, 2, 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 UefiX509Cert(certBlob);
//cert = new X509Certificate(certBlob); //cert = new X509Certificate(certBlob);
certList.add(cert); 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. * Class for defining hash algorithms referenced in the DMTF SPDM specification.
* SPDM 1.3.0, Table 21, MeasurementHashAlgo. * SPDM 1.3.0, Table 21, MeasurementHashAlgo.
*/ */
public class SpdmHa { public final class SpdmHa {
/**
* Default private constructor so checkstyles doesn't complain
*/
private SpdmHa() { }
/** /**
* Spdm Hash Alg = Raw bit stream. * Spdm Hash Alg = Raw bit stream.
@ -40,6 +35,12 @@ public class SpdmHa {
*/ */
public static final int TPM_ALG_SHA3_512 = 64; 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. * Returns the hash name via a lookup.
* Lookup based upon SPDM Spec v1.03 section 10.4. * Lookup based upon SPDM Spec v1.03 section 10.4.
@ -48,32 +49,16 @@ public class SpdmHa {
* @return name of the algorithm * @return name of the algorithm
*/ */
public static String tcgAlgIdToString(final int algId) { public static String tcgAlgIdToString(final int algId) {
String alg; String alg = switch (algId) {
switch (algId) { case TPM_ALG_RAW -> "Raw Bit Stream";
case TPM_ALG_RAW: case TPM_ALG_SHA_256 -> "TPM_ALG_SHA_256";
alg = "Raw Bit Stream"; case TPM_ALG_SHA_384 -> "TPM_ALG_SHA_384";
break; case TPM_ALG_SHA_512 -> "TPM_ALG_SHA_512";
case TPM_ALG_SHA_256: case TPM_ALG_SHA3_256 -> "TPM_ALG_SHA3_256";
alg = "TPM_ALG_SHA_256"; case TPM_ALG_SHA3_384 -> "TPM_ALG_SHA3_384";
break; case TPM_ALG_SHA3_512 -> "TPM_ALG_SHA3_512";
case TPM_ALG_SHA_384: default -> "Unknown or invalid Hash";
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";
}
return alg; return alg;
} }
@ -85,32 +70,17 @@ public class SpdmHa {
* @return size of the algorithm output * @return size of the algorithm output
*/ */
public static int tcgAlgIdToByteSize(final int algId) { public static int tcgAlgIdToByteSize(final int algId) {
int byteSize; final int byteSize256 = 32;
switch (algId) { final int byteSize384 = 48;
//case TPM_ALG_RAW: // add this when have more test data final int byteSize512 = 64;
// byteSize = ;
// break; return switch (algId) {
case TPM_ALG_SHA_256: // case TPM_ALG_RAW: // add this when have more test data
byteSize = 32; // return ;
break; case TPM_ALG_SHA_256, TPM_ALG_SHA3_256 -> byteSize256;
case TPM_ALG_SHA_384: case TPM_ALG_SHA_384, TPM_ALG_SHA3_384 -> byteSize384;
byteSize = 48; case TPM_ALG_SHA_512, TPM_ALG_SHA3_512 -> byteSize512;
break; default -> -1;
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;
} }
} }

View File

@ -8,34 +8,89 @@ import lombok.Getter;
* <p> * <p>
* Measurement, defined by SPDM v1.03, Sect 10.11.1, Table 54: * Measurement, defined by SPDM v1.03, Sect 10.11.1, Table 54:
* DMTF measurement spec format { * DMTF measurement spec format {
* DMTFSpecMeasurementValueType 1 byte; * DMTFSpecMeasurementValueType 1 byte;
* DMTFSpecMeasurementValueSize 2 bytes; * DMTFSpecMeasurementValueSize 2 bytes;
* DMTFSpecMeasurementValue <DMTFSpecMeasurementValueSize> bytes; * DMTFSpecMeasurementValue <DMTFSpecMeasurementValueSize> bytes;
* } * }
* <p> * <p>
* DMTFSpecMeasurementValueType[7] * DMTFSpecMeasurementValueType[7]
* Indicates how bits [0:6] are represented * Indicates how bits [0:6] are represented
* Bit = 0: Digest * Bit = 0: Digest
* Bit = 1: Raw bit stream * Bit = 1: Raw bit stream
* DMTFSpecMeasurementValueType[6:0] (see SPDM Spec, Table 55 "DMTFSpecMeasurementValueType[6:0]") * DMTFSpecMeasurementValueType[6:0] (see SPDM Spec, Table 55 "DMTFSpecMeasurementValueType[6:0]")
* Immutable ROM 0x0 * Immutable ROM 0x0
* Mutable firmware 0x1 * Mutable firmware 0x1
* Hardware configuration 0x2 * Hardware configuration 0x2
* Firmware configuration 0x3 * Firmware configuration 0x3
* etc. * etc.
* <p> * <p>
*/ */
public class SpdmMeasurement { 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). * Measurement value type (such as mutable firmware, etc).
*/ */
@Getter @Getter
private int dmtfSpecMeasurementValueType = 0; private int dmtfSpecMeasurementValueType = 0;
/**
* Measurement value (digest).
*/
private byte[] dmtfSpecMeasurementValue;
/** /**
* SpdmMeasurement Constructor. * SpdmMeasurement Constructor.
@ -49,14 +104,16 @@ public class SpdmMeasurement {
1); 1);
dmtfSpecMeasurementValueType = HexUtils.leReverseInt(dmtfSpecMeasurementValueTypeBytes); 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]; byte[] dmtfSpecMeasurementValueSizeBytes = new byte[2];
System.arraycopy(spdmMeasBytes, 1, dmtfSpecMeasurementValueSizeBytes, 0, System.arraycopy(spdmMeasBytes, 1, dmtfSpecMeasurementValueSizeBytes, 0,
2); 2);
int dmtfSpecMeasurementValueSize = HexUtils.leReverseInt(dmtfSpecMeasurementValueSizeBytes); int dmtfSpecMeasurementValueSize = HexUtils.leReverseInt(dmtfSpecMeasurementValueSizeBytes);
dmtfSpecMeasurementValue = new byte[dmtfSpecMeasurementValueSize]; dmtfSpecMeasurementValue = new byte[dmtfSpecMeasurementValueSize];
System.arraycopy(spdmMeasBytes, 3, dmtfSpecMeasurementValue, 0,
final int sourceIndex = 3;
System.arraycopy(spdmMeasBytes, sourceIndex, dmtfSpecMeasurementValue, 0,
dmtfSpecMeasurementValueSize); dmtfSpecMeasurementValueSize);
} }
@ -64,50 +121,23 @@ public class SpdmMeasurement {
* Lookup for SPDM measurement value type. * Lookup for SPDM measurement value type.
* *
* @param measValType the numerical representation of the measurement value type. * @param measValType the numerical representation of the measurement value type.
*
* @return a description of the measurement value type. * @return a description of the measurement value type.
*/ */
public String dmtfSpecMeasurementValueTypeToString(final int measValType) { public String dmtfSpecMeasurementValueTypeToString(final int measValType) {
return switch (measValType) {
String measValTypeStr; case MEASUREMENT_VALUE_0 -> "Immutable ROM";
switch (measValType) { case MEASUREMENT_VALUE_1 -> "Mutable firmware";
case 0: case MEASUREMENT_VALUE_2 -> "Hardware configuration";
measValTypeStr = "Immutable ROM"; case MEASUREMENT_VALUE_3 -> "Firmware configuration";
break; case MEASUREMENT_VALUE_4 -> "Freeform measurement manifest";
case 1: case MEASUREMENT_VALUE_5 -> "Structured representation of debug and device mode";
measValTypeStr = "Mutable firmware"; case MEASUREMENT_VALUE_6 -> "Mutable firmware's version number";
break; case MEASUREMENT_VALUE_7 -> "Mutable firmware's security version number";
case 2: case MEASUREMENT_VALUE_8 -> "Hash-extended measurement";
measValTypeStr = "Hardware configuration"; case MEASUREMENT_VALUE_9 -> "Informational";
break; case MEASUREMENT_VALUE_10 -> "Structured measurement manifest";
case 3: default -> "Unknown or invalid DMTF Spec Measurement Value Type";
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;
} }
/** /**

View File

@ -2,4 +2,4 @@
* Non-persistent classes related to TGC Event Logs. * Non-persistent classes related to TGC Event Logs.
*/ */
package hirs.utils.tpm.eventlog.spdm; package hirs.utils.tpm.eventlog.spdm;

View File

@ -7,11 +7,6 @@ package hirs.utils.tpm.eventlog.uefi;
*/ */
public final class UefiConstants { public final class UefiConstants {
/**
* Default private constructor so checkstyles doesn't complain
*/
private UefiConstants() { }
/** /**
* 2 byte size. * 2 byte size.
*/ */
@ -278,13 +273,18 @@ public final class UefiConstants {
public static final String FILESTATUS_FROM_FILESYSTEM = "fileFromFilesystem"; public static final String FILESTATUS_FROM_FILESYSTEM = "fileFromFilesystem";
/** /**
* file status, where file was not found on local machine, so file from code was used. * file status, where file was not found on local machine, so file from code was used.
* For instance, if vendor-table.json is not found in filesystem at location * For instance, if vendor-table.json is not found in filesystem at location
* /etc/hirs/aca/default-properties/, it will be grabbed from code at * /etc/hirs/aca/default-properties/, it will be grabbed from code at
* HIRS_AttestationCA/src/main/resources/. * HIRS_AttestationCA/src/main/resources/.
*/ */
public static final String FILESTATUS_FROM_CODE = "fileFromCode"; public static final String FILESTATUS_FROM_CODE = "fileFromCode";
/** /**
* file status, where file is not accessible (either not found, or no access permission). * file status, where file is not accessible (either not found, or no access permission).
*/ */
public static final String FILESTATUS_NOT_ACCESSIBLE = "fileNotAccessible"; 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; package hirs.data.persist;
import java.util.Arrays;
import hirs.utils.digest.Digest; import hirs.utils.digest.Digest;
import hirs.utils.digest.DigestAlgorithm; import hirs.utils.digest.DigestAlgorithm;
import hirs.utils.digest.DigestComparisonResultType; import hirs.utils.digest.DigestComparisonResultType;
import org.apache.commons.codec.digest.DigestUtils; import org.apache.commons.codec.digest.DigestUtils;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Arrays;
/** /**
* Unit tests for the <code>Digest</code> class. * Unit tests for the <code>Digest</code> class.
*/ */
public class DigestTest { public class DigestTest {
private static final int DIGEST_LENGTH_BYTES = 20; 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. * Get a test SHA1 digest.
* *
@ -464,7 +48,455 @@ public class DigestTest {
return new byte[count]; 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() { 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 hirs.attestationca.persist.entity.userdefined.info.FirmwareInfo;
import org.apache.commons.lang3.StringUtils; 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.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
/** /**
* FirmwareInfoTest is a unit test class for FirmwareInfo. * 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_VENDOR = "test bios vendor";
private static final String BIOS_VERSION = "test bios version"; private static final String BIOS_VERSION = "test bios version";
private static final String BIOS_RELEASE_DATE = "test bios release date"; 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( private static final String LONG_BIOS_VENDOR = StringUtils.rightPad(
"test bios vendor", BIOS_VENDOR,
257 PRIMARY_SIZE
); );
private static final String LONG_BIOS_VERSION = StringUtils.rightPad( private static final String LONG_BIOS_VERSION = StringUtils.rightPad(
"test bios version", BIOS_VERSION,
257 PRIMARY_SIZE
); );
private static final String LONG_BIOS_RELEASE_DATE = StringUtils.rightPad( private static final String LONG_BIOS_RELEASE_DATE = StringUtils.rightPad(
"test bios release date", BIOS_RELEASE_DATE,
33 SECONDARY_SIZE
); );
/** /**
@ -44,8 +46,8 @@ public class FirmwareInfoTest {
public final void firmwareInfoNoParams() { public final void firmwareInfoNoParams() {
FirmwareInfo firmwareInfo = new FirmwareInfo(); FirmwareInfo firmwareInfo = new FirmwareInfo();
Assertions.assertEquals(NOT_SPECIFIED, firmwareInfo.getBiosVendor()); Assertions.assertEquals(NOT_SPECIFIED, firmwareInfo.getBiosVendor());
Assertions.assertEquals(NOT_SPECIFIED,firmwareInfo.getBiosVersion()); Assertions.assertEquals(NOT_SPECIFIED, firmwareInfo.getBiosVersion());
Assertions.assertEquals(NOT_SPECIFIED,firmwareInfo.getBiosReleaseDate()); Assertions.assertEquals(NOT_SPECIFIED, firmwareInfo.getBiosReleaseDate());
} }
/** /**

View File

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

View File

@ -1,12 +1,12 @@
package hirs.data.persist; package hirs.data.persist;
import hirs.attestationca.persist.entity.userdefined.info.NetworkInfo; 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.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.net.InetAddress;
import java.net.UnknownHostException;
/** /**
* NetworkInfoTest is a unit test class for NetworkInfo. * 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, private static final byte[] MAC_ADDRESS = new byte[] {11, 22, 33, 44, 55,
66}; 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. * Tests instantiation of a NetworkInfo object.
*/ */
@ -103,14 +112,14 @@ public class NetworkInfoTest {
* Tests that hashcodes generated by NetworkInfo objects with different IP * Tests that hashcodes generated by NetworkInfo objects with different IP
* addresses are not equal. * addresses are not equal.
* *
* @throws UnknownHostException * @throws UnknownHostException in case the InetAddress is not created correctly
* in case the InetAddress is not created correctly
*/ */
@Test @Test
public final void testHashCodeNotEqualsIpAddress() public final void testHashCodeNotEqualsIpAddress()
throws UnknownHostException { throws UnknownHostException {
final byte[] byteAddress = new byte[] {127, 0, 0, 2};
final InetAddress ipAddress2 = final InetAddress ipAddress2 =
InetAddress.getByAddress(new byte[] {127, 0, 0, 2}); InetAddress.getByAddress(byteAddress);
NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS); NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
NetworkInfo ni2 = new NetworkInfo(HOSTNAME, ipAddress2, MAC_ADDRESS); NetworkInfo ni2 = new NetworkInfo(HOSTNAME, ipAddress2, MAC_ADDRESS);
Assertions.assertNotEquals(ni2.hashCode(), ni1.hashCode()); 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 * Tests that two NetworkInfo objects are not equal if they have different
* IP addresses. * IP addresses.
* *
* @throws UnknownHostException * @throws UnknownHostException in case InetAddress is not created correctly
* in case InetAddress is not created correctly
*/ */
@Test @Test
public final void testNotEqualsIpAddress() throws UnknownHostException { public final void testNotEqualsIpAddress() throws UnknownHostException {
final byte[] byteAddress = new byte[] {127, 0, 0, 2};
final InetAddress ipAddress2 = final InetAddress ipAddress2 =
InetAddress.getByAddress(new byte[] {127, 0, 0, 2}); InetAddress.getByAddress(byteAddress);
NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS); NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
NetworkInfo ni2 = new NetworkInfo(HOSTNAME, ipAddress2, MAC_ADDRESS); NetworkInfo ni2 = new NetworkInfo(HOSTNAME, ipAddress2, MAC_ADDRESS);
Assertions.assertNotEquals(ni2, ni1); Assertions.assertNotEquals(ni2, ni1);
@ -178,12 +187,4 @@ public class NetworkInfoTest {
NetworkInfo ni2 = new NetworkInfo(HOSTNAME, IP_ADDRESS, macAddress2); NetworkInfo ni2 = new NetworkInfo(HOSTNAME, IP_ADDRESS, macAddress2);
Assertions.assertNotEquals(ni2, ni1); 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; package hirs.data.persist;
import hirs.attestationca.persist.entity.userdefined.info.OSInfo; import hirs.attestationca.persist.entity.userdefined.info.OSInfo;
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
/** /**
* OSInfoTest is a unit test class for OSInfo. * 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 OS_ARCH = "test osArch";
private static final String DISTRIBUTION = "test distribution"; private static final String DISTRIBUTION = "test distribution";
private static final String DISTRIBUTION_RELEASE = "test distribution release"; 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_NAME = StringUtils.rightPad(OS_NAME, PRIMARY_SIZE);
private static final String LONG_OS_VERSION = StringUtils.rightPad("test osVersion", 257); private static final String LONG_OS_VERSION = StringUtils.rightPad(OS_VERSION, PRIMARY_SIZE);
private static final String LONG_OS_ARCH = StringUtils.rightPad("test osArch", 33); private static final String LONG_OS_ARCH = StringUtils.rightPad(OS_ARCH, SECONDARY_SIZE);
/** /**
* Tests instantiation of an OSInfo object. * Tests instantiation of an OSInfo object.
@ -63,7 +65,7 @@ public class OSInfoTest {
@Test @Test
public final void osNameNullTest() { public final void osNameNullTest() {
Assertions.assertThrows(IllegalArgumentException.class, () -> Assertions.assertThrows(IllegalArgumentException.class, () ->
new OSInfo(null, OS_VERSION, OS_ARCH, DISTRIBUTION, DISTRIBUTION_RELEASE)); new OSInfo(null, OS_VERSION, OS_ARCH, DISTRIBUTION, DISTRIBUTION_RELEASE));
} }
/** /**
@ -72,7 +74,7 @@ public class OSInfoTest {
@Test @Test
public final void osVersionNullTest() { public final void osVersionNullTest() {
Assertions.assertThrows(IllegalArgumentException.class, () -> Assertions.assertThrows(IllegalArgumentException.class, () ->
new OSInfo(OS_NAME, null, OS_ARCH, DISTRIBUTION, DISTRIBUTION_RELEASE)); new OSInfo(OS_NAME, null, OS_ARCH, DISTRIBUTION, DISTRIBUTION_RELEASE));
} }
/** /**
@ -81,7 +83,7 @@ public class OSInfoTest {
@Test @Test
public final void osArchNullTest() { public final void osArchNullTest() {
Assertions.assertThrows(IllegalArgumentException.class, () -> Assertions.assertThrows(IllegalArgumentException.class, () ->
new OSInfo(OS_NAME, OS_VERSION, null, DISTRIBUTION, DISTRIBUTION_RELEASE)); new OSInfo(OS_NAME, OS_VERSION, null, DISTRIBUTION, DISTRIBUTION_RELEASE));
} }
/** /**
@ -108,7 +110,7 @@ public class OSInfoTest {
@Test @Test
public final void osArchLongTest() { public final void osArchLongTest() {
Assertions.assertThrows(IllegalArgumentException.class, () -> Assertions.assertThrows(IllegalArgumentException.class, () ->
new OSInfo(OS_NAME, OS_VERSION, LONG_OS_ARCH, DISTRIBUTION, DISTRIBUTION_RELEASE)); new OSInfo(OS_NAME, OS_VERSION, LONG_OS_ARCH, DISTRIBUTION, DISTRIBUTION_RELEASE));
} }
/** /**

View File

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

View File

@ -1,25 +1,29 @@
package hirs.tpm.eventlog.uefi; 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 com.eclipsesource.json.JsonObject;
import hirs.utils.HexUtils;
import hirs.utils.JsonUtils; 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.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import hirs.utils.HexUtils;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; 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. * Class for testing TCG Event Log processing of UEFI defined Data.
*/ */
@ -61,7 +65,7 @@ public class UefiProcessingTest {
* @throws IOException when processing the test fails. * @throws IOException when processing the test fails.
* @throws NoSuchAlgorithmException if non TCG Algorithm is encountered. * @throws NoSuchAlgorithmException if non TCG Algorithm is encountered.
* @throws CertificateException if parsing issue for X509 cert is encountered. * @throws CertificateException if parsing issue for X509 cert is encountered.
* @throws URISyntaxException File location exception * @throws URISyntaxException File location exception
*/ */
@Test @Test
public final void testUefiVariables() throws IOException, public final void testUefiVariables() throws IOException,
@ -70,7 +74,7 @@ public class UefiProcessingTest {
Path jsonPath = Paths.get(this.getClass() Path jsonPath = Paths.get(this.getClass()
.getResource(JSON_FILE).toURI()); .getResource(JSON_FILE).toURI());
String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_VARIABLE_BOOT), String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_VARIABLE_BOOT),
"UTF-8"); StandardCharsets.UTF_8);
byte[] uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt); byte[] uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt);
UefiVariable uefiVariable = new UefiVariable(uefiVariableBytes); UefiVariable uefiVariable = new UefiVariable(uefiVariableBytes);
UefiGuid guid = uefiVariable.getUefiVarGuid(); UefiGuid guid = uefiVariable.getUefiVarGuid();
@ -83,7 +87,7 @@ public class UefiProcessingTest {
uefiTxt = IOUtils.toString(this.getClass() uefiTxt = IOUtils.toString(this.getClass()
.getResourceAsStream(UEFI_VARIABLE_BOOT_SECURE_BOOT), .getResourceAsStream(UEFI_VARIABLE_BOOT_SECURE_BOOT),
"UTF-8"); StandardCharsets.UTF_8);
uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt); uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt);
uefiVariable = new UefiVariable(uefiVariableBytes); uefiVariable = new UefiVariable(uefiVariableBytes);
guid = uefiVariable.getUefiVarGuid(); guid = uefiVariable.getUefiVarGuid();
@ -94,7 +98,7 @@ public class UefiProcessingTest {
Assertions.assertEquals("SecureBoot", varName); Assertions.assertEquals("SecureBoot", varName);
uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream( 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); uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt);
uefiVariable = new UefiVariable(uefiVariableBytes); uefiVariable = new UefiVariable(uefiVariableBytes);
varName = uefiVariable.getEfiVarName(); varName = uefiVariable.getEfiVarName();
@ -107,7 +111,7 @@ public class UefiProcessingTest {
* @throws IOException when processing the test fails. * @throws IOException when processing the test fails.
* @throws NoSuchAlgorithmException if non TCG Algorithm is encountered. * @throws NoSuchAlgorithmException if non TCG Algorithm is encountered.
* @throws CertificateException if parsing issue for X509 cert is encountered. * @throws CertificateException if parsing issue for X509 cert is encountered.
* @throws URISyntaxException File location exception * @throws URISyntaxException File location exception
*/ */
@Test @Test
public final void testUefiPartiton() throws IOException, public final void testUefiPartiton() throws IOException,
@ -116,7 +120,7 @@ public class UefiProcessingTest {
Path jsonPath = Paths.get(this.getClass() Path jsonPath = Paths.get(this.getClass()
.getResource(JSON_FILE).toURI()); .getResource(JSON_FILE).toURI());
String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_GPT_EVENT), String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_GPT_EVENT),
"UTF-8"); StandardCharsets.UTF_8);
byte[] uefiPartitionBytes = HexUtils.hexStringToByteArray(uefiTxt); byte[] uefiPartitionBytes = HexUtils.hexStringToByteArray(uefiTxt);
UefiPartition gptPart = new UefiPartition(uefiPartitionBytes); UefiPartition gptPart = new UefiPartition(uefiPartitionBytes);
String gptPartName = gptPart.getPartitionName(); String gptPartName = gptPart.getPartitionName();
@ -143,29 +147,33 @@ public class UefiProcessingTest {
CertificateException, NoSuchAlgorithmException { CertificateException, NoSuchAlgorithmException {
LOGGER.debug("Testing the parsing of Uefi Firmware Blob"); LOGGER.debug("Testing the parsing of Uefi Firmware Blob");
String uefiTxt = IOUtils.toString(this.getClass() String uefiTxt = IOUtils.toString(this.getClass()
.getResourceAsStream(UEFI_FW_BLOB), "UTF-8"); .getResourceAsStream(UEFI_FW_BLOB), StandardCharsets.UTF_8);
byte[] uefiFwBlobBytes = HexUtils.hexStringToByteArray(uefiTxt); byte[] uefiFwBlobBytes = HexUtils.hexStringToByteArray(uefiTxt);
UefiFirmware uefiFWBlob = new UefiFirmware(uefiFwBlobBytes); UefiFirmware uefiFWBlob = new UefiFirmware(uefiFwBlobBytes);
int fwAddress = uefiFWBlob.getPhysicalBlobAddress(); int fwAddress = uefiFWBlob.getPhysicalBlobAddress();
int fwLength = uefiFWBlob.getBlobLength(); 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);
} }
/** /**
* Tests the processing of a UEFI defined Device Path. * Tests the processing of a UEFI defined Device Path.
* *
* @throws IOException when processing the test fails. * @throws IOException when processing the test fails.
* @throws URISyntaxException File location exception * @throws URISyntaxException File location exception
*/ */
@Test @Test
public final void testUefiDevicePath() throws IOException, URISyntaxException { public final void testUefiDevicePath() throws IOException, URISyntaxException {
LOGGER.debug("Testing the parsing of Uefi Device Path"); LOGGER.debug("Testing the parsing of Uefi Device Path");
String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_DEVICE_PATH), String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_DEVICE_PATH),
"UTF-8"); StandardCharsets.UTF_8);
byte[] uefiFwBlobBytes = HexUtils.hexStringToByteArray(uefiTxt); byte[] uefiFwBlobBytes = HexUtils.hexStringToByteArray(uefiTxt);
UefiDevicePath uefiDevPath = new UefiDevicePath(uefiFwBlobBytes); UefiDevicePath uefiDevPath = new UefiDevicePath(uefiFwBlobBytes);
String devPathType = uefiDevPath.getType(); String devPathType = uefiDevPath.getType();
Assertions.assertEquals("Media Device Path", devPathType); Assertions.assertEquals("Media Device Path", devPathType);
} }
} }

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.apache.logging.log4j.util.Strings;
import org.junit.jupiter.api.Test; 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.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
/** /**
* Tests methods in the (@link BouncyCastleUtils) utility class. * Tests methods in the (@link BouncyCastleUtils) utility class.
@ -46,4 +47,4 @@ public class BouncyCastleUtilsTest {
assertFalse(BouncyCastleUtils.x500NameCompare( assertFalse(BouncyCastleUtils.x500NameCompare(
MALFORMED_RDN_STRING, MALFORMED_RDN_STRING)); MALFORMED_RDN_STRING, MALFORMED_RDN_STRING));
} }
} }

View File

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

View File

@ -1,11 +1,12 @@
package hirs.utils; package hirs.utils;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import org.mockito.Mockito;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows; import org.mockito.Mockito;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertEquals; 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; import static org.mockito.Mockito.times;
/** /**
@ -114,10 +115,10 @@ public class StringValidatorTest {
@Test @Test
public void testValidateMaxLengthFailOnLongString() { public void testValidateMaxLengthFailOnLongString() {
assertThrows(IllegalArgumentException.class, () -> assertThrows(IllegalArgumentException.class, () ->
assertEquals( assertEquals(
StringValidator.check(NONEMPTY_VALUE, FIELD_NAME).maxLength(SMALL_LENGTH).getValue(), StringValidator.check(NONEMPTY_VALUE, FIELD_NAME).maxLength(SMALL_LENGTH).getValue(),
NONEMPTY_VALUE NONEMPTY_VALUE
)); ));
} }
/** /**
@ -138,8 +139,8 @@ public class StringValidatorTest {
@Test @Test
public void testValidateSeveralConditionsFailOnLast() { public void testValidateSeveralConditionsFailOnLast() {
assertThrows(IllegalArgumentException.class, () -> assertThrows(IllegalArgumentException.class, () ->
StringValidator.check(NONEMPTY_VALUE, FIELD_NAME) StringValidator.check(NONEMPTY_VALUE, FIELD_NAME)
.notNull().notBlank().maxLength(SMALL_LENGTH)); .notNull().notBlank().maxLength(SMALL_LENGTH));
} }
/** /**
@ -155,4 +156,4 @@ public class StringValidatorTest {
} }
Mockito.verify(mockLogger, times(1)).error(Mockito.anyString()); Mockito.verify(mockLogger, times(1)).error(Mockito.anyString());
} }
} }

View File

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

View File

@ -1,20 +1,20 @@
package hirs.utils.tpm.eventlog; 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.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.util.Arrays; import java.util.Arrays;
import org.apache.commons.io.IOUtils; import static hirs.utils.tpm.eventlog.TCGEventLog.PCR_COUNT;
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 org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
@ -36,103 +36,117 @@ public class TCGEventLogTest {
@BeforeAll @BeforeAll
public static final void setup() { public static final void setup() {
LOGGER.debug("retrieving session factory"); LOGGER.debug("retrieving session factory");
} }
/** /**
* Closes the <code>SessionFactory</code> from setup. * Closes the <code>SessionFactory</code> from setup.
*/ */
@AfterAll @AfterAll
public static final void tearDown() { public static final void tearDown() {
LOGGER.debug("closing session factory"); LOGGER.debug("closing session factory");
} }
/** /**
* Tests the processing of a crypto agile event log. * 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 IOException when processing the test fails
* @throws CertificateException if a certificate fails to parse. * @throws NoSuchAlgorithmException if an unknown algorithm is encountered.
*/ * @throws CertificateException if a certificate fails to parse.
*/
@Test @Test
public final void testCryptoAgileTCGEventLog() throws IOException, CertificateException, public final void testCryptoAgileTCGEventLog() throws IOException, CertificateException,
NoSuchAlgorithmException { NoSuchAlgorithmException {
LOGGER.debug("Testing the parsing of a Crypto Agile formatted TCG Event Log"); LOGGER.debug("Testing the parsing of a Crypto Agile formatted TCG Event Log");
InputStream log, pcrs;
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++) {
if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) {
testPass = false;
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));
// Test 3 check the Algorithm String Identifier used in the log
String algStr = evlog.getEventLogHashAlgorithm();
assertThat("TPM_ALG_SHA256", equalTo(algStr));
// Test 4 check the Algorithm # Identifier used in the log try {
int id = evlog.getEventLogHashAlgorithmID(); // setup
assertThat(TcgTpmtHa.TPM_ALG_SHA256, equalTo(id)); final InputStream log = this.getClass().getResourceAsStream(DEFAULT_EVENT_LOG);
final InputStream pcrs = this.getClass().getResourceAsStream(DEFAULT_EXPECTED_PCRS);
LOGGER.debug("OK. Parsing of a Crypto Agile Format Success"); 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;
// Test 1 get all PCRs
for (int i = 0; i < PCR_COUNT; i++) {
if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) {
testPass = false;
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR {}", i);
}
}
assertTrue(testPass);
// Test 2 get an individual PCR
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();
assertThat("TPM_ALG_SHA256", equalTo(algStr));
// Test 4 check the Algorithm # Identifier used in the log
int id = evlog.getEventLogHashAlgorithmID();
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. * Tests the processing of a SHA1 formatted Event log.
* @throws IOException when processing the test fails *
* @throws IOException when processing the test fails
* @throws NoSuchAlgorithmException if an unknown algorithm is encountered. * @throws NoSuchAlgorithmException if an unknown algorithm is encountered.
* @throws CertificateException if a certificate fails to parse. * @throws CertificateException if a certificate fails to parse.
*/ */
@Test @Test
public final void testSHA1TCGEventLog() throws IOException, CertificateException, public final void testSHA1TCGEventLog() throws IOException, CertificateException,
NoSuchAlgorithmException { NoSuchAlgorithmException {
LOGGER.debug("Testing the parsing of a SHA1 formated TCG Event Log"); LOGGER.debug("Testing the parsing of a SHA1 formated TCG Event Log");
InputStream log, pcrs;
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++) {
if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) {
testPass = false;
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR " + i);
}
}
assertTrue(testPass);
// Test 2 get an individual PCR
String pcr0 = evlog.getExpectedPCRValue(0);
assertThat(pcrFromLog[0], equalTo(pcr0));
// Test 3 check the Algorithm String Identifier used in the log
String algStr = evlog.getEventLogHashAlgorithm();
assertThat("TPM_ALG_SHA1", equalTo(algStr));
// Test 4 check the Algorithm # Identifier used in the log try {
int id = evlog.getEventLogHashAlgorithmID(); // setup
assertThat(TcgTpmtHa.TPM_ALG_SHA1, equalTo(id)); final InputStream log = this.getClass().getResourceAsStream(SHA1_EVENT_LOG);
final InputStream pcrs = this.getClass().getResourceAsStream(SHA1_EXPECTED_PCRS);
LOGGER.debug("OK. Parsing of a SHA1 formatted TCG Event Log Success"); 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;
// Test 1 get all PCRs
for (int i = 0; i < PCR_COUNT; i++) {
if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) {
testPass = false;
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR {}", i);
}
}
assertTrue(testPass);
// Test 2 get an individual PCR
String pcr0 = evlog.getExpectedPCRValue(0);
assertThat(pcrFromLog[0], equalTo(pcr0));
// Test 3 check the Algorithm String Identifier used in the log
String algStr = evlog.getEventLogHashAlgorithm();
assertThat("TPM_ALG_SHA1", equalTo(algStr));
// Test 4 check the Algorithm # Identifier used in the log
int id = evlog.getEventLogHashAlgorithmID();
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 java.util.concurrent.TimeUnit
import org.gradle.api.tasks.Copy
plugins { plugins {
// Apply the application plugin to add support for building a CLI application in Java. // Apply the application plugin to add support for building a CLI application in Java.
@ -8,7 +7,7 @@ plugins {
} }
// Global checkstyle file // Global checkstyle file
ext.checkstyleConfigFile = new File(rootDir, "/config/checkstyle/sun_checks.xml") ext.checkstyleConfigFile = new File(rootDir, "/config/checkstyle/sun_checks.xml")
subprojects { subprojects {
apply plugin: "com.github.spotbugs" apply plugin: "com.github.spotbugs"
@ -19,13 +18,12 @@ subprojects {
tasks.withType(com.github.spotbugs.snom.SpotBugsTask) { tasks.withType(com.github.spotbugs.snom.SpotBugsTask) {
reports { reports {
html { html.required = true
enabled = true
}
} }
} }
} }
dependencies { dependencies {
repositories { repositories {
// Use Maven Central for resolving dependencies. // Use Maven Central for resolving dependencies.
@ -36,10 +34,10 @@ dependencies {
def projectVersion = rootProject.file('VERSION').text.trim() def projectVersion = rootProject.file('VERSION').text.trim()
def buildTime = { -> def buildTime = { ->
Date latestdate = new Date(); Date latestdate = new Date()
def time = latestdate.getTime(); def time = latestdate.getTime()
long seconds = TimeUnit.MILLISECONDS.toSeconds(time); long seconds = TimeUnit.MILLISECONDS.toSeconds(time)
return seconds; return seconds
} }
def gitHash = { -> def gitHash = { ->

View File

@ -109,7 +109,10 @@
<!-- Checks for Naming Conventions. --> <!-- Checks for Naming Conventions. -->
<!-- See https://checkstyle.org/checks/naming/index.html --> <!-- See https://checkstyle.org/checks/naming/index.html -->
<module name="ConstantName"/> <module name="ConstantName">
<property name="format"
value="[A-Z_][A-Z0-9]*(_[A-Z0-9]+)*$"/>
</module>
<module name="LocalFinalVariableName"/> <module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/> <module name="LocalVariableName"/>
<module name="MemberName"/> <module name="MemberName"/>
@ -163,10 +166,17 @@
<!-- See https://checkstyle.org/checks/coding/index.html --> <!-- See https://checkstyle.org/checks/coding/index.html -->
<module name="EmptyStatement"/> <module name="EmptyStatement"/>
<module name="EqualsHashCode"/> <module name="EqualsHashCode"/>
<module name="HiddenField"/> <module name="HiddenField">
<property name="tokens" value="VARIABLE_DEF"/>
</module>
<module name="IllegalInstantiation"/> <module name="IllegalInstantiation"/>
<module name="InnerAssignment"/> <module name="InnerAssignment"/>
<module name="MagicNumber"/> <module name="MagicNumber">
<property name="ignoreAnnotation" value="true"/>
<property name="ignoreFieldDeclaration" value="true"/>
<property name="constantWaiverParentToken" value="ASSIGN,ARRAY_INIT,EXPR,
UNARY_PLUS, UNARY_MINUS, TYPECAST, ELIST, LITERAL_NEW"/>
</module>
<module name="MissingSwitchDefault"/> <module name="MissingSwitchDefault"/>
<module name="MultipleVariableDeclarations"/> <module name="MultipleVariableDeclarations"/>
<module name="SimplifyBooleanExpression"/> <module name="SimplifyBooleanExpression"/>