mirror of
https://github.com/nsacyber/HIRS.git
synced 2024-12-22 22:32:27 +00:00
Merge branch 'main' into v3_issue_847-update-hirs_attestationca-caportal-for-checkstyle2
This commit is contained in:
commit
99188f17c1
.ci/docker
HIRS_Utils/src
main/java/hirs/utils
BannerConfiguration.javaHexUtils.javaJsonUtils.javaPciIds.javaSwidResource.java
digest
enums
exception
package-info.javarim
swid
tpm/eventlog
events
DeviceSecurityEventDataHeader.javaDeviceSecurityEventDataHeader2.javaDeviceSecurityEventDataPciContext.javaDeviceSecurityEventDataSubHeaderCertChain.javaDeviceSecurityEventDataSubHeaderSpdmMeasurementBlock.javaDeviceSecurityEventHeader.javaEvConstants.javaEvNoAction.javaNvIndexDynamicEventLogData.javaNvIndexInstanceEventLogData.java
spdm
uefi
test/java/hirs
data/persist
DigestTest.javaFirmwareInfoTest.javaHardwareInfoTest.javaNetworkInfoTest.javaOSInfoTest.javapackage-info.java
tpm/eventlog/uefi
utils
@ -12,6 +12,7 @@ services:
|
||||
hat:
|
||||
image: ghcr.io/nsacyber/hirs/hat
|
||||
container_name: hat
|
||||
privileged: true
|
||||
ports:
|
||||
- 53:53/tcp
|
||||
- 53:53/udp
|
||||
|
@ -23,14 +23,16 @@ import java.util.Properties;
|
||||
public class BannerConfiguration {
|
||||
|
||||
private static final Path BANNER_PROPERTIES_PATH = FileSystems.getDefault()
|
||||
.getPath("/opt/tomcat/webapps/HIRS_AttestationCAPortal", "WEB-INF", "classes", "banner.properties");
|
||||
.getPath("/opt/tomcat/webapps/HIRS_AttestationCAPortal",
|
||||
"WEB-INF", "classes", "banner.properties");
|
||||
|
||||
private static final String BANNER_COLOR = "banner.color";
|
||||
private static final String BANNER_STRING = "banner.string";
|
||||
private static final String BANNER_DYNAMIC = "banner.dynamic";
|
||||
private static final String LEFT_CONTENT = "left.content";
|
||||
private static final String RIGHT_CONTENT = "right.content";
|
||||
|
||||
private final ArrayList<String> leftContent = new ArrayList<>();
|
||||
private final ArrayList<String> rightContent = new ArrayList<>();
|
||||
@Getter
|
||||
private String bannerColor = "";
|
||||
@Getter
|
||||
@ -38,21 +40,18 @@ public class BannerConfiguration {
|
||||
@Getter
|
||||
private String bannerDynamic = "";
|
||||
|
||||
private final ArrayList<String> leftContent = new ArrayList<>();
|
||||
private final ArrayList<String> rightContent = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Banner Configuration default constructor.
|
||||
* Verify if the file exist, if it does it will get all the
|
||||
* properties values and save them on the class.
|
||||
*
|
||||
* @throws IOException the banner level for the web site.
|
||||
* @throws IOException the banner level for the website.
|
||||
*/
|
||||
public BannerConfiguration() throws IOException {
|
||||
if (!Files.exists(BANNER_PROPERTIES_PATH)) {
|
||||
log.info(String.format(
|
||||
"No file found at %s. Banner will not display.",
|
||||
BANNER_PROPERTIES_PATH.toString()
|
||||
BANNER_PROPERTIES_PATH
|
||||
));
|
||||
return;
|
||||
}
|
||||
@ -69,8 +68,8 @@ public class BannerConfiguration {
|
||||
/**
|
||||
* This method applies any dynamically configuration found in the properties file,
|
||||
* if it exists.
|
||||
* @param bannerProps
|
||||
* @return the banner level for the web site.
|
||||
*
|
||||
* @param bannerProps banner props
|
||||
*/
|
||||
private void setBannerProperties(final Properties bannerProps) {
|
||||
|
||||
@ -103,10 +102,7 @@ public class BannerConfiguration {
|
||||
* @return if the banner was set.
|
||||
*/
|
||||
public Boolean getHasBanner() {
|
||||
if (!bannerColor.isEmpty() || !bannerString.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return !bannerColor.isEmpty() || !bannerString.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,22 +7,24 @@ import java.math.BigInteger;
|
||||
*/
|
||||
public final class HexUtils {
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain
|
||||
*/
|
||||
private HexUtils() { }
|
||||
/**
|
||||
* The mathematical base for the hexadecimal representation.
|
||||
*/
|
||||
public static final int HEX_BASIS = 16;
|
||||
|
||||
/**
|
||||
* An integer representation of the byte 0xff or 255.
|
||||
*/
|
||||
public static final int FF_BYTE = 0xff;
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain.
|
||||
*/
|
||||
private HexUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a binary hex string to a byte array.
|
||||
*
|
||||
* @param s string to convert
|
||||
* @return byte array representation of s
|
||||
*/
|
||||
@ -40,6 +42,7 @@ public final class HexUtils {
|
||||
|
||||
/**
|
||||
* Converts a byte array to a hex represented binary string.
|
||||
*
|
||||
* @param b byte array to convert
|
||||
* @return hex string representation of array
|
||||
*/
|
||||
@ -58,6 +61,7 @@ public final class HexUtils {
|
||||
|
||||
/**
|
||||
* Converts an individual hex string to an integer.
|
||||
*
|
||||
* @param s an individual hex string
|
||||
* @return an integer representation of a hex string
|
||||
*/
|
||||
@ -68,6 +72,7 @@ public final class HexUtils {
|
||||
|
||||
/**
|
||||
* Takes a byte array returns a subset of the array.
|
||||
*
|
||||
* @param b the array to take a subset of
|
||||
* @param start the first index to copy
|
||||
* @param end the last index to copy (inclusive)
|
||||
@ -81,6 +86,7 @@ public final class HexUtils {
|
||||
|
||||
/**
|
||||
* Takes in a byte array and reverses the order.
|
||||
*
|
||||
* @param in byte array to reverse
|
||||
* @return reversed byte array
|
||||
*/
|
||||
@ -94,6 +100,7 @@ public final class HexUtils {
|
||||
|
||||
/**
|
||||
* Takes in a byte array and reverses the order then converts to an int.
|
||||
*
|
||||
* @param in byte array to reverse
|
||||
* @return integer that represents the reversed byte array
|
||||
*/
|
||||
@ -104,6 +111,7 @@ public final class HexUtils {
|
||||
|
||||
/**
|
||||
* Takes in a byte array of 4 bytes and returns a long.
|
||||
*
|
||||
* @param bytes byte array to convert
|
||||
* @return long representation of the bytes
|
||||
*/
|
||||
|
@ -21,9 +21,10 @@ import java.nio.file.Path;
|
||||
public final class JsonUtils {
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain
|
||||
* Default private constructor so checkstyles doesn't complain.
|
||||
*/
|
||||
private JsonUtils() { }
|
||||
private JsonUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for the JSON Object that is associated with the elementName value
|
||||
@ -85,7 +86,7 @@ public final class JsonUtils {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
|
||||
if (Files.notExists(jsonPath)) {
|
||||
log.warn(String.format("No file found at %s.", jsonPath.toString()));
|
||||
log.warn("No file found at {}.", jsonPath.toString());
|
||||
} else {
|
||||
try {
|
||||
InputStream inputStream = new FileInputStream(jsonPath.toString());
|
||||
|
@ -25,29 +25,24 @@ import java.util.List;
|
||||
@Log4j2
|
||||
public final class PciIds {
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain
|
||||
*/
|
||||
private PciIds() { }
|
||||
|
||||
/**
|
||||
* This pci ids file can be in different places on different distributions.
|
||||
*/
|
||||
public static final List<String> PCI_IDS_PATH =
|
||||
Collections.unmodifiableList(new ArrayList<>() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
{
|
||||
add("/usr/share/hwdata/pci.ids");
|
||||
add("/usr/share/misc/pci.ids");
|
||||
add("/tmp/pci.ids");
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The PCI IDs Database object.
|
||||
*
|
||||
* <p>
|
||||
* This only needs to be loaded one time.
|
||||
*
|
||||
* <p>
|
||||
* The pci ids library protects the data inside the object by making it immutable.
|
||||
*/
|
||||
public static final PciIdsDatabase DB = new PciIdsDatabase();
|
||||
@ -65,7 +60,7 @@ public final class PciIds {
|
||||
if (dbFile != null) {
|
||||
InputStream is = null;
|
||||
try {
|
||||
is = new FileInputStream(new File(dbFile));
|
||||
is = new FileInputStream(dbFile);
|
||||
DB.loadStream(is);
|
||||
} catch (IOException e) {
|
||||
// DB will not be ready, hardware IDs will not be translated
|
||||
@ -83,9 +78,16 @@ public final class PciIds {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain.
|
||||
*/
|
||||
private PciIds() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the vendor name from the PCI IDs list, if the input string contains an ID.
|
||||
* If any part of this fails, return the original manufacturer value.
|
||||
*
|
||||
* @param refManufacturer DERUTF8String, likely from a ComponentIdentifier
|
||||
* @return DERUTF8String with the discovered vendor name, or the original manufacturer value.
|
||||
*/
|
||||
@ -103,6 +105,7 @@ public final class PciIds {
|
||||
/**
|
||||
* Look up the vendor name from the PCI IDs list, if the input string contains an ID.
|
||||
* If any part of this fails, return the original manufacturer value.
|
||||
*
|
||||
* @param refManufacturer String, likely from a ComponentResult
|
||||
* @return String with the discovered vendor name, or the original manufacturer value.
|
||||
*/
|
||||
@ -121,6 +124,7 @@ public final class PciIds {
|
||||
* Look up the device name from the PCI IDs list, if the input strings contain IDs.
|
||||
* The Device lookup requires the Vendor ID AND the Device ID to be valid values.
|
||||
* If any part of this fails, return the original model value.
|
||||
*
|
||||
* @param refManufacturer ASN1UTF8String, likely from a ComponentIdentifier
|
||||
* @param refModel ASN1UTF8String, likely from a ComponentIdentifier
|
||||
* @return ASN1UTF8String with the discovered device name, or the original model value.
|
||||
@ -146,6 +150,7 @@ public final class PciIds {
|
||||
* Look up the device name from the PCI IDs list, if the input strings contain IDs.
|
||||
* The Device lookup requires the Vendor ID AND the Device ID to be valid values.
|
||||
* If any part of this fails, return the original model value.
|
||||
*
|
||||
* @param refManufacturer String, likely from a ComponentResult
|
||||
* @param refModel String, likely from a ComponentResult
|
||||
* @return String with the discovered device name, or the original model value.
|
||||
@ -169,6 +174,7 @@ public final class PciIds {
|
||||
/**
|
||||
* Look up the device class name from the PCI IDs list, if the input string contains an ID.
|
||||
* If any part of this fails, return the original manufacturer value.
|
||||
*
|
||||
* @param refClassCode String, formatted as 2 characters (1 byte) for each of the 3 categories
|
||||
* Example "010802":
|
||||
* Class: "01"
|
||||
@ -184,9 +190,23 @@ public final class PciIds {
|
||||
|
||||
String classCode = refClassCode;
|
||||
if (classCode != null && classCode.trim().matches("^[0-9A-Fa-f]{6}$")) {
|
||||
String deviceClass = classCode.substring(0, 2).toLowerCase();
|
||||
String deviceSubclass = classCode.substring(2, 4).toLowerCase();
|
||||
String programInterface = classCode.substring(4, 6).toLowerCase();
|
||||
final int startIndexOfDeviceClass = 0;
|
||||
final int endIndexOfDeviceClass = 2;
|
||||
String deviceClass =
|
||||
classCode.substring(startIndexOfDeviceClass, endIndexOfDeviceClass).toLowerCase();
|
||||
|
||||
final int startIndexOfDeviceSubclass = 2;
|
||||
final int endIndexOfDeviceSubclass = 4;
|
||||
String deviceSubclass =
|
||||
classCode.substring(startIndexOfDeviceSubclass, endIndexOfDeviceSubclass)
|
||||
.toLowerCase();
|
||||
|
||||
final int startIndexOfProgramInterface = 4;
|
||||
final int endIndexOfProgramInterface = 6;
|
||||
final String programInterface =
|
||||
classCode.substring(startIndexOfProgramInterface, endIndexOfProgramInterface)
|
||||
.toLowerCase();
|
||||
|
||||
translatedClassCode.add(deviceClass);
|
||||
translatedClassCode.add(deviceSubclass);
|
||||
translatedClassCode.add(programInterface);
|
||||
|
@ -18,15 +18,31 @@ import java.util.Map;
|
||||
@ToString
|
||||
public class SwidResource {
|
||||
|
||||
@Getter
|
||||
private static final boolean VALID_FILE_SIZE = false;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String name, size, hashValue;
|
||||
private String name;
|
||||
|
||||
@Getter
|
||||
private String rimFormat, rimType, rimUriGlobal;
|
||||
// private TpmWhiteListBaseline tpmWhiteList;
|
||||
@Setter
|
||||
private String size;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
private String hashValue;
|
||||
|
||||
@Getter
|
||||
private String rimFormat;
|
||||
|
||||
@Getter
|
||||
private String rimType;
|
||||
|
||||
@Getter
|
||||
private String rimUriGlobal;
|
||||
// private TpmWhiteListBaseline tpmWhiteList;
|
||||
private DigestAlgorithm digest = DigestAlgorithm.SHA1;
|
||||
@Getter
|
||||
private boolean validFileSize = false;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
|
@ -15,8 +15,8 @@ import java.util.regex.Pattern;
|
||||
* <p>
|
||||
* Two classes were made to facilitate persisting them with Hibernate in different ways.
|
||||
* To persist non-nullable entries in an embedded collection, use {@link hirs.utils.digest.Digest} (see
|
||||
* {@link TPMBaseline} for reference.) To persist nullable entries, use {@link hirs.utils.digest.OptionalDigest}
|
||||
* (see {@link ImaBlacklistRecord} for reference.)
|
||||
* {@link TPMBaseline} for reference.) To persist nullable entries,
|
||||
* use {@link hirs.utils.digest.OptionalDigest} (see {@link ImaBlacklistRecord} for reference.)
|
||||
*/
|
||||
@Log4j2
|
||||
public abstract class AbstractDigest {
|
||||
@ -45,30 +45,6 @@ public abstract class AbstractDigest {
|
||||
*/
|
||||
public static final int SHA512_DIGEST_LENGTH = 64;
|
||||
|
||||
/**
|
||||
* Ensures the given algorithm type and digest byte array represent a valid digest.
|
||||
* This includes ensuring they are both not null or empty and ensuring that the length of the
|
||||
* digest matches the expected amount of data for the given algorithm.
|
||||
*
|
||||
* @param algorithm a digest algorithm
|
||||
* @param digest the digest computed by this algorithm
|
||||
* @throws IllegalArgumentException if the provided input does not represent a valid digest
|
||||
*/
|
||||
void validateInput(final DigestAlgorithm algorithm, final byte[] digest)
|
||||
throws IllegalArgumentException {
|
||||
if (algorithm == null) {
|
||||
throw new IllegalArgumentException("Algorithm must not be null");
|
||||
}
|
||||
|
||||
if (ArrayUtils.isEmpty(digest)) {
|
||||
throw new IllegalArgumentException("Digest must have at least one byte");
|
||||
}
|
||||
|
||||
if (digest.length != algorithm.getLengthInBytes()) {
|
||||
throw new AbstractDigest.IllegalDigestLength(algorithm, digest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will help class determine the algorithm associated with the
|
||||
* pcr values given.
|
||||
@ -114,6 +90,61 @@ public abstract class AbstractDigest {
|
||||
return DigestAlgorithm.UNSPECIFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a {@link DigestAlgorithm} from a String returned by {@link AbstractDigest#toString()}.
|
||||
*
|
||||
* @param digest the digest string as computed above
|
||||
* @return the DigestAlgorithm component of the String
|
||||
*/
|
||||
static DigestAlgorithm algorithmFromString(final String digest) {
|
||||
return DigestAlgorithm.findByString(matchString(digest).group(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a digest from a String returned by {@link AbstractDigest#toString()}.
|
||||
*
|
||||
* @param digest the digest string as computed above
|
||||
* @return the byte array representing the actual digest
|
||||
*/
|
||||
static byte[] digestFromString(final String digest) {
|
||||
return DatatypeConverter.parseHexBinary(matchString(digest).group(2));
|
||||
}
|
||||
|
||||
private static Matcher matchString(final String digest) {
|
||||
Pattern digestPattern = Pattern.compile("(.*) - 0x(.*)");
|
||||
Matcher matcher = digestPattern.matcher(digest);
|
||||
if (!matcher.matches()) {
|
||||
String message = String.format("String \"%s\" did not match pattern \"%s\"", digest,
|
||||
digestPattern);
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
return matcher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the given algorithm type and digest byte array represent a valid digest.
|
||||
* This includes ensuring they are both not null or empty and ensuring that the length of the
|
||||
* digest matches the expected amount of data for the given algorithm.
|
||||
*
|
||||
* @param algorithm a digest algorithm
|
||||
* @param digest the digest computed by this algorithm
|
||||
* @throws IllegalArgumentException if the provided input does not represent a valid digest
|
||||
*/
|
||||
void validateInput(final DigestAlgorithm algorithm, final byte[] digest)
|
||||
throws IllegalArgumentException {
|
||||
if (algorithm == null) {
|
||||
throw new IllegalArgumentException("Algorithm must not be null");
|
||||
}
|
||||
|
||||
if (ArrayUtils.isEmpty(digest)) {
|
||||
throw new IllegalArgumentException("Digest must have at least one byte");
|
||||
}
|
||||
|
||||
if (digest.length != algorithm.getLengthInBytes()) {
|
||||
throw new AbstractDigest.IllegalDigestLength(algorithm, digest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the <code>DigestAlgorithm</code> that identifies which hash
|
||||
* function generated the digest.
|
||||
@ -140,6 +171,7 @@ public abstract class AbstractDigest {
|
||||
|
||||
/**
|
||||
* Compares this digest's hash with another digest's hash.
|
||||
*
|
||||
* @param otherDigest a Digest to compare to.
|
||||
* @return the comparison result type.
|
||||
*/
|
||||
@ -155,37 +187,6 @@ public abstract class AbstractDigest {
|
||||
return DigestComparisonResultType.MISMATCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a {@link DigestAlgorithm} from a String returned by {@link AbstractDigest#toString()}.
|
||||
*
|
||||
* @param digest the digest string as computed above
|
||||
* @return the DigestAlgorithm component of the String
|
||||
*/
|
||||
static DigestAlgorithm algorithmFromString(final String digest) {
|
||||
return DigestAlgorithm.findByString(matchString(digest).group(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a digest from a String returned by {@link AbstractDigest#toString()}.
|
||||
*
|
||||
* @param digest the digest string as computed above
|
||||
* @return the byte array representing the actual digest
|
||||
*/
|
||||
static byte[] digestFromString(final String digest) {
|
||||
return DatatypeConverter.parseHexBinary(matchString(digest).group(2));
|
||||
}
|
||||
|
||||
private static Matcher matchString(final String digest) {
|
||||
Pattern digestPattern = Pattern.compile("(.*) - 0x(.*)");
|
||||
Matcher matcher = digestPattern.matcher(digest);
|
||||
if (!matcher.matches()) {
|
||||
String message = String.format("String \"%s\" did not match pattern \"%s\"", digest,
|
||||
digestPattern.toString());
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
return matcher;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
final int prime = 31;
|
||||
@ -201,21 +202,15 @@ public abstract class AbstractDigest {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || !(obj instanceof AbstractDigest)) {
|
||||
if (obj == null || !(obj instanceof AbstractDigest other)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AbstractDigest other = (AbstractDigest) obj;
|
||||
|
||||
if (getAlgorithm() != other.getAlgorithm()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Arrays.equals(getDigest(), other.getDigest())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return Arrays.equals(getDigest(), other.getDigest());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,12 +50,11 @@ public enum DigestAlgorithm {
|
||||
* options for standardAlgorithmName. Throws an IllegalArgumentException if no Enum exists with
|
||||
* that value.
|
||||
*
|
||||
* @param standardAlgorithmName
|
||||
* String value of the Enum
|
||||
* @param standardAlgorithmName String value of the Enum
|
||||
* @return DigestAlgorithm object
|
||||
*/
|
||||
public static DigestAlgorithm findByString(final String standardAlgorithmName) {
|
||||
for (DigestAlgorithm algorithm: DigestAlgorithm.values()) {
|
||||
for (DigestAlgorithm algorithm : DigestAlgorithm.values()) {
|
||||
if (algorithm.getStandardAlgorithmName().equals(standardAlgorithmName)) {
|
||||
return algorithm;
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
package hirs.utils.digest;
|
@ -2,11 +2,6 @@ package hirs.utils.enums;
|
||||
|
||||
public final class DeviceInfoEnums {
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain
|
||||
*/
|
||||
private DeviceInfoEnums() { }
|
||||
|
||||
/**
|
||||
* A variable used to describe unavailable hardware, firmware, or OS info.
|
||||
*/
|
||||
@ -23,4 +18,9 @@ public final class DeviceInfoEnums {
|
||||
* Constant variable representing the various Long sized strings.
|
||||
*/
|
||||
public static final int LONG_STRING_LENGTH = 255;
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain.
|
||||
*/
|
||||
private DeviceInfoEnums() {
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
package hirs.utils.enums;
|
@ -0,0 +1 @@
|
||||
package hirs.utils.exception;
|
1
HIRS_Utils/src/main/java/hirs/utils/package-info.java
Normal file
1
HIRS_Utils/src/main/java/hirs/utils/package-info.java
Normal file
@ -0,0 +1 @@
|
||||
package hirs.utils;
|
@ -5,10 +5,11 @@ import jakarta.xml.bind.JAXBContext;
|
||||
import jakarta.xml.bind.JAXBException;
|
||||
import jakarta.xml.bind.UnmarshalException;
|
||||
import jakarta.xml.bind.Unmarshaller;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.bouncycastle.asn1.x509.Extension;
|
||||
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
|
||||
import org.bouncycastle.jcajce.provider.asymmetric.X509;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
@ -47,7 +48,7 @@ import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.InvalidKeyException;
|
||||
@ -86,105 +87,29 @@ public class ReferenceManifestValidator {
|
||||
|
||||
private Document rim;
|
||||
private Unmarshaller unmarshaller;
|
||||
|
||||
@Getter
|
||||
private PublicKey publicKey;
|
||||
|
||||
private Schema schema;
|
||||
|
||||
@Getter
|
||||
private String subjectKeyIdentifier;
|
||||
|
||||
@Setter
|
||||
private String rimEventLog;
|
||||
|
||||
@Setter
|
||||
private String trustStoreFile;
|
||||
|
||||
@Setter
|
||||
private List<X509Certificate> trustStore;
|
||||
private boolean signatureValid, supportRimValid;
|
||||
|
||||
/**
|
||||
* Setter for the RIM to be validated. The ReferenceManifest object is converted into a
|
||||
* Document for processing.
|
||||
*
|
||||
* @param rimBytes ReferenceManifest object bytes
|
||||
*/
|
||||
public void setRim(final byte[] rimBytes) {
|
||||
try {
|
||||
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(
|
||||
new ByteArrayInputStream(rimBytes))));
|
||||
this.rim = doc;
|
||||
} catch (IOException e) {
|
||||
log.error("Error while unmarshalling rim bytes: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@Getter
|
||||
private boolean signatureValid;
|
||||
|
||||
/**
|
||||
* Setter for the swidtag XML to be validated. The XML is passed in via a filepath
|
||||
* and converted into a Document for processing.
|
||||
*
|
||||
* @param path String filepath
|
||||
*/
|
||||
public void setRim(final String path) {
|
||||
File swidtagFile = new File(path);
|
||||
try {
|
||||
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(swidtagFile)));
|
||||
this.rim = doc;
|
||||
} catch (IOException e) {
|
||||
log.error("Error while unmarshalling rim bytes: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for signatureValid.
|
||||
*
|
||||
* @return true if valid, false if not.
|
||||
*/
|
||||
public boolean isSignatureValid() {
|
||||
return signatureValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for supportRimValid.
|
||||
*
|
||||
* @return true if valid, false if not.
|
||||
*/
|
||||
public boolean isSupportRimValid() {
|
||||
return supportRimValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for certificate PublicKey.
|
||||
*
|
||||
* @return PublicKey
|
||||
*/
|
||||
public PublicKey getPublicKey() {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for subjectKeyIdentifier.
|
||||
*
|
||||
* @return subjectKeyIdentifier
|
||||
*/
|
||||
public String getSubjectKeyIdentifier() {
|
||||
return subjectKeyIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the truststore file path.
|
||||
* @param trustStoreFile the file path to reference
|
||||
*/
|
||||
public void setTrustStoreFile(String trustStoreFile) {
|
||||
this.trustStoreFile = trustStoreFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for truststore
|
||||
* @param trustStore the List of X509Certificates
|
||||
*/
|
||||
public void setTrustStore(List<X509Certificate> trustStore) {
|
||||
this.trustStore = trustStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for rimel file path.
|
||||
* @param rimEventLog the rimel file
|
||||
*/
|
||||
public void setRimEventLog(String rimEventLog) {
|
||||
this.rimEventLog = rimEventLog;
|
||||
}
|
||||
@Getter
|
||||
private boolean supportRimValid;
|
||||
|
||||
/**
|
||||
* This default constructor creates the Schema object from SCHEMA_URL immediately to save
|
||||
@ -209,6 +134,38 @@ public class ReferenceManifestValidator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the RIM to be validated. The ReferenceManifest object is converted into a
|
||||
* Document for processing.
|
||||
*
|
||||
* @param rimBytes ReferenceManifest object bytes
|
||||
*/
|
||||
public void setRim(final byte[] rimBytes) {
|
||||
try {
|
||||
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(
|
||||
new ByteArrayInputStream(rimBytes))));
|
||||
this.rim = doc;
|
||||
} catch (IOException e) {
|
||||
log.error("Error while unmarshalling rim bytes: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for the swidtag XML to be validated. The XML is passed in via a filepath
|
||||
* and converted into a Document for processing.
|
||||
*
|
||||
* @param path String filepath
|
||||
*/
|
||||
public void setRim(final String path) {
|
||||
File swidtagFile = new File(path);
|
||||
try {
|
||||
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(swidtagFile)));
|
||||
this.rim = doc;
|
||||
} catch (IOException e) {
|
||||
log.error("Error while unmarshalling rim bytes: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method attempts to validate the signature element of the instance's RIM
|
||||
* using a given cert. The cert is compared to either the RIM's embedded certificate
|
||||
@ -257,7 +214,7 @@ public class ReferenceManifestValidator {
|
||||
return signatureValid;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Error while parsing certificate data: " + e.getMessage());
|
||||
log.warn("Error while parsing certificate data: {}", e.getMessage());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -267,25 +224,26 @@ public class ReferenceManifestValidator {
|
||||
|
||||
/**
|
||||
* This method validates the rim with a public key cert.
|
||||
*
|
||||
* @param signingCertPath to the public key certificate used to sign the rim
|
||||
* @return true if both the file element and signature are valid, false otherwise
|
||||
*/
|
||||
public boolean validateRim(String signingCertPath) {
|
||||
public boolean validateRim(final String signingCertPath) {
|
||||
Element fileElement = (Element) rim.getElementsByTagNameNS(
|
||||
SwidTagConstants.SWIDTAG_NAMESPACE, "File").item(0);
|
||||
X509Certificate signingCert = parseCertificatesFromPem(signingCertPath).get(0);
|
||||
if (signingCert == null) {
|
||||
return failWithError("Unable to parse the signing cert from " + signingCertPath);
|
||||
}
|
||||
String subjectKeyIdentifier = "";
|
||||
String retrievedSubjectKeyIdentifier = "";
|
||||
try {
|
||||
subjectKeyIdentifier = getCertificateSubjectKeyIdentifier(signingCert);
|
||||
retrievedSubjectKeyIdentifier = getCertificateSubjectKeyIdentifier(signingCert);
|
||||
} catch (IOException e) {
|
||||
return failWithError("Error while parsing SKID: " + e.getMessage());
|
||||
}
|
||||
|
||||
boolean isSignatureValid = validateXmlSignature(signingCert.getPublicKey(),
|
||||
subjectKeyIdentifier,
|
||||
retrievedSubjectKeyIdentifier,
|
||||
signingCert.getPublicKey().getEncoded());
|
||||
return isSignatureValid && validateFile(fileElement);
|
||||
}
|
||||
@ -301,13 +259,15 @@ public class ReferenceManifestValidator {
|
||||
String calculatedHash = getHashValue(input, SHA256);
|
||||
supportRimValid = calculatedHash.equals(expected);
|
||||
if (!supportRimValid) {
|
||||
log.info("Unmatched support RIM hash! Expected: " + expected
|
||||
+ ", actual: " + calculatedHash);
|
||||
log.info("Unmatched support RIM hash! Expected: {}, actual: {}", expected, calculatedHash);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method validates a hirs.swid.xjc.File from an indirect payload
|
||||
* This method validates a hirs.swid.xjc.File from an indirect payload.
|
||||
*
|
||||
* @param file file extracted from element
|
||||
* @return true if the provided file is valid, false otherwise
|
||||
*/
|
||||
private boolean validateFile(final Element file) {
|
||||
String filepath;
|
||||
@ -317,9 +277,9 @@ public class ReferenceManifestValidator {
|
||||
filepath = file.getAttribute(SwidTagConstants.NAME);
|
||||
}
|
||||
if (getHashValue(filepath, "SHA256").equals(
|
||||
file.getAttribute(SwidTagConstants._SHA256_HASH.getPrefix() + ":" +
|
||||
SwidTagConstants._SHA256_HASH.getLocalPart()))) {
|
||||
log.info("Support RIM hash verified for " + filepath);
|
||||
file.getAttribute(SwidTagConstants._SHA256_HASH.getPrefix() + ":"
|
||||
+ SwidTagConstants._SHA256_HASH.getLocalPart()))) {
|
||||
log.info("Support RIM hash verified for {}", filepath);
|
||||
return true;
|
||||
} else {
|
||||
return failWithError("Support RIM hash does not match Base RIM!");
|
||||
@ -333,10 +293,10 @@ public class ReferenceManifestValidator {
|
||||
* @return X509Certificate signing cert
|
||||
*/
|
||||
private X509Certificate getCertFromTruststore() throws IOException {
|
||||
String subjectKeyIdentifier = getKeyName(rim);
|
||||
String retrievedSubjectKeyIdentifier = getKeyName(rim);
|
||||
for (X509Certificate trustedCert : trustStore) {
|
||||
String trustedSubjectKeyIdentifier = getCertificateSubjectKeyIdentifier(trustedCert);
|
||||
if (subjectKeyIdentifier.equals(trustedSubjectKeyIdentifier)) {
|
||||
if (retrievedSubjectKeyIdentifier.equals(trustedSubjectKeyIdentifier)) {
|
||||
return trustedCert;
|
||||
}
|
||||
}
|
||||
@ -345,7 +305,7 @@ public class ReferenceManifestValidator {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calculates the digest of the file at filepath based on algorithm sha
|
||||
* This method calculates the digest of the file at filepath based on algorithm sha.
|
||||
*
|
||||
* @param filepath the file to hash
|
||||
* @param sha the algorithm to use
|
||||
@ -359,11 +319,12 @@ public class ReferenceManifestValidator {
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
log.warn(e.getMessage());
|
||||
} catch (IOException e) {
|
||||
log.warn("Error reading " + filepath + " for hashing: " + e.getMessage());
|
||||
log.warn("Error reading {} for hashing: {}", filepath, e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method calculates the digest of a byte array based on the hashing algorithm passed in.
|
||||
*
|
||||
@ -401,9 +362,9 @@ public class ReferenceManifestValidator {
|
||||
whySignatureInvalid(signature, context);
|
||||
}
|
||||
} catch (MarshalException e) {
|
||||
log.warn("Error while unmarshalling XML signature: " + e.getMessage());
|
||||
log.warn("Error while unmarshalling XML signature: {}", e.getMessage());
|
||||
} catch (XMLSignatureException e) {
|
||||
log.warn("Error while validating XML signature: " + e.getMessage());
|
||||
log.warn("Error while validating XML signature: {}", e.getMessage());
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -419,7 +380,7 @@ public class ReferenceManifestValidator {
|
||||
* @throws XMLSignatureException
|
||||
*/
|
||||
private void whySignatureInvalid(final XMLSignature signature, final DOMValidateContext context)
|
||||
throws XMLSignatureException{
|
||||
throws XMLSignatureException {
|
||||
boolean cryptoValidity = signature.getSignatureValue().validate(context);
|
||||
if (cryptoValidity) {
|
||||
log.error("Signature value is valid.");
|
||||
@ -435,9 +396,9 @@ public class ReferenceManifestValidator {
|
||||
refUri = "whole document";
|
||||
}
|
||||
if (refValidity) {
|
||||
log.error("Reference for " + refUri + " is valid.");
|
||||
log.error("Reference for {} is valid.", refUri);
|
||||
} else {
|
||||
log.error("Reference for " + refUri + " is invalid!");
|
||||
log.error("Reference for {} is invalid!", refUri);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -445,6 +406,7 @@ public class ReferenceManifestValidator {
|
||||
/**
|
||||
* This method validates the cert chain for a given certificate. The truststore is iterated
|
||||
* over until a root CA is found, otherwise an error is returned.
|
||||
*
|
||||
* @param cert the certificate at the start of the chain
|
||||
* @return true if the chain is valid
|
||||
* @throws Exception if a valid chain is not found in the truststore
|
||||
@ -462,7 +424,7 @@ public class ReferenceManifestValidator {
|
||||
boolean isChainCertValid;
|
||||
do {
|
||||
isChainCertValid = false;
|
||||
log.info("Validating " + chainCert.getSubjectX500Principal().getName());
|
||||
log.info("Validating {}", chainCert.getSubjectX500Principal().getName());
|
||||
for (X509Certificate trustedCert : trustStore) {
|
||||
boolean isIssuer = areYouMyIssuer(chainCert, trustedCert);
|
||||
boolean isSigner = areYouMySigner(chainCert, trustedCert);
|
||||
@ -490,13 +452,14 @@ public class ReferenceManifestValidator {
|
||||
}
|
||||
} while (isChainCertValid);
|
||||
|
||||
log.error("CA chain validation failed to validate "
|
||||
+ chainCert.getSubjectX500Principal().getName() + ", " + errorMessage);
|
||||
log.error("CA chain validation failed to validate {}, {}",
|
||||
chainCert.getSubjectX500Principal().getName(), errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks if cert's issuerDN matches issuer's subjectDN.
|
||||
*
|
||||
* @param cert the signed certificate
|
||||
* @param issuer the signing certificate
|
||||
* @return true if they match, false if not
|
||||
@ -512,6 +475,7 @@ public class ReferenceManifestValidator {
|
||||
|
||||
/**
|
||||
* This method checks if cert's issuerDN matches issuer's subjectDN.
|
||||
*
|
||||
* @param cert the signed certificate
|
||||
* @param issuer the signing certificate
|
||||
* @return true if they match, false if not
|
||||
@ -528,6 +492,7 @@ public class ReferenceManifestValidator {
|
||||
|
||||
/**
|
||||
* This method checks if cert's signature matches signer's public key.
|
||||
*
|
||||
* @param cert the signed certificate
|
||||
* @param signer the signing certificate
|
||||
* @return true if they match
|
||||
@ -562,6 +527,7 @@ public class ReferenceManifestValidator {
|
||||
|
||||
/**
|
||||
* This method checks if a given certificate is self signed or not.
|
||||
*
|
||||
* @param cert the cert to check
|
||||
* @return true if self signed, false if not
|
||||
*/
|
||||
@ -569,128 +535,6 @@ public class ReferenceManifestValidator {
|
||||
return cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal());
|
||||
}
|
||||
|
||||
/**
|
||||
* This internal class handles selecting an X509 certificate embedded in a KeyInfo element.
|
||||
* It is passed as a parameter to a DOMValidateContext that uses it to validate
|
||||
* an XML signature.
|
||||
*/
|
||||
public class X509KeySelector extends KeySelector {
|
||||
PublicKey publicKey;
|
||||
X509Certificate signingCert;
|
||||
/**
|
||||
* This method selects a public key for validation.
|
||||
* PKs are parsed preferentially from the following elements:
|
||||
* - X509Data
|
||||
* - KeyValue
|
||||
* The parsed PK is then verified based on the provided algorithm before
|
||||
* being returned in a KeySelectorResult.
|
||||
*
|
||||
* @param keyinfo object containing the cert.
|
||||
* @param purpose purpose.
|
||||
* @param algorithm algorithm.
|
||||
* @param context XMLCryptoContext.
|
||||
* @return KeySelectorResult holding the PublicKey.
|
||||
* @throws KeySelectorException exception.
|
||||
*/
|
||||
public KeySelectorResult select(final KeyInfo keyinfo,
|
||||
final KeySelector.Purpose purpose,
|
||||
final AlgorithmMethod algorithm,
|
||||
final XMLCryptoContext context)
|
||||
throws KeySelectorException {
|
||||
Iterator keyinfoItr = keyinfo.getContent().iterator();
|
||||
while (keyinfoItr.hasNext()) {
|
||||
XMLStructure element = (XMLStructure) keyinfoItr.next();
|
||||
if (element instanceof X509Data) {
|
||||
X509Data data = (X509Data) element;
|
||||
Iterator dataItr = data.getContent().iterator();
|
||||
while (dataItr.hasNext()) {
|
||||
Object object = dataItr.next();
|
||||
if (object instanceof X509Certificate) {
|
||||
X509Certificate embeddedCert = (X509Certificate) object;
|
||||
try {
|
||||
if (isCertChainValid(embeddedCert)) {
|
||||
publicKey = ((X509Certificate) embeddedCert).getPublicKey();
|
||||
signingCert = embeddedCert;
|
||||
log.info("Certificate chain valid.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Certificate chain invalid: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (element instanceof KeyValue) {
|
||||
try {
|
||||
PublicKey pk = ((KeyValue) element).getPublicKey();
|
||||
if (isPublicKeyTrusted(pk)) {
|
||||
publicKey = pk;
|
||||
try {
|
||||
if (isCertChainValid(signingCert)) {
|
||||
log.info("Certificate chain valid.");
|
||||
} else {
|
||||
log.error("Certificate chain invalid.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Certificate chain invalid: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
} catch (KeyException e) {
|
||||
log.error("Unable to convert KeyValue data to PK.");
|
||||
}
|
||||
}
|
||||
if (publicKey != null) {
|
||||
if (areAlgorithmsEqual(algorithm.getAlgorithm(), publicKey.getAlgorithm())) {
|
||||
return new ReferenceManifestValidator.X509KeySelector
|
||||
.RIMKeySelectorResult(publicKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new KeySelectorException("No key found!");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks that the signature and public key algorithms match.
|
||||
* @param uri to match the signature algorithm
|
||||
* @param name to match the public key algorithm
|
||||
* @return true if both match, false otherwise
|
||||
*/
|
||||
public boolean areAlgorithmsEqual(String uri, String name) {
|
||||
return uri.equals(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256)
|
||||
&& name.equalsIgnoreCase("RSA");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method compares a public key against those in the truststore.
|
||||
* @param pk a public key
|
||||
* @return true if pk is found in the trust store, false otherwise
|
||||
*/
|
||||
private boolean isPublicKeyTrusted(final PublicKey pk) {
|
||||
for (X509Certificate trustedCert : trustStore) {
|
||||
if (Arrays.equals(trustedCert.getPublicKey().getEncoded(),
|
||||
pk.getEncoded())) {
|
||||
signingCert = trustedCert;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This internal class creates a KeySelectorResult from the public key.
|
||||
*/
|
||||
private static class RIMKeySelectorResult implements KeySelectorResult {
|
||||
private Key key;
|
||||
|
||||
RIMKeySelectorResult(final Key key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public Key getKey() {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method extracts certificate bytes from a string. The bytes are assumed to be
|
||||
* PEM format, and a header and footer are concatenated with the input string to
|
||||
@ -709,12 +553,10 @@ public class ReferenceManifestValidator {
|
||||
+ System.lineSeparator()
|
||||
+ pemString
|
||||
+ System.lineSeparator()
|
||||
+ certificateFooter).getBytes("UTF-8"));
|
||||
+ certificateFooter).getBytes(StandardCharsets.UTF_8));
|
||||
return (X509Certificate) factory.generateCertificate(inputStream);
|
||||
} catch (CertificateException e) {
|
||||
log.warn("Error creating CertificateFactory instance: " + e.getMessage());
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
log.warn("Error while parsing cert from PEM string: " + e.getMessage());
|
||||
log.warn("Error creating CertificateFactory instance: {}", e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -724,11 +566,12 @@ public class ReferenceManifestValidator {
|
||||
* This method returns the X509Certificates found in a PEM file.
|
||||
* Unchecked type case warnings are suppressed because the CertificateFactory
|
||||
* implements X509Certificate objects explicitly.
|
||||
*
|
||||
* @param filename pem file
|
||||
* @return a list containing all X509Certificates extracted
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<X509Certificate> parseCertificatesFromPem(String filename) {
|
||||
private List<X509Certificate> parseCertificatesFromPem(final String filename) {
|
||||
List<X509Certificate> certificates = null;
|
||||
FileInputStream fis = null;
|
||||
BufferedInputStream bis = null;
|
||||
@ -742,14 +585,14 @@ public class ReferenceManifestValidator {
|
||||
(List<X509Certificate>) certificateFactory.generateCertificates(bis);
|
||||
}
|
||||
|
||||
if (certificates.size() < 1) {
|
||||
if (certificates.isEmpty()) {
|
||||
System.out.println("ERROR: No certificates parsed from " + filename);
|
||||
}
|
||||
bis.close();
|
||||
} catch (CertificateException e) {
|
||||
log.error("Error in certificate factory: " + e.getMessage());
|
||||
log.error("Error in certificate factory: {}", e.getMessage());
|
||||
} catch (IOException e) {
|
||||
log.error("Error reading from input stream: " + e.getMessage());
|
||||
log.error("Error reading from input stream: {}", e.getMessage());
|
||||
} finally {
|
||||
try {
|
||||
if (fis != null) {
|
||||
@ -759,7 +602,7 @@ public class ReferenceManifestValidator {
|
||||
bis.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.warn("Error closing input stream: " + e.getMessage());
|
||||
log.warn("Error closing input stream: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -854,11 +697,135 @@ public class ReferenceManifestValidator {
|
||||
|
||||
/**
|
||||
* This method logs an error message and returns a false to signal failed validation.
|
||||
*
|
||||
* @param errorMessage String description of what went wrong
|
||||
* @return false to represent failed validation
|
||||
*/
|
||||
private boolean failWithError(String errorMessage) {
|
||||
private boolean failWithError(final String errorMessage) {
|
||||
log.error(errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This internal class handles selecting an X509 certificate embedded in a KeyInfo element.
|
||||
* It is passed as a parameter to a DOMValidateContext that uses it to validate
|
||||
* an XML signature.
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class X509KeySelector extends KeySelector {
|
||||
|
||||
private PublicKey publicKey;
|
||||
private X509Certificate signingCert;
|
||||
|
||||
/**
|
||||
* This method selects a public key for validation.
|
||||
* PKs are parsed preferentially from the following elements:
|
||||
* - X509Data
|
||||
* - KeyValue
|
||||
* The parsed PK is then verified based on the provided algorithm before
|
||||
* being returned in a KeySelectorResult.
|
||||
*
|
||||
* @param keyinfo object containing the cert.
|
||||
* @param purpose purpose.
|
||||
* @param algorithm algorithm.
|
||||
* @param context XMLCryptoContext.
|
||||
* @return KeySelectorResult holding the PublicKey.
|
||||
* @throws KeySelectorException exception.
|
||||
*/
|
||||
public KeySelectorResult select(final KeyInfo keyinfo,
|
||||
final KeySelector.Purpose purpose,
|
||||
final AlgorithmMethod algorithm,
|
||||
final XMLCryptoContext context)
|
||||
throws KeySelectorException {
|
||||
Iterator keyinfoItr = keyinfo.getContent().iterator();
|
||||
while (keyinfoItr.hasNext()) {
|
||||
XMLStructure element = (XMLStructure) keyinfoItr.next();
|
||||
if (element instanceof X509Data data) {
|
||||
Iterator dataItr = data.getContent().iterator();
|
||||
while (dataItr.hasNext()) {
|
||||
Object object = dataItr.next();
|
||||
if (object instanceof X509Certificate embeddedCert) {
|
||||
try {
|
||||
if (isCertChainValid(embeddedCert)) {
|
||||
publicKey = embeddedCert.getPublicKey();
|
||||
signingCert = embeddedCert;
|
||||
log.info("Certificate chain valid.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Certificate chain invalid: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (element instanceof KeyValue) {
|
||||
try {
|
||||
PublicKey pk = ((KeyValue) element).getPublicKey();
|
||||
if (isPublicKeyTrusted(pk)) {
|
||||
publicKey = pk;
|
||||
try {
|
||||
if (isCertChainValid(signingCert)) {
|
||||
log.info("Certificate chain valid.");
|
||||
} else {
|
||||
log.error("Certificate chain invalid.");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Certificate chain invalid: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
} catch (KeyException e) {
|
||||
log.error("Unable to convert KeyValue data to PK.");
|
||||
}
|
||||
}
|
||||
if (publicKey != null) {
|
||||
if (areAlgorithmsEqual(algorithm.getAlgorithm(), publicKey.getAlgorithm())) {
|
||||
return new ReferenceManifestValidator.X509KeySelector
|
||||
.RIMKeySelectorResult(publicKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new KeySelectorException("No key found!");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method checks that the signature and public key algorithms match.
|
||||
*
|
||||
* @param uri to match the signature algorithm
|
||||
* @param name to match the public key algorithm
|
||||
* @return true if both match, false otherwise
|
||||
*/
|
||||
public boolean areAlgorithmsEqual(final String uri, final String name) {
|
||||
return uri.equals(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256)
|
||||
&& name.equalsIgnoreCase("RSA");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method compares a public key against those in the truststore.
|
||||
*
|
||||
* @param pk a public key
|
||||
* @return true if pk is found in the trust store, false otherwise
|
||||
*/
|
||||
private boolean isPublicKeyTrusted(final PublicKey pk) {
|
||||
for (X509Certificate trustedCert : trustStore) {
|
||||
if (Arrays.equals(trustedCert.getPublicKey().getEncoded(),
|
||||
pk.getEncoded())) {
|
||||
signingCert = trustedCert;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This internal class creates a KeySelectorResult from the public key.
|
||||
*/
|
||||
@Getter
|
||||
private static class RIMKeySelectorResult implements KeySelectorResult {
|
||||
private final Key key;
|
||||
|
||||
RIMKeySelectorResult(final Key key) {
|
||||
this.key = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
package hirs.utils.rim;
|
@ -8,26 +8,19 @@ import javax.xml.namespace.QName;
|
||||
* class. It is expected that member properties of this class will expand as
|
||||
* more functionality is added to SwidTagGateway.
|
||||
*/
|
||||
public class SwidTagConstants {
|
||||
public final class SwidTagConstants {
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain
|
||||
*/
|
||||
private SwidTagConstants() { }
|
||||
|
||||
public static final String DEFAULT_KEYSTORE_FILE = "keystore.jks";//"/opt/hirs/rimtool/keystore.jks";
|
||||
public static final String DEFAULT_KEYSTORE_FILE = "keystore.jks"; //"/opt/hirs/rimtool/keystore.jks";
|
||||
public static final String DEFAULT_KEYSTORE_PASSWORD = "password";
|
||||
public static final String DEFAULT_PRIVATE_KEY_ALIAS = "1";
|
||||
public static final String DEFAULT_ATTRIBUTES_FILE = "/opt/hirs/rimtool/rim_fields.json";
|
||||
public static final String DEFAULT_ENGLISH = "en";
|
||||
|
||||
public static final String SIGNATURE_ALGORITHM_RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
|
||||
|
||||
public static final String SIGNATURE_ALGORITHM_RSA_SHA256 =
|
||||
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
|
||||
public static final String SCHEMA_PACKAGE = "hirs.swid.xjc";
|
||||
public static final String SCHEMA_LANGUAGE = XMLConstants.W3C_XML_SCHEMA_NS_URI;
|
||||
public static final String SCHEMA_URL = "swid_schema.xsd";
|
||||
public static final String SWIDTAG_NAMESPACE = "http://standards.iso.org/iso/19770/-2/2015/schema.xsd";
|
||||
|
||||
public static final String SOFTWARE_IDENTITY = "SoftwareIdentity";
|
||||
public static final String ENTITY = "Entity";
|
||||
public static final String LINK = "Link";
|
||||
@ -76,48 +69,43 @@ public class SwidTagConstants {
|
||||
public static final String SUPPORT_RIM_FORMAT_MISSING = "supportRIMFormat missing";
|
||||
public static final String SUPPORT_RIM_URI_GLOBAL = "supportRIMURIGlobal";
|
||||
public static final String DATETIME = "dateTime";
|
||||
|
||||
public static final String NIST_NS = "http://csrc.nist.gov/ns/swid/2015-extensions/1.0";
|
||||
public static final String TCG_NS = "https://trustedcomputinggroup.org/wp-content/uploads/TCG_RIM_Model";
|
||||
public static final String RFC3852_NS = "https://www.ietf.org/rfc/rfc3852.txt";
|
||||
public static final String RFC3339_NS = "https://www.ietf.org/rfc/rfc3339.txt";
|
||||
|
||||
public static final String N8060_PFX = "n8060";
|
||||
public static final String RIM_PFX = "rim";
|
||||
public static final String FX_SEPARATOR = ":";
|
||||
public static final String RFC3852_PFX = "rcf3852";
|
||||
public static final String RFC3339_PFX = "rcf3339";
|
||||
|
||||
public static final String _COLLOQUIAL_VERSION_STR = N8060_PFX + FX_SEPARATOR +
|
||||
COLLOQUIAL_VERSION;
|
||||
public static final String _PRODUCT_STR = N8060_PFX + FX_SEPARATOR +
|
||||
PRODUCT;
|
||||
public static final String _REVISION_STR = N8060_PFX + FX_SEPARATOR +
|
||||
REVISION;
|
||||
public static final String _EDITION_STR = N8060_PFX + FX_SEPARATOR +
|
||||
EDITION;
|
||||
public static final String _RIM_LINK_HASH_STR = RIM_PFX + FX_SEPARATOR +
|
||||
RIM_LINK_HASH;
|
||||
public static final String _BINDING_SPEC_STR = RIM_PFX + FX_SEPARATOR +
|
||||
BINDING_SPEC;
|
||||
public static final String _BINDING_SPEC_VERSION_STR = RIM_PFX + FX_SEPARATOR +
|
||||
BINDING_SPEC_VERSION;
|
||||
public static final String _PLATFORM_MANUFACTURER_STR = RIM_PFX + FX_SEPARATOR +
|
||||
PLATFORM_MANUFACTURER_STR;
|
||||
public static final String _PLATFORM_MANUFACTURER_ID_STR = RIM_PFX + FX_SEPARATOR +
|
||||
PLATFORM_MANUFACTURER_ID;
|
||||
public static final String _PLATFORM_MODEL_STR = RIM_PFX + FX_SEPARATOR +
|
||||
PLATFORM_MODEL;
|
||||
public static final String _PLATFORM_VERSION_STR = RIM_PFX + FX_SEPARATOR +
|
||||
PLATFORM_VERSION;
|
||||
public static final String _PAYLOAD_TYPE_STR = RIM_PFX + FX_SEPARATOR +
|
||||
PAYLOAD_TYPE;
|
||||
public static final String _PC_URI_LOCAL_STR = RIM_PFX + FX_SEPARATOR +
|
||||
PC_URI_LOCAL;
|
||||
public static final String _PC_URI_GLOBAL_STR = RIM_PFX + FX_SEPARATOR +
|
||||
PC_URI_GLOBAL;
|
||||
|
||||
|
||||
public static final String _COLLOQUIAL_VERSION_STR = N8060_PFX + FX_SEPARATOR
|
||||
+ COLLOQUIAL_VERSION;
|
||||
public static final String _PRODUCT_STR = N8060_PFX + FX_SEPARATOR
|
||||
+ PRODUCT;
|
||||
public static final String _REVISION_STR = N8060_PFX + FX_SEPARATOR
|
||||
+ REVISION;
|
||||
public static final String _EDITION_STR = N8060_PFX + FX_SEPARATOR
|
||||
+ EDITION;
|
||||
public static final String _RIM_LINK_HASH_STR = RIM_PFX + FX_SEPARATOR
|
||||
+ RIM_LINK_HASH;
|
||||
public static final String _BINDING_SPEC_STR = RIM_PFX + FX_SEPARATOR
|
||||
+ BINDING_SPEC;
|
||||
public static final String _BINDING_SPEC_VERSION_STR = RIM_PFX + FX_SEPARATOR
|
||||
+ BINDING_SPEC_VERSION;
|
||||
public static final String _PLATFORM_MANUFACTURER_STR = RIM_PFX + FX_SEPARATOR
|
||||
+ PLATFORM_MANUFACTURER_STR;
|
||||
public static final String _PLATFORM_MANUFACTURER_ID_STR = RIM_PFX + FX_SEPARATOR
|
||||
+ PLATFORM_MANUFACTURER_ID;
|
||||
public static final String _PLATFORM_MODEL_STR = RIM_PFX + FX_SEPARATOR
|
||||
+ PLATFORM_MODEL;
|
||||
public static final String _PLATFORM_VERSION_STR = RIM_PFX + FX_SEPARATOR
|
||||
+ PLATFORM_VERSION;
|
||||
public static final String _PAYLOAD_TYPE_STR = RIM_PFX + FX_SEPARATOR
|
||||
+ PAYLOAD_TYPE;
|
||||
public static final String _PC_URI_LOCAL_STR = RIM_PFX + FX_SEPARATOR
|
||||
+ PC_URI_LOCAL;
|
||||
public static final String _PC_URI_GLOBAL_STR = RIM_PFX + FX_SEPARATOR
|
||||
+ PC_URI_GLOBAL;
|
||||
public static final QName _SHA256_HASH = new QName(
|
||||
"http://www.w3.org/2001/04/xmlenc#sha256", HASH, "SHA256");
|
||||
public static final QName _COLLOQUIAL_VERSION = new QName(
|
||||
@ -168,6 +156,11 @@ public class SwidTagConstants {
|
||||
NIST_NS, "envVarSuffix", N8060_PFX);
|
||||
public static final QName _N8060_PATHSEPARATOR = new QName(
|
||||
NIST_NS, "pathSeparator", N8060_PFX);
|
||||
|
||||
public static final String CA_ISSUERS = "1.3.6.1.5.5.7.48.2";
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain.
|
||||
*/
|
||||
private SwidTagConstants() {
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
package hirs.utils.swid;
|
@ -13,7 +13,7 @@ import java.io.IOException;
|
||||
* Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER.
|
||||
* DEVICE_SECURITY_EVENT_DATA_HEADER contains the measurement(s) and hash algorithm identifier
|
||||
* returned by the SPDM "GET_MEASUREMENTS" function.
|
||||
*
|
||||
* <p>
|
||||
* HEADERS defined by PFP v1.06 Rev 52:
|
||||
* <p>
|
||||
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER {
|
||||
@ -62,8 +62,9 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
|
||||
|
||||
super(dsedBytes);
|
||||
|
||||
final int dsedBytesSrcIndex1 = 18;
|
||||
byte[] lengthBytes = new byte[UefiConstants.SIZE_2];
|
||||
System.arraycopy(dsedBytes, 18, lengthBytes, 0,
|
||||
System.arraycopy(dsedBytes, dsedBytesSrcIndex1, lengthBytes, 0,
|
||||
UefiConstants.SIZE_2);
|
||||
length = HexUtils.leReverseInt(lengthBytes);
|
||||
|
||||
@ -72,18 +73,22 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
|
||||
UefiConstants.SIZE_4);
|
||||
spdmHashAlgo = HexUtils.leReverseInt(spdmHashAlgoBytes);
|
||||
|
||||
extractDeviceType(dsedBytes, 24);
|
||||
final int dsedBytesStartByte = 24;
|
||||
extractDeviceType(dsedBytes, dsedBytesStartByte);
|
||||
|
||||
// get the size of the SPDM Measurement Block
|
||||
final int dsedBytesSrcIndex2 = 30;
|
||||
byte[] sizeOfSpdmMeasBlockBytes = new byte[UefiConstants.SIZE_2];
|
||||
System.arraycopy(dsedBytes, 30, sizeOfSpdmMeasBlockBytes, 0,
|
||||
System.arraycopy(dsedBytes, dsedBytesSrcIndex2, sizeOfSpdmMeasBlockBytes, 0,
|
||||
UefiConstants.SIZE_2);
|
||||
int sizeOfSpdmMeas = HexUtils.leReverseInt(sizeOfSpdmMeasBlockBytes);
|
||||
int sizeOfSpdmMeasBlock = sizeOfSpdmMeas + 4; // header is 4 bytes
|
||||
final int sizeOfSpdmMeas = HexUtils.leReverseInt(sizeOfSpdmMeasBlockBytes);
|
||||
final int offSetBytesForSpdm = 4;
|
||||
final int sizeOfSpdmMeasBlock = sizeOfSpdmMeas + offSetBytesForSpdm; // header is 4 bytes
|
||||
|
||||
// extract the bytes that comprise the SPDM Measurement Block
|
||||
final int dsedBytesSrcIndex3 = 28;
|
||||
byte[] spdmMeasBlockBytes = new byte[sizeOfSpdmMeasBlock];
|
||||
System.arraycopy(dsedBytes, 28, spdmMeasBlockBytes, 0,
|
||||
System.arraycopy(dsedBytes, dsedBytesSrcIndex3, spdmMeasBlockBytes, 0,
|
||||
sizeOfSpdmMeasBlock);
|
||||
|
||||
ByteArrayInputStream spdmMeasurementBlockData =
|
||||
@ -96,7 +101,8 @@ public class DeviceSecurityEventDataHeader extends DeviceSecurityEventHeader {
|
||||
spdmMeasurementBlockInfo = " Error reading SPDM Measurement Block";
|
||||
}
|
||||
|
||||
int devPathLenStartByte = 28 + sizeOfSpdmMeasBlock;
|
||||
final int offSetBytesForDevPath = 28;
|
||||
final int devPathLenStartByte = offSetBytesForDevPath + sizeOfSpdmMeasBlock;
|
||||
extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte);
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import lombok.Getter;
|
||||
* Class to process the DEVICE_SECURITY_EVENT_DATA_HEADER2.
|
||||
* DEVICE_SECURITY_EVENT_DATA_HEADER2 contains the measurement(s) and hash algorithm identifier
|
||||
* returned by the SPDM "GET_MEASUREMENTS" function.
|
||||
*
|
||||
* <p>
|
||||
* HEADERS defined by PFP v1.06 Rev 52:
|
||||
* <p>
|
||||
* typedef struct tdDEVICE_SECURITY_EVENT_DATA_HEADER2 {
|
||||
@ -27,6 +27,32 @@ import lombok.Getter;
|
||||
*/
|
||||
public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
|
||||
|
||||
/**
|
||||
* Auth state - success.
|
||||
*/
|
||||
public static final int AUTH_SUCCESS = 0;
|
||||
/**
|
||||
* Auth state - digital signature of the data is valid, but the public key certificate chain is not
|
||||
* validated with the entry in the UEFI device signature variable.
|
||||
*/
|
||||
public static final int AUTH_NO_AUTHORITY = 1;
|
||||
/**
|
||||
* Auth state - digital signature of the measurement data is valid, but the reported device capabilities,
|
||||
* negotiated parameters or certificate chains were not validated by a transcript.
|
||||
*/
|
||||
public static final int AUTH_NO_BINDING = 2;
|
||||
/**
|
||||
* Auth state - data has no digital signature.
|
||||
*/
|
||||
public static final int AUTH_FAIL_NO_SIG = 3;
|
||||
/**
|
||||
* Auth state - data is invalid.
|
||||
*/
|
||||
public static final int AUTH_FAIL_INVALID = 4;
|
||||
/**
|
||||
* Auth state - device is not an SPDM-capable device.
|
||||
*/
|
||||
public static final int AUTH_NO_SPDM = 0xFF;
|
||||
/**
|
||||
* Event auth state.
|
||||
*/
|
||||
@ -55,33 +81,6 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
|
||||
@Getter
|
||||
private String subHeaderUid = "";
|
||||
|
||||
/**
|
||||
* Auth state - success.
|
||||
*/
|
||||
public static final int AUTH_SUCCESS = 0;
|
||||
/**
|
||||
* Auth state - digital signature of the data is valid, but the public key certificate chain is not
|
||||
* validated with the entry in the UEFI device signature variable.
|
||||
*/
|
||||
public static final int AUTH_NO_AUTHORITY = 1;
|
||||
/**
|
||||
* Auth state - digital signature of the measurement data is valid, but the reported device capabilities,
|
||||
* negotiated parameters or certificate chains were not validated by a transcript.
|
||||
*/
|
||||
public static final int AUTH_NO_BINDING = 2;
|
||||
/**
|
||||
* Auth state - data has no digital signature.
|
||||
*/
|
||||
public static final int AUTH_FAIL_NO_SIG = 3;
|
||||
/**
|
||||
* Auth state - data is invalid.
|
||||
*/
|
||||
public static final int AUTH_FAIL_INVALID = 4;
|
||||
/**
|
||||
* Auth state - device is not an SPDM-capable device.
|
||||
*/
|
||||
public static final int AUTH_NO_SPDM = 0xFF;
|
||||
|
||||
/**
|
||||
* DeviceSecurityEventDataHeader2 Constructor.
|
||||
*
|
||||
@ -91,33 +90,43 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
|
||||
|
||||
super(dsedBytes);
|
||||
|
||||
final int dsedBytesSrcIndex = 18;
|
||||
byte[] authStateBytes = new byte[1];
|
||||
System.arraycopy(dsedBytes, 18, authStateBytes, 0, 1);
|
||||
System.arraycopy(dsedBytes, dsedBytesSrcIndex, authStateBytes, 0, 1);
|
||||
authState = HexUtils.leReverseInt(authStateBytes);
|
||||
|
||||
// byte[] reserved[Bytes]: 1 byte
|
||||
|
||||
byte[] lengthBytes = new byte[4];
|
||||
System.arraycopy(dsedBytes, 20, lengthBytes, 0, 4);
|
||||
final int dsedBytesSrcIndex2 = 20;
|
||||
final int lengthBytesSize = 4;
|
||||
byte[] lengthBytes = new byte[lengthBytesSize];
|
||||
System.arraycopy(dsedBytes, dsedBytesSrcIndex2, lengthBytes, 0, lengthBytesSize);
|
||||
length = HexUtils.leReverseInt(lengthBytes);
|
||||
|
||||
extractDeviceType(dsedBytes, 24);
|
||||
final int dsedBytesStartByte1 = 24;
|
||||
extractDeviceType(dsedBytes, dsedBytesStartByte1);
|
||||
|
||||
byte[] subHeaderTypeBytes = new byte[4];
|
||||
System.arraycopy(dsedBytes, 28, subHeaderTypeBytes, 0, 4);
|
||||
final int dsedBytesSrcIndex3 = 28;
|
||||
final int subHeaderTypeBytesSize = 4;
|
||||
byte[] subHeaderTypeBytes = new byte[subHeaderTypeBytesSize];
|
||||
System.arraycopy(dsedBytes, dsedBytesSrcIndex3, subHeaderTypeBytes, 0, subHeaderTypeBytesSize);
|
||||
subHeaderType = HexUtils.leReverseInt(subHeaderTypeBytes);
|
||||
|
||||
byte[] subHeaderLengthBytes = new byte[4];
|
||||
System.arraycopy(dsedBytes, 32, subHeaderLengthBytes, 0, 4);
|
||||
final int dsedBytesSrcIndex4 = 32;
|
||||
final int subHeaderLengthBytesSize = 4;
|
||||
byte[] subHeaderLengthBytes = new byte[subHeaderLengthBytesSize];
|
||||
System.arraycopy(dsedBytes, dsedBytesSrcIndex4, subHeaderLengthBytes, 0, subHeaderLengthBytesSize);
|
||||
subHeaderLength = HexUtils.leReverseInt(subHeaderLengthBytes);
|
||||
|
||||
byte[] subHeaderUidBytes = new byte[8];
|
||||
System.arraycopy(dsedBytes, 36, subHeaderUidBytes, 0, 8);
|
||||
final int dsedBytesSrcIndex5 = 36;
|
||||
final int subHeaderUidBytesSize = 8;
|
||||
byte[] subHeaderUidBytes = new byte[subHeaderUidBytesSize];
|
||||
System.arraycopy(dsedBytes, dsedBytesSrcIndex5, subHeaderUidBytes, 0, subHeaderUidBytesSize);
|
||||
subHeaderUidBytes = HexUtils.leReverseByte(subHeaderUidBytes);
|
||||
subHeaderUid = HexUtils.byteArrayToHexString(subHeaderUidBytes);
|
||||
|
||||
int devPathLenStartByte = 44;
|
||||
extractDevicePathAndFinalSize(dsedBytes, devPathLenStartByte);
|
||||
final int dsedBytesStartByte2 = 44;
|
||||
extractDevicePathAndFinalSize(dsedBytes, dsedBytesStartByte2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -139,22 +148,14 @@ public class DeviceSecurityEventDataHeader2 extends DeviceSecurityEventHeader {
|
||||
* @return a description of the auth state.
|
||||
*/
|
||||
public String getAuthStateString() {
|
||||
|
||||
switch (authState) {
|
||||
case AUTH_SUCCESS:
|
||||
return ("AUTH_SUCCESS");
|
||||
case AUTH_NO_AUTHORITY:
|
||||
return ("AUTH_NO_AUTHORITY");
|
||||
case AUTH_NO_BINDING:
|
||||
return ("AUTH_NO_BINDING");
|
||||
case AUTH_FAIL_NO_SIG:
|
||||
return ("AUTH_FAIL_NO_SIG");
|
||||
case AUTH_FAIL_INVALID:
|
||||
return ("AUTH_FAIL_INVALID");
|
||||
case AUTH_NO_SPDM:
|
||||
return ("AUTH_NO_SPDM");
|
||||
default:
|
||||
return ("Auth State unknown");
|
||||
}
|
||||
return switch (authState) {
|
||||
case AUTH_SUCCESS -> ("AUTH_SUCCESS");
|
||||
case AUTH_NO_AUTHORITY -> ("AUTH_NO_AUTHORITY");
|
||||
case AUTH_NO_BINDING -> ("AUTH_NO_BINDING");
|
||||
case AUTH_FAIL_NO_SIG -> ("AUTH_FAIL_NO_SIG");
|
||||
case AUTH_FAIL_INVALID -> ("AUTH_FAIL_INVALID");
|
||||
case AUTH_NO_SPDM -> ("AUTH_NO_SPDM");
|
||||
default -> ("Auth State unknown");
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -78,28 +78,36 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
|
||||
|
||||
super(dSEDpciContextBytes);
|
||||
|
||||
final int dSEDpciContextBytesSrcIndex1 = 4;
|
||||
byte[] pciVendorIdBytes = new byte[2];
|
||||
System.arraycopy(dSEDpciContextBytes, 4, pciVendorIdBytes, 0, 2);
|
||||
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex1, pciVendorIdBytes, 0, 2);
|
||||
vendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciVendorIdBytes));
|
||||
|
||||
final int dSEDpciContextBytesSrcIndex2 = 6;
|
||||
byte[] pciDeviceIdBytes = new byte[2];
|
||||
System.arraycopy(dSEDpciContextBytes, 6, pciDeviceIdBytes, 0, 2);
|
||||
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex2, pciDeviceIdBytes, 0, 2);
|
||||
deviceId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciDeviceIdBytes));
|
||||
|
||||
final int dSEDpciContextBytesSrcIndex3 = 8;
|
||||
byte[] pciRevisionIdBytes = new byte[1];
|
||||
System.arraycopy(dSEDpciContextBytes, 8, pciRevisionIdBytes, 0, 1);
|
||||
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex3, pciRevisionIdBytes, 0, 1);
|
||||
revisionId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciRevisionIdBytes));
|
||||
|
||||
byte[] pciClassCodeBytes = new byte[3];
|
||||
System.arraycopy(dSEDpciContextBytes, 9, pciClassCodeBytes, 0, 3);
|
||||
final int dSEDpciContextBytesSrcIndex4 = 9;
|
||||
final int pciClassCodeBytesSize = 3;
|
||||
byte[] pciClassCodeBytes = new byte[pciClassCodeBytesSize];
|
||||
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex4, pciClassCodeBytes, 0,
|
||||
pciClassCodeBytesSize);
|
||||
classCode = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciClassCodeBytes));
|
||||
|
||||
final int dSEDpciContextBytesSrcIndex5 = 12;
|
||||
byte[] pciSubsystemVendorIdBytes = new byte[2];
|
||||
System.arraycopy(dSEDpciContextBytes, 12, pciSubsystemVendorIdBytes, 0, 2);
|
||||
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex5, pciSubsystemVendorIdBytes, 0, 2);
|
||||
subsystemVendorId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemVendorIdBytes));
|
||||
|
||||
final int dSEDpciContextBytesSrcIndex6 = 14;
|
||||
byte[] pciSubsystemIdBytes = new byte[2];
|
||||
System.arraycopy(dSEDpciContextBytes, 14, pciSubsystemIdBytes, 0, 2);
|
||||
System.arraycopy(dSEDpciContextBytes, dSEDpciContextBytesSrcIndex6, pciSubsystemIdBytes, 0, 2);
|
||||
subsystemId = HexUtils.byteArrayToHexString(HexUtils.leReverseByte(pciSubsystemIdBytes));
|
||||
}
|
||||
|
||||
@ -118,8 +126,9 @@ public class DeviceSecurityEventDataPciContext extends DeviceSecurityEventDataDe
|
||||
dSEDpciContextInfo += " RevisionID = " + revisionId + "\n";
|
||||
|
||||
List<String> classCodeList = translateDeviceClass(classCode);
|
||||
final int validClassCodeListSize = 3;
|
||||
dSEDpciContextInfo += " Device Class: \n";
|
||||
if (classCodeList.size() == 3) {
|
||||
if (classCodeList.size() == validClassCodeListSize) {
|
||||
dSEDpciContextInfo += " Class = " + classCodeList.get(0) + "\n";
|
||||
dSEDpciContextInfo += " Subclass = " + classCodeList.get(1) + "\n";
|
||||
dSEDpciContextInfo += " Programming Interface = " + classCodeList.get(2) + "\n";
|
||||
|
@ -61,16 +61,21 @@ public class DeviceSecurityEventDataSubHeaderCertChain extends DeviceSecurityEve
|
||||
|
||||
// byte[] reserved[Bytes]: 1 byte
|
||||
|
||||
byte[] spdmBaseHashAlgoBytes = new byte[4];
|
||||
System.arraycopy(dsedSubHBytes, 4, spdmBaseHashAlgoBytes, 0, 4);
|
||||
final int dsedSybHBytesSrcIndex1 = 4;
|
||||
final int spdmBaseHashAlgoBytesSize = 4;
|
||||
byte[] spdmBaseHashAlgoBytes = new byte[spdmBaseHashAlgoBytesSize];
|
||||
System.arraycopy(dsedSubHBytes, dsedSybHBytesSrcIndex1, spdmBaseHashAlgoBytes, 0,
|
||||
spdmBaseHashAlgoBytesSize);
|
||||
spdmBaseHashAlgo = HexUtils.leReverseInt(spdmBaseHashAlgoBytes);
|
||||
|
||||
// get the size of the SPDM Cert Chain
|
||||
int spdmCertChainSize = dsedSubHBytes.length - 8;
|
||||
final int offsetForSpdmCertChain = 8;
|
||||
int spdmCertChainSize = dsedSubHBytes.length - offsetForSpdmCertChain;
|
||||
|
||||
// extract the bytes that comprise the SPDM Cert Chain
|
||||
final int dsedSybHBytesSrcIndex2 = 8;
|
||||
byte[] spdmCertChainBytes = new byte[spdmCertChainSize];
|
||||
System.arraycopy(dsedSubHBytes, 8, spdmCertChainBytes, 0,
|
||||
System.arraycopy(dsedSubHBytes, dsedSybHBytesSrcIndex2, spdmCertChainBytes, 0,
|
||||
spdmCertChainSize);
|
||||
|
||||
int spdmBaseHashAlgoSize = SpdmHa.tcgAlgIdToByteSize(spdmBaseHashAlgo);
|
||||
|
@ -22,7 +22,7 @@ import java.util.List;
|
||||
* SPDM_MEASUREMENT_BLOCK SpdmMeasurementBlock[SpdmMeasurementBlockCount];
|
||||
* } DEVICE_SECURITY_EVENT_DATA_SUB_HEADER_SPDM_MEASUREMENT_BLOCK;
|
||||
* <p>
|
||||
*
|
||||
* <p>
|
||||
* SpdmMeasurementBlock is an array of SPDM_MEASUREMENT_BLOCKs
|
||||
* The size of each block is the same and can be found by either:
|
||||
* 1) 4 + SpdmMeasurementBlock MeasurementSize
|
||||
@ -33,6 +33,10 @@ import java.util.List;
|
||||
*/
|
||||
public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends DeviceSecurityEventDataSubHeader {
|
||||
|
||||
/**
|
||||
* List of SPDM Measurement Blocks.
|
||||
*/
|
||||
private final List<SpdmMeasurementBlock> spdmMeasurementBlockList;
|
||||
/**
|
||||
* SPDM version.
|
||||
*/
|
||||
@ -48,11 +52,6 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
|
||||
*/
|
||||
@Getter
|
||||
private int spdmMeasurementHashAlgo = -1;
|
||||
|
||||
/**
|
||||
* List of SPDM Measurement Blocks.
|
||||
*/
|
||||
private List<SpdmMeasurementBlock> spdmMeasurementBlockList;
|
||||
/**
|
||||
* Error reading SPDM Measurement Block.
|
||||
*/
|
||||
@ -77,16 +76,21 @@ public class DeviceSecurityEventDataSubHeaderSpdmMeasurementBlock extends Device
|
||||
|
||||
// byte[] reserved[Bytes]: 1 byte
|
||||
|
||||
byte[] spdmMeasurementHashAlgoBytes = new byte[4];
|
||||
System.arraycopy(dsedSubHBytes, 4, spdmMeasurementHashAlgoBytes, 0, 4);
|
||||
final int spdmMeasurementHashAlgoBytesSize = 4;
|
||||
final int dsedSubHBytesSrcIndex1 = 4;
|
||||
byte[] spdmMeasurementHashAlgoBytes = new byte[spdmMeasurementHashAlgoBytesSize];
|
||||
System.arraycopy(dsedSubHBytes, dsedSubHBytesSrcIndex1, spdmMeasurementHashAlgoBytes, 0,
|
||||
spdmMeasurementHashAlgoBytesSize);
|
||||
spdmMeasurementHashAlgo = HexUtils.leReverseInt(spdmMeasurementHashAlgoBytes);
|
||||
|
||||
// get the total size of the SPDM Measurement Block List
|
||||
int spdmMeasurementBlockListSize = dsedSubHBytes.length - 8;
|
||||
final int offsetForspdmMeasurementBlockList = 8;
|
||||
final int spdmMeasurementBlockListSize = dsedSubHBytes.length - offsetForspdmMeasurementBlockList;
|
||||
|
||||
// extract the bytes that comprise the SPDM Measurement Block List
|
||||
final int dsedSubHBytesSrcIndex2 = 8;
|
||||
byte[] spdmMeasurementBlockListBytes = new byte[spdmMeasurementBlockListSize];
|
||||
System.arraycopy(dsedSubHBytes, 8, spdmMeasurementBlockListBytes, 0,
|
||||
System.arraycopy(dsedSubHBytes, dsedSubHBytesSrcIndex2, spdmMeasurementBlockListBytes, 0,
|
||||
spdmMeasurementBlockListSize);
|
||||
|
||||
ByteArrayInputStream spdmMeasurementBlockListData =
|
||||
|
@ -12,7 +12,7 @@ import java.nio.charset.StandardCharsets;
|
||||
* The first 16 bytes of the event data header MUST be a String based identifier (Signature),
|
||||
* NUL-terminated, per PFP. The only currently defined Signature is "SPDM Device Sec",
|
||||
* which implies the data is a DEVICE_SECURITY_EVENT_DATA or ..DATA2.
|
||||
*
|
||||
* <p>
|
||||
* HEADERS defined by PFP v1.06 Rev 52.
|
||||
* Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures.
|
||||
* <p>
|
||||
@ -51,12 +51,16 @@ import java.nio.charset.StandardCharsets;
|
||||
*/
|
||||
public abstract class DeviceSecurityEventHeader {
|
||||
|
||||
/**
|
||||
* UEFI Device Path Length.
|
||||
*/
|
||||
@Getter
|
||||
private static final int DEVICE_PATH_LENGTH = 0;
|
||||
/**
|
||||
* Contains the size (in bytes) of the header.
|
||||
*/
|
||||
@Getter
|
||||
private Integer dsedHeaderLength = 0;
|
||||
|
||||
/**
|
||||
* Signature (text) data.
|
||||
*/
|
||||
@ -73,11 +77,6 @@ public abstract class DeviceSecurityEventHeader {
|
||||
*/
|
||||
@Getter
|
||||
private int deviceType = -1;
|
||||
/**
|
||||
* UEFI Device Path Length.
|
||||
*/
|
||||
@Getter
|
||||
private int devicePathLength = 0;
|
||||
/**
|
||||
* UEFI Device path.
|
||||
*/
|
||||
@ -129,21 +128,23 @@ public abstract class DeviceSecurityEventHeader {
|
||||
int startByteUpdated = startByte;
|
||||
|
||||
// get the device path length
|
||||
byte[] devicePathLengthBytes = new byte[8];
|
||||
System.arraycopy(dsedBytes, startByteUpdated, devicePathLengthBytes, 0, 8);
|
||||
int devicePathLength = HexUtils.leReverseInt(devicePathLengthBytes);
|
||||
final int devicePathLengthBytesSize = 8;
|
||||
byte[] devicePathLengthBytes = new byte[devicePathLengthBytesSize];
|
||||
System.arraycopy(dsedBytes, startByteUpdated, devicePathLengthBytes, 0, devicePathLengthBytesSize);
|
||||
int retrievedDevicePathLength = HexUtils.leReverseInt(devicePathLengthBytes);
|
||||
|
||||
// get the device path
|
||||
if (devicePathLength > 0) {
|
||||
startByteUpdated = startByteUpdated + 8;
|
||||
byte[] devPathBytes = new byte[devicePathLength];
|
||||
if (retrievedDevicePathLength > 0) {
|
||||
final int startByteUpdatedOffset = 8;
|
||||
startByteUpdated = startByteUpdated + startByteUpdatedOffset;
|
||||
byte[] devPathBytes = new byte[retrievedDevicePathLength];
|
||||
System.arraycopy(dsedBytes, startByteUpdated, devPathBytes,
|
||||
0, devicePathLength);
|
||||
0, retrievedDevicePathLength);
|
||||
devicePath = new UefiDevicePath(devPathBytes);
|
||||
}
|
||||
|
||||
// header total size
|
||||
dsedHeaderLength = startByteUpdated + devicePathLength;
|
||||
dsedHeaderLength = startByteUpdated + retrievedDevicePathLength;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -154,16 +155,12 @@ public abstract class DeviceSecurityEventHeader {
|
||||
* @return name of the device type
|
||||
*/
|
||||
public String deviceTypeToString(final int deviceTypeInt) {
|
||||
switch (deviceTypeInt) {
|
||||
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_NONE:
|
||||
return "No device type";
|
||||
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_PCI:
|
||||
return "PCI";
|
||||
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_USB:
|
||||
return "USB";
|
||||
default:
|
||||
return "Unknown or invalid Device Type";
|
||||
}
|
||||
return switch (deviceTypeInt) {
|
||||
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_NONE -> "No device type";
|
||||
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_PCI -> "PCI";
|
||||
case DeviceSecurityEventDataDeviceContext.DEVICE_TYPE_USB -> "USB";
|
||||
default -> "Unknown or invalid Device Type";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -6,11 +6,6 @@ package hirs.utils.tpm.eventlog.events;
|
||||
*/
|
||||
public final class EvConstants {
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain
|
||||
*/
|
||||
private EvConstants() { }
|
||||
|
||||
/**
|
||||
* Type length = 4 bytes.
|
||||
*/
|
||||
@ -39,11 +34,11 @@ public final class EvConstants {
|
||||
* Each PCR bank holds 24 registers.
|
||||
*/
|
||||
public static final int PCR_COUNT = 24;
|
||||
// Event IDs
|
||||
/**
|
||||
* Pre boot cert Event ID.
|
||||
*/
|
||||
public static final int EV_PREBOOT_CERT = 0x00000000;
|
||||
// Event IDs
|
||||
/**
|
||||
* POST Code Event ID.
|
||||
*/
|
||||
@ -180,4 +175,9 @@ public final class EvConstants {
|
||||
* EFI SPDM Device Authority Event ID.
|
||||
*/
|
||||
public static final int EV_EFI_SPDM_DEVICE_AUTHORITY = 0x800000E4;
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain.
|
||||
*/
|
||||
private EvConstants() {
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ public class EvNoAction {
|
||||
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
|
||||
if (signature.contains("Spec ID Event03")) { // implies CryptAgileFormat
|
||||
EvEfiSpecIdEvent specIDEvent = new EvEfiSpecIdEvent(eventData);
|
||||
noActionInfo += specIDEventToString(specIDEvent).toString();
|
||||
noActionInfo += specIDEventToString(specIDEvent);
|
||||
bSpecIDEvent = true;
|
||||
specVersion = String.format("%s.%s",
|
||||
specIDEvent.getVersionMajor(),
|
||||
@ -126,25 +126,21 @@ public class EvNoAction {
|
||||
* @return a description of the locality.
|
||||
*/
|
||||
private String getLocality(final byte[] eventData) {
|
||||
String localityInfo = "";
|
||||
final int eventDataSrcIndex = 16;
|
||||
byte[] localityBytes = new byte[1];
|
||||
System.arraycopy(eventData, 16, localityBytes, 0, 1);
|
||||
int locality = HexUtils.leReverseInt(localityBytes);
|
||||
System.arraycopy(eventData, eventDataSrcIndex, localityBytes, 0, 1);
|
||||
final int locality = HexUtils.leReverseInt(localityBytes);
|
||||
|
||||
switch (locality) {
|
||||
case 0:
|
||||
localityInfo += "Locality 0 without an H-CRTM sequence";
|
||||
break;
|
||||
case 3:
|
||||
localityInfo += "Locality 3 without an H-CRTM sequence";
|
||||
break;
|
||||
case 4:
|
||||
localityInfo += "Locality 4 with an H-CRTM sequence initialized";
|
||||
break;
|
||||
default:
|
||||
localityInfo += "Unknown";
|
||||
}
|
||||
return localityInfo;
|
||||
final int locality0 = 0;
|
||||
final int locality3 = 3;
|
||||
final int locality4 = 4;
|
||||
|
||||
return switch (locality) {
|
||||
case locality0 -> "Locality 0 without an H-CRTM sequence";
|
||||
case locality3 -> "Locality 3 without an H-CRTM sequence";
|
||||
case locality4 -> "Locality 4 with an H-CRTM sequence initialized";
|
||||
default -> "Unknown";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets;
|
||||
* Class to process the NV_INDEX_DYNAMIC_EVENT_LOG_DATA per PFP.
|
||||
* Per PFP, the first 16 bytes of the structure are a String based identifier (Signature),
|
||||
* which are a NULL-terminated ASCII string "NvIndexDynamic".
|
||||
*
|
||||
* <p>
|
||||
* HEADERS defined by PFP v1.06 Rev 52.
|
||||
* Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures.
|
||||
* <p>
|
||||
@ -43,13 +43,16 @@ public class NvIndexDynamicEventLogData {
|
||||
*/
|
||||
public NvIndexDynamicEventLogData(final byte[] eventData) {
|
||||
|
||||
byte[] signatureBytes = new byte[16];
|
||||
System.arraycopy(eventData, 0, signatureBytes, 0, 16);
|
||||
final int signatureBytesSize = 16;
|
||||
byte[] signatureBytes = new byte[signatureBytesSize];
|
||||
System.arraycopy(eventData, 0, signatureBytes, 0, signatureBytesSize);
|
||||
signature = new String(signatureBytes, StandardCharsets.UTF_8);
|
||||
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
|
||||
|
||||
byte[] versionBytes = new byte[2];
|
||||
System.arraycopy(eventData, 16, versionBytes, 0, 2);
|
||||
final int versionBytesSize = 2;
|
||||
final int eventDataSrcIndex1 = 16;
|
||||
byte[] versionBytes = new byte[versionBytesSize];
|
||||
System.arraycopy(eventData, eventDataSrcIndex1, versionBytes, 0, versionBytesSize);
|
||||
String nvIndexVersion = HexUtils.byteArrayToHexString(versionBytes);
|
||||
if (nvIndexVersion.isEmpty()) {
|
||||
nvIndexVersion = "version not readable";
|
||||
@ -58,23 +61,28 @@ public class NvIndexDynamicEventLogData {
|
||||
nvIndexDynamicInfo += " Nv Index Dynamic Version = " + nvIndexVersion + "\n";
|
||||
|
||||
// 6 bytes of Reserved data
|
||||
|
||||
byte[] uidBytes = new byte[8];
|
||||
System.arraycopy(eventData, 24, uidBytes, 0, 8);
|
||||
final int uidBytesSize = 8;
|
||||
final int eventDataSrcIndex2 = 24;
|
||||
byte[] uidBytes = new byte[uidBytesSize];
|
||||
System.arraycopy(eventData, eventDataSrcIndex2, uidBytes, 0, uidBytesSize);
|
||||
String uid = HexUtils.byteArrayToHexString(uidBytes);
|
||||
nvIndexDynamicInfo += " UID = " + uid + "\n";
|
||||
|
||||
byte[] descriptionSizeBytes = new byte[2];
|
||||
System.arraycopy(eventData, 32, descriptionSizeBytes, 0, 2);
|
||||
final int descriptionSizeBytesLength = 2;
|
||||
final int eventDataSrcIndex3 = 32;
|
||||
byte[] descriptionSizeBytes = new byte[descriptionSizeBytesLength];
|
||||
System.arraycopy(eventData, eventDataSrcIndex3, descriptionSizeBytes, 0, descriptionSizeBytesLength);
|
||||
int descriptionSize = HexUtils.leReverseInt(descriptionSizeBytes);
|
||||
|
||||
final int eventDataSrcIndex4 = 34;
|
||||
byte[] descriptionBytes = new byte[descriptionSize];
|
||||
System.arraycopy(eventData, 34, descriptionBytes, 0, descriptionSize);
|
||||
System.arraycopy(eventData, eventDataSrcIndex4, descriptionBytes, 0, descriptionSize);
|
||||
String description = new String(descriptionBytes, StandardCharsets.UTF_8);
|
||||
description = description.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
|
||||
nvIndexDynamicInfo += " Description = " + description + "\n";
|
||||
|
||||
int dataSizeStartByte = 34 + descriptionSize;
|
||||
final int dataSizeOffset = 34;
|
||||
int dataSizeStartByte = dataSizeOffset + descriptionSize;
|
||||
byte[] dataSizeBytes = new byte[2];
|
||||
System.arraycopy(eventData, dataSizeStartByte, dataSizeBytes, 0, 2);
|
||||
int dataSize = HexUtils.leReverseInt(dataSizeBytes);
|
||||
|
@ -8,7 +8,7 @@ import java.nio.charset.StandardCharsets;
|
||||
* Class to process the NV_INDEX_INSTANCE_EVENT_LOG_DATA per PFP.
|
||||
* Per PFP, the first 16 bytes of the structure are a String based identifier (Signature),
|
||||
* which are a NULL-terminated ASCII string "NvIndexInstance".
|
||||
*
|
||||
* <p>
|
||||
* HEADERS defined by PFP v1.06 Rev 52.
|
||||
* Certain fields are common to both ..HEADER and ..HEADER2, and are noted below the structures.
|
||||
* <p>
|
||||
@ -45,13 +45,15 @@ public class NvIndexInstanceEventLogData {
|
||||
*/
|
||||
public NvIndexInstanceEventLogData(final byte[] eventData) {
|
||||
|
||||
byte[] signatureBytes = new byte[16];
|
||||
System.arraycopy(eventData, 0, signatureBytes, 0, 16);
|
||||
final int signatureBytesSize = 16;
|
||||
byte[] signatureBytes = new byte[signatureBytesSize];
|
||||
System.arraycopy(eventData, 0, signatureBytes, 0, signatureBytesSize);
|
||||
signature = new String(signatureBytes, StandardCharsets.UTF_8);
|
||||
signature = signature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
|
||||
|
||||
final int eventDataSrcIndex1 = 16;
|
||||
byte[] versionBytes = new byte[2];
|
||||
System.arraycopy(eventData, 16, versionBytes, 0, 2);
|
||||
System.arraycopy(eventData, eventDataSrcIndex1, versionBytes, 0, 2);
|
||||
String nvIndexVersion = HexUtils.byteArrayToHexString(versionBytes);
|
||||
if (nvIndexVersion == "") {
|
||||
nvIndexVersion = "version not readable";
|
||||
@ -60,14 +62,16 @@ public class NvIndexInstanceEventLogData {
|
||||
nvIndexInstanceInfo += " Nv Index Instance Version = " + nvIndexVersion + "\n";
|
||||
|
||||
// 6 bytes of Reserved data
|
||||
|
||||
byte[] dsedSignatureBytes = new byte[16];
|
||||
System.arraycopy(eventData, 24, dsedSignatureBytes, 0, 16);
|
||||
final int eventDataSrcIndex2 = 24;
|
||||
final int dsedSignatureBytesSize = 16;
|
||||
byte[] dsedSignatureBytes = new byte[dsedSignatureBytesSize];
|
||||
System.arraycopy(eventData, eventDataSrcIndex2, dsedSignatureBytes, 0, dsedSignatureBytesSize);
|
||||
String dsedSignature = new String(dsedSignatureBytes, StandardCharsets.UTF_8);
|
||||
dsedSignature = dsedSignature.replaceAll("[^\\P{C}\t\r\n]", ""); // remove null characters
|
||||
|
||||
final int eventDataSrcIndex3 = 40;
|
||||
byte[] dsedVersionBytes = new byte[2];
|
||||
System.arraycopy(eventData, 40, dsedVersionBytes, 0, 2);
|
||||
System.arraycopy(eventData, eventDataSrcIndex3, dsedVersionBytes, 0, 2);
|
||||
String dsedVersion = HexUtils.byteArrayToHexString(dsedVersionBytes);
|
||||
if (dsedVersion == "") {
|
||||
dsedVersion = "version not readable";
|
||||
@ -75,9 +79,10 @@ public class NvIndexInstanceEventLogData {
|
||||
|
||||
if (dsedSignature.contains("SPDM Device Sec2")) {
|
||||
|
||||
int dsedEventDataSize = eventData.length - 24;
|
||||
final int eventDataSrcIndex4 = 24;
|
||||
final int dsedEventDataSize = eventData.length - eventDataSrcIndex4;
|
||||
byte[] dsedEventData = new byte[dsedEventDataSize];
|
||||
System.arraycopy(eventData, 24, dsedEventData, 0, dsedEventDataSize);
|
||||
System.arraycopy(eventData, eventDataSrcIndex4, dsedEventData, 0, dsedEventDataSize);
|
||||
|
||||
nvIndexInstanceInfo += " Signature = SPDM Device Sec2\n";
|
||||
|
||||
@ -89,7 +94,7 @@ public class NvIndexInstanceEventLogData {
|
||||
+ dsedVersion + "\n";
|
||||
}
|
||||
} else {
|
||||
nvIndexInstanceInfo = " Signature error: should be \'SPDM Device Sec2\' but is "
|
||||
nvIndexInstanceInfo = " Signature error: should be 'SPDM Device Sec2' but is "
|
||||
+ signature + "\n";
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,10 @@ public class SpdmCertificateChain {
|
||||
// * Length of the certificate chain to include all fields in this structure.
|
||||
// */
|
||||
//private int length = 0;
|
||||
/**
|
||||
* Array List of certs found in the chain.
|
||||
*/
|
||||
private final ArrayList<UefiX509Cert> certList = new ArrayList<UefiX509Cert>();
|
||||
/**
|
||||
* Root hash.
|
||||
*/
|
||||
@ -46,10 +50,6 @@ public class SpdmCertificateChain {
|
||||
* Number of certs in the SPDM cert chain.
|
||||
*/
|
||||
private int numberOfCerts = 0;
|
||||
/**
|
||||
* Array List of certs found in the chain.
|
||||
*/
|
||||
private ArrayList<UefiX509Cert> certList = new ArrayList<UefiX509Cert>();
|
||||
/**
|
||||
* Human-readable description of any error associated with SPDM base hash alg.
|
||||
*/
|
||||
@ -76,11 +76,13 @@ public class SpdmCertificateChain {
|
||||
|
||||
// Reserved: 2 bytes
|
||||
|
||||
final int spdmCertChainBytesSrcIndex = 4;
|
||||
rootHash = new byte[rootHashLength];
|
||||
System.arraycopy(spdmCertChainBytes, 4, rootHash, 0, rootHashLength);
|
||||
System.arraycopy(spdmCertChainBytes, spdmCertChainBytesSrcIndex, rootHash, 0, rootHashLength);
|
||||
|
||||
int certChainStartPos = 4 + rootHashLength;
|
||||
int certChainLength = spdmCertChainBytes.length - certChainStartPos;
|
||||
final int offsetForCertChain = 4;
|
||||
final int certChainStartPos = offsetForCertChain + rootHashLength;
|
||||
final int certChainLength = spdmCertChainBytes.length - certChainStartPos;
|
||||
byte[] certChainBytes = new byte[certChainLength];
|
||||
System.arraycopy(spdmCertChainBytes, certChainStartPos, certChainBytes, 0, certChainLength);
|
||||
|
||||
@ -113,10 +115,11 @@ public class SpdmCertificateChain {
|
||||
byte[] certData = new byte[cLength];
|
||||
certChainDataIS.read(certData);
|
||||
// put the cert back together
|
||||
byte[] certBlob = new byte[cLength + 4];
|
||||
final int certBlobStartIndex = 4;
|
||||
byte[] certBlob = new byte[cLength + certBlobStartIndex];
|
||||
System.arraycopy(certType, 0, certBlob, 0, 2);
|
||||
System.arraycopy(certLength, 0, certBlob, 2, 2);
|
||||
System.arraycopy(certData, 0, certBlob, 4, cLength);
|
||||
System.arraycopy(certData, 0, certBlob, certBlobStartIndex, cLength);
|
||||
cert = new UefiX509Cert(certBlob);
|
||||
//cert = new X509Certificate(certBlob);
|
||||
certList.add(cert);
|
||||
|
@ -4,12 +4,7 @@ package hirs.utils.tpm.eventlog.spdm;
|
||||
* Class for defining hash algorithms referenced in the DMTF SPDM specification.
|
||||
* SPDM 1.3.0, Table 21, MeasurementHashAlgo.
|
||||
*/
|
||||
public class SpdmHa {
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain
|
||||
*/
|
||||
private SpdmHa() { }
|
||||
public final class SpdmHa {
|
||||
|
||||
/**
|
||||
* Spdm Hash Alg = Raw bit stream.
|
||||
@ -40,6 +35,12 @@ public class SpdmHa {
|
||||
*/
|
||||
public static final int TPM_ALG_SHA3_512 = 64;
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain.
|
||||
*/
|
||||
private SpdmHa() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash name via a lookup.
|
||||
* Lookup based upon SPDM Spec v1.03 section 10.4.
|
||||
@ -48,32 +49,16 @@ public class SpdmHa {
|
||||
* @return name of the algorithm
|
||||
*/
|
||||
public static String tcgAlgIdToString(final int algId) {
|
||||
String alg;
|
||||
switch (algId) {
|
||||
case TPM_ALG_RAW:
|
||||
alg = "Raw Bit Stream";
|
||||
break;
|
||||
case TPM_ALG_SHA_256:
|
||||
alg = "TPM_ALG_SHA_256";
|
||||
break;
|
||||
case TPM_ALG_SHA_384:
|
||||
alg = "TPM_ALG_SHA_384";
|
||||
break;
|
||||
case TPM_ALG_SHA_512:
|
||||
alg = "TPM_ALG_SHA_512";
|
||||
break;
|
||||
case TPM_ALG_SHA3_256:
|
||||
alg = "TPM_ALG_SHA3_256";
|
||||
break;
|
||||
case TPM_ALG_SHA3_384:
|
||||
alg = "TPM_ALG_SHA3_384";
|
||||
break;
|
||||
case TPM_ALG_SHA3_512:
|
||||
alg = "TPM_ALG_SHA3_512";
|
||||
break;
|
||||
default:
|
||||
alg = "Unknown or invalid Hash";
|
||||
}
|
||||
String alg = switch (algId) {
|
||||
case TPM_ALG_RAW -> "Raw Bit Stream";
|
||||
case TPM_ALG_SHA_256 -> "TPM_ALG_SHA_256";
|
||||
case TPM_ALG_SHA_384 -> "TPM_ALG_SHA_384";
|
||||
case TPM_ALG_SHA_512 -> "TPM_ALG_SHA_512";
|
||||
case TPM_ALG_SHA3_256 -> "TPM_ALG_SHA3_256";
|
||||
case TPM_ALG_SHA3_384 -> "TPM_ALG_SHA3_384";
|
||||
case TPM_ALG_SHA3_512 -> "TPM_ALG_SHA3_512";
|
||||
default -> "Unknown or invalid Hash";
|
||||
};
|
||||
return alg;
|
||||
}
|
||||
|
||||
@ -85,32 +70,17 @@ public class SpdmHa {
|
||||
* @return size of the algorithm output
|
||||
*/
|
||||
public static int tcgAlgIdToByteSize(final int algId) {
|
||||
int byteSize;
|
||||
switch (algId) {
|
||||
//case TPM_ALG_RAW: // add this when have more test data
|
||||
// byteSize = ;
|
||||
// break;
|
||||
case TPM_ALG_SHA_256:
|
||||
byteSize = 32;
|
||||
break;
|
||||
case TPM_ALG_SHA_384:
|
||||
byteSize = 48;
|
||||
break;
|
||||
case TPM_ALG_SHA_512:
|
||||
byteSize = 64;
|
||||
break;
|
||||
case TPM_ALG_SHA3_256:
|
||||
byteSize = 32;
|
||||
break;
|
||||
case TPM_ALG_SHA3_384:
|
||||
byteSize = 48;
|
||||
break;
|
||||
case TPM_ALG_SHA3_512:
|
||||
byteSize = 64;
|
||||
break;
|
||||
default:
|
||||
byteSize = -1;
|
||||
}
|
||||
return byteSize;
|
||||
final int byteSize256 = 32;
|
||||
final int byteSize384 = 48;
|
||||
final int byteSize512 = 64;
|
||||
|
||||
return switch (algId) {
|
||||
// case TPM_ALG_RAW: // add this when have more test data
|
||||
// return ;
|
||||
case TPM_ALG_SHA_256, TPM_ALG_SHA3_256 -> byteSize256;
|
||||
case TPM_ALG_SHA_384, TPM_ALG_SHA3_384 -> byteSize384;
|
||||
case TPM_ALG_SHA_512, TPM_ALG_SHA3_512 -> byteSize512;
|
||||
default -> -1;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -27,15 +27,70 @@ import lombok.Getter;
|
||||
*/
|
||||
public class SpdmMeasurement {
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_0 = Immutable ROM.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_0 = 0;
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_1 = Mutable firmware.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_1 = 1;
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_2 = Hardware configuration.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_2 = 2;
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_3 = Firmware configuration.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_3 = 3;
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_4 = Freeform measurement manifest.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_4 = 4;
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_5 = Structured representation of debug and device mode.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_5 = 5;
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_6 = Mutable firmware's version number.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_6 = 6;
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_7 = Mutable firmware's security version number.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_7 = 7;
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_8 = Hash-extended measurement.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_8 = 8;
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_9 = Informational.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_9 = 9;
|
||||
|
||||
/**
|
||||
* MEASUREMENT_VALUE_10 = Structured measurement manifest.
|
||||
*/
|
||||
private static final int MEASUREMENT_VALUE_10 = 10;
|
||||
|
||||
/**
|
||||
* Measurement value (digest).
|
||||
*/
|
||||
private final byte[] dmtfSpecMeasurementValue;
|
||||
/**
|
||||
* Measurement value type (such as mutable firmware, etc).
|
||||
*/
|
||||
@Getter
|
||||
private int dmtfSpecMeasurementValueType = 0;
|
||||
/**
|
||||
* Measurement value (digest).
|
||||
*/
|
||||
private byte[] dmtfSpecMeasurementValue;
|
||||
|
||||
/**
|
||||
* SpdmMeasurement Constructor.
|
||||
@ -49,14 +104,16 @@ public class SpdmMeasurement {
|
||||
1);
|
||||
dmtfSpecMeasurementValueType = HexUtils.leReverseInt(dmtfSpecMeasurementValueTypeBytes);
|
||||
|
||||
// in future, can crosscheck this value size + 3 with the spdm block MeasurementSize size
|
||||
// in the future, can crosscheck this value size + 3 with the spdm block MeasurementSize size
|
||||
byte[] dmtfSpecMeasurementValueSizeBytes = new byte[2];
|
||||
System.arraycopy(spdmMeasBytes, 1, dmtfSpecMeasurementValueSizeBytes, 0,
|
||||
2);
|
||||
int dmtfSpecMeasurementValueSize = HexUtils.leReverseInt(dmtfSpecMeasurementValueSizeBytes);
|
||||
|
||||
dmtfSpecMeasurementValue = new byte[dmtfSpecMeasurementValueSize];
|
||||
System.arraycopy(spdmMeasBytes, 3, dmtfSpecMeasurementValue, 0,
|
||||
|
||||
final int sourceIndex = 3;
|
||||
System.arraycopy(spdmMeasBytes, sourceIndex, dmtfSpecMeasurementValue, 0,
|
||||
dmtfSpecMeasurementValueSize);
|
||||
}
|
||||
|
||||
@ -64,50 +121,23 @@ public class SpdmMeasurement {
|
||||
* Lookup for SPDM measurement value type.
|
||||
*
|
||||
* @param measValType the numerical representation of the measurement value type.
|
||||
*
|
||||
* @return a description of the measurement value type.
|
||||
*/
|
||||
public String dmtfSpecMeasurementValueTypeToString(final int measValType) {
|
||||
|
||||
String measValTypeStr;
|
||||
switch (measValType) {
|
||||
case 0:
|
||||
measValTypeStr = "Immutable ROM";
|
||||
break;
|
||||
case 1:
|
||||
measValTypeStr = "Mutable firmware";
|
||||
break;
|
||||
case 2:
|
||||
measValTypeStr = "Hardware configuration";
|
||||
break;
|
||||
case 3:
|
||||
measValTypeStr = "Firmware configuration";
|
||||
break;
|
||||
case 4:
|
||||
measValTypeStr = "Freeform measurement manifest";
|
||||
break;
|
||||
case 5:
|
||||
measValTypeStr = "Structured representation of debug and device mode";
|
||||
break;
|
||||
case 6:
|
||||
measValTypeStr = "Mutable firmware's version number";
|
||||
break;
|
||||
case 7:
|
||||
measValTypeStr = "Mutable firmware's security version number";
|
||||
break;
|
||||
case 8:
|
||||
measValTypeStr = "Hash-extended measurement";
|
||||
break;
|
||||
case 9:
|
||||
measValTypeStr = "Informational";
|
||||
break;
|
||||
case 10:
|
||||
measValTypeStr = "Structured measurement manifest";
|
||||
break;
|
||||
default:
|
||||
measValTypeStr = "Unknown or invalid DMTF Spec Measurement Value Type";
|
||||
}
|
||||
return measValTypeStr;
|
||||
return switch (measValType) {
|
||||
case MEASUREMENT_VALUE_0 -> "Immutable ROM";
|
||||
case MEASUREMENT_VALUE_1 -> "Mutable firmware";
|
||||
case MEASUREMENT_VALUE_2 -> "Hardware configuration";
|
||||
case MEASUREMENT_VALUE_3 -> "Firmware configuration";
|
||||
case MEASUREMENT_VALUE_4 -> "Freeform measurement manifest";
|
||||
case MEASUREMENT_VALUE_5 -> "Structured representation of debug and device mode";
|
||||
case MEASUREMENT_VALUE_6 -> "Mutable firmware's version number";
|
||||
case MEASUREMENT_VALUE_7 -> "Mutable firmware's security version number";
|
||||
case MEASUREMENT_VALUE_8 -> "Hash-extended measurement";
|
||||
case MEASUREMENT_VALUE_9 -> "Informational";
|
||||
case MEASUREMENT_VALUE_10 -> "Structured measurement manifest";
|
||||
default -> "Unknown or invalid DMTF Spec Measurement Value Type";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,11 +7,6 @@ package hirs.utils.tpm.eventlog.uefi;
|
||||
*/
|
||||
public final class UefiConstants {
|
||||
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain
|
||||
*/
|
||||
private UefiConstants() { }
|
||||
|
||||
/**
|
||||
* 2 byte size.
|
||||
*/
|
||||
@ -287,4 +282,9 @@ public final class UefiConstants {
|
||||
* file status, where file is not accessible (either not found, or no access permission).
|
||||
*/
|
||||
public static final String FILESTATUS_NOT_ACCESSIBLE = "fileNotAccessible";
|
||||
/**
|
||||
* Default private constructor so checkstyles doesn't complain.
|
||||
*/
|
||||
private UefiConstants() {
|
||||
}
|
||||
}
|
||||
|
@ -1,436 +1,20 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import hirs.utils.digest.Digest;
|
||||
import hirs.utils.digest.DigestAlgorithm;
|
||||
import hirs.utils.digest.DigestComparisonResultType;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Unit tests for the <code>Digest</code> class.
|
||||
*/
|
||||
public class DigestTest {
|
||||
private static final int DIGEST_LENGTH_BYTES = 20;
|
||||
|
||||
/**
|
||||
* Tests that constructor throws a <code>IllegalArgumentException</code> when a
|
||||
* null <code>DigestAlgorithm</code> is passed into constructor.
|
||||
*/
|
||||
@Test
|
||||
public final void nullAlgorithm() {
|
||||
final byte[] digest = getTestDigest(16);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(null, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that constructor throws a <code>IllegalArgumentException</code> when a
|
||||
* null digest is passed into constructor.
|
||||
*/
|
||||
@Test
|
||||
public final void nullDigest() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.MD2, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that constructor throws a <code>IllegalArgumentException</code> when an
|
||||
* digest that is an empty array is passed into constructor.
|
||||
*/
|
||||
@Test
|
||||
public final void emptyArrayDigest() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.MD2, new byte[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that MD2 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void md2() {
|
||||
final byte[] digest = getTestDigest(16);
|
||||
final Digest d = new Digest(DigestAlgorithm.MD2, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an MD2 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringMD2() {
|
||||
final byte[] digestBytes = getTestDigest(16);
|
||||
Digest digest = new Digest(DigestAlgorithm.MD2, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that MD2 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void md2IllegalDigest() {
|
||||
final byte[] digest = getTestDigest(17);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.MD2, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that MD5 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void md5() {
|
||||
final byte[] digest = getTestDigest(16);
|
||||
final Digest d = new Digest(DigestAlgorithm.MD5, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an MD5 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringMD5() {
|
||||
final byte[] digestBytes = getTestDigest(16);
|
||||
Digest digest = new Digest(DigestAlgorithm.MD5, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that MD5 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void md5IllegalDigest() {
|
||||
final byte[] digest = getTestDigest(17);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.MD5, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA1 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void sha1() {
|
||||
final byte[] digest = getTestDigest(20);
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA1, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA1 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringSHA1() {
|
||||
final byte[] digestBytes = getTestDigest(20);
|
||||
Digest digest = new Digest(DigestAlgorithm.SHA1, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA1 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void sha1IllegalDigest() {
|
||||
final byte[] digest = getTestDigest(21);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.SHA1, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA256 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void sha256() {
|
||||
final byte[] digest = getTestDigest(32);
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA256, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA256 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringSHA256() {
|
||||
final byte[] digestBytes = getTestDigest(32);
|
||||
Digest digest = new Digest(DigestAlgorithm.SHA256, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA256 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void sha256IllegalDigest() {
|
||||
final byte[] digest = getTestDigest(33);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.SHA256, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA384 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void sha384() {
|
||||
final byte[] digest = getTestDigest(48);
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA384, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA384 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringSHA384() {
|
||||
final byte[] digestBytes = getTestDigest(48);
|
||||
Digest digest = new Digest(DigestAlgorithm.SHA384, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA384 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void sha384IllegalDigest() {
|
||||
final byte[] digest = getTestDigest(49);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.SHA384, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA512 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void sha512() {
|
||||
final byte[] digest = getTestDigest(64);
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA512, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA512 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringSHA512() {
|
||||
final byte[] digestBytes = getTestDigest(64);
|
||||
Digest digest = new Digest(DigestAlgorithm.SHA512, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA512 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void sha512IllegalDigest() {
|
||||
final byte[] digest = getTestDigest(65);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.SHA512, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the correct <code>DigestAlgorithm</code> is returned by
|
||||
* {@link Digest#getAlgorithm()}.
|
||||
*/
|
||||
@Test
|
||||
public final void testGetAlgorithm() {
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
|
||||
Assertions.assertEquals(d.getAlgorithm(), DigestAlgorithm.SHA1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the bytes of the digest are created and do not affect the
|
||||
* underlying state of the <code>Digest</code> instance.
|
||||
*/
|
||||
@Test
|
||||
public final void testGetDigest() {
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
|
||||
final byte[] digestBytes = d.getDigest();
|
||||
final byte[] testBytes = getTestDigest(20);
|
||||
Assertions.assertArrayEquals(digestBytes, testBytes);
|
||||
digestBytes[0] = (byte) (digestBytes[0] + 1);
|
||||
Assertions.assertArrayEquals(d.getDigest(), testBytes);
|
||||
Assertions.assertFalse(Arrays.equals(d.getDigest(), digestBytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s have equal hash code for same
|
||||
* algorithm and digest.
|
||||
*/
|
||||
@Test
|
||||
public final void testHashCodeEqual() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
|
||||
Assertions.assertEquals(d2.hashCode(), d1.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s indicate MATCH when compared.
|
||||
*/
|
||||
@Test
|
||||
public final void testMatchedComparison() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s have unequal hash code for same
|
||||
* digest but different algorithm.
|
||||
*/
|
||||
@Test
|
||||
public final void testHashCodeNotEqualAlgorithm() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(16));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(16));
|
||||
Assertions.assertNotEquals(d2.hashCode(), d1.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s indicate MISMATCH when compared.
|
||||
*/
|
||||
@Test
|
||||
public final void testMismatchAlgorithm() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(16));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(16));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s have unequal hash code for same
|
||||
* algorithm but different digest.
|
||||
*/
|
||||
@Test
|
||||
public final void testHashCodeNotEqualDigest() {
|
||||
final byte[] digest = getTestDigest(20);
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, digest);
|
||||
digest[0] += 1;
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, digest);
|
||||
Assertions.assertNotEquals(d2.hashCode(), d1.hashCode());
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s are equal for same algorithm and
|
||||
* digest.
|
||||
*/
|
||||
@Test
|
||||
public final void testEqual() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
|
||||
Assertions.assertEquals(d2, d1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s are unequal for same digest but
|
||||
* different algorithm.
|
||||
*/
|
||||
@Test
|
||||
public final void testNotEqualAlgorithm() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(16));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(16));
|
||||
Assertions.assertNotEquals(d2, d1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s are unequal for same algorithm but
|
||||
* different digest.
|
||||
*/
|
||||
@Test
|
||||
public final void testNotEqualDigest() {
|
||||
final byte[] digest = getTestDigest(20);
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, digest);
|
||||
digest[0] += 1;
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, digest);
|
||||
Assertions.assertNotEquals(d2, d1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that comparing a null Digest to a Digest indicates an UNKNOWN
|
||||
* comparison type.
|
||||
*/
|
||||
@Test
|
||||
public final void testCompareToNull() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(16));
|
||||
Assertions.assertEquals(DigestComparisonResultType.UNKNOWN, d1.compare(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that comparing two Digests with hashes with values of zero gives a MATCH
|
||||
* comparison result.
|
||||
*/
|
||||
@Test
|
||||
public final void testCompareToDigestWithBothZeroizedHash() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(20));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(20));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that comparing two Digests, one with a hash of value zero, gives a MISMATCH
|
||||
* comparison result.
|
||||
*/
|
||||
@Test
|
||||
public final void testCompareToDigestWithOneZeroizedHash() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(20));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that comparing two Digests with a hash of no data gives a MATCH
|
||||
* comparison result.
|
||||
*/
|
||||
@Test
|
||||
public final void testCompareToDigestWithBothEmptyHash() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that comparing two Digests, one with a hash of no data, gives a MISMATCH
|
||||
* comparison result.
|
||||
*/
|
||||
@Test
|
||||
public final void testCompareToDigestWithOneEmptyHash() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(20));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that if someone tries to recreate a Digest using an invalid String, an error is thrown.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringInvalid() {
|
||||
String invalidDigestString = "SHA1 00000000000000000000";
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> Digest.fromString(invalidDigestString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a test SHA1 digest.
|
||||
*
|
||||
@ -464,7 +48,455 @@ public class DigestTest {
|
||||
return new byte[count];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that constructor throws a <code>IllegalArgumentException</code> when a
|
||||
* null <code>DigestAlgorithm</code> is passed into constructor.
|
||||
*/
|
||||
@Test
|
||||
public final void nullAlgorithm() {
|
||||
final int count = 16;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(null, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that constructor throws a <code>IllegalArgumentException</code> when a
|
||||
* null digest is passed into constructor.
|
||||
*/
|
||||
@Test
|
||||
public final void nullDigest() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.MD2, null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that constructor throws a <code>IllegalArgumentException</code> when an
|
||||
* digest that is an empty array is passed into constructor.
|
||||
*/
|
||||
@Test
|
||||
public final void emptyArrayDigest() {
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.MD2, new byte[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that MD2 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void md2() {
|
||||
final int count = 16;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
final Digest d = new Digest(DigestAlgorithm.MD2, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an MD2 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringMD2() {
|
||||
final int count = 16;
|
||||
final byte[] digestBytes = getTestDigest(count);
|
||||
Digest digest = new Digest(DigestAlgorithm.MD2, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that MD2 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void md2IllegalDigest() {
|
||||
final int count = 17;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.MD2, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that MD5 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void md5() {
|
||||
final int count = 16;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
final Digest d = new Digest(DigestAlgorithm.MD5, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that an MD5 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringMD5() {
|
||||
final int count = 16;
|
||||
final byte[] digestBytes = getTestDigest(count);
|
||||
Digest digest = new Digest(DigestAlgorithm.MD5, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that MD5 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void md5IllegalDigest() {
|
||||
final int count = 17;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.MD5, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA1 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void sha1() {
|
||||
final int count = 20;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA1, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA1 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringSHA1() {
|
||||
final int count = 20;
|
||||
final byte[] digestBytes = getTestDigest(count);
|
||||
Digest digest = new Digest(DigestAlgorithm.SHA1, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA1 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void sha1IllegalDigest() {
|
||||
final int count = 21;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.SHA1, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA256 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void sha256() {
|
||||
final int count = 32;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA256, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA256 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringSHA256() {
|
||||
final int count = 32;
|
||||
final byte[] digestBytes = getTestDigest(count);
|
||||
Digest digest = new Digest(DigestAlgorithm.SHA256, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA256 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void sha256IllegalDigest() {
|
||||
final int count = 33;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.SHA256, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA384 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void sha384() {
|
||||
final int count = 48;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA384, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA384 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringSHA384() {
|
||||
final int count = 48;
|
||||
final byte[] digestBytes = getTestDigest(count);
|
||||
Digest digest = new Digest(DigestAlgorithm.SHA384, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA384 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void sha384IllegalDigest() {
|
||||
final int count = 49;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.SHA384, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA512 digest can be created.
|
||||
*/
|
||||
@Test
|
||||
public final void sha512() {
|
||||
final int count = 64;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA512, digest);
|
||||
Assertions.assertNotNull(d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA512 digest can be recreated from a string.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringSHA512() {
|
||||
final int count = 64;
|
||||
final byte[] digestBytes = getTestDigest(count);
|
||||
Digest digest = new Digest(DigestAlgorithm.SHA512, digestBytes);
|
||||
String digestString = digest.toString();
|
||||
Digest digestFromString = Digest.fromString(digestString);
|
||||
Assertions.assertEquals(digest, digestFromString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that SHA512 digest cannot be created with a digest that has extra
|
||||
* bytes.
|
||||
*/
|
||||
@Test
|
||||
public final void sha512IllegalDigest() {
|
||||
final int count = 65;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> new Digest(DigestAlgorithm.SHA512, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the correct <code>DigestAlgorithm</code> is returned by
|
||||
* {@link Digest#getAlgorithm()}.
|
||||
*/
|
||||
@Test
|
||||
public final void testGetAlgorithm() {
|
||||
final int count = 20;
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
|
||||
Assertions.assertEquals(d.getAlgorithm(), DigestAlgorithm.SHA1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the bytes of the digest are created and do not affect the
|
||||
* underlying state of the <code>Digest</code> instance.
|
||||
*/
|
||||
@Test
|
||||
public final void testGetDigest() {
|
||||
final int count = 20;
|
||||
final Digest d = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
|
||||
final byte[] digestBytes = d.getDigest();
|
||||
final byte[] testBytes = getTestDigest(count);
|
||||
Assertions.assertArrayEquals(digestBytes, testBytes);
|
||||
digestBytes[0] = (byte) (digestBytes[0] + 1);
|
||||
Assertions.assertArrayEquals(d.getDigest(), testBytes);
|
||||
Assertions.assertFalse(Arrays.equals(d.getDigest(), digestBytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s have equal hash code for same
|
||||
* algorithm and digest.
|
||||
*/
|
||||
@Test
|
||||
public final void testHashCodeEqual() {
|
||||
final int count = 20;
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
|
||||
Assertions.assertEquals(d2.hashCode(), d1.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s indicate MATCH when compared.
|
||||
*/
|
||||
@Test
|
||||
public final void testMatchedComparison() {
|
||||
final int count = 20;
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s have unequal hash code for same
|
||||
* digest but different algorithm.
|
||||
*/
|
||||
@Test
|
||||
public final void testHashCodeNotEqualAlgorithm() {
|
||||
final int count = 16;
|
||||
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(count));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(count));
|
||||
Assertions.assertNotEquals(d2.hashCode(), d1.hashCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s indicate MISMATCH when compared.
|
||||
*/
|
||||
@Test
|
||||
public final void testMismatchAlgorithm() {
|
||||
final int count = 16;
|
||||
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(count));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(count));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s have unequal hash code for same
|
||||
* algorithm but different digest.
|
||||
*/
|
||||
@Test
|
||||
public final void testHashCodeNotEqualDigest() {
|
||||
final int count = 20;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, digest);
|
||||
digest[0] += 1;
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, digest);
|
||||
Assertions.assertNotEquals(d2.hashCode(), d1.hashCode());
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s are equal for same algorithm and
|
||||
* digest.
|
||||
*/
|
||||
@Test
|
||||
public final void testEqual() {
|
||||
final int count = 20;
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
|
||||
Assertions.assertEquals(d2, d1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s are unequal for same digest but
|
||||
* different algorithm.
|
||||
*/
|
||||
@Test
|
||||
public final void testNotEqualAlgorithm() {
|
||||
final int count = 16;
|
||||
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(count));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.MD5, getTestDigest(count));
|
||||
Assertions.assertNotEquals(d2, d1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that two <code>Digest</code>s are unequal for same algorithm but
|
||||
* different digest.
|
||||
*/
|
||||
@Test
|
||||
public final void testNotEqualDigest() {
|
||||
final int count = 20;
|
||||
final byte[] digest = getTestDigest(count);
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, digest);
|
||||
digest[0] += 1;
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, digest);
|
||||
Assertions.assertNotEquals(d2, d1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that comparing a null Digest to a Digest indicates an UNKNOWN
|
||||
* comparison type.
|
||||
*/
|
||||
@Test
|
||||
public final void testCompareToNull() {
|
||||
final int count = 16;
|
||||
final Digest d1 = new Digest(DigestAlgorithm.MD2, getTestDigest(count));
|
||||
Assertions.assertEquals(DigestComparisonResultType.UNKNOWN, d1.compare(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that comparing two Digests with hashes with values of zero gives a MATCH
|
||||
* comparison result.
|
||||
*/
|
||||
@Test
|
||||
public final void testCompareToDigestWithBothZeroizedHash() {
|
||||
final int count = 20;
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(count));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(count));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that comparing two Digests, one with a hash of value zero, gives a MISMATCH
|
||||
* comparison result.
|
||||
*/
|
||||
@Test
|
||||
public final void testCompareToDigestWithOneZeroizedHash() {
|
||||
final int count = 20;
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getZeroValueDigest(count));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that comparing two Digests with a hash of no data gives a MATCH
|
||||
* comparison result.
|
||||
*/
|
||||
@Test
|
||||
public final void testCompareToDigestWithBothEmptyHash() {
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that comparing two Digests, one with a hash of no data, gives a MISMATCH
|
||||
* comparison result.
|
||||
*/
|
||||
@Test
|
||||
public final void testCompareToDigestWithOneEmptyHash() {
|
||||
final int count = 20;
|
||||
final Digest d1 = new Digest(DigestAlgorithm.SHA1, getTestDigest(count));
|
||||
final Digest d2 = new Digest(DigestAlgorithm.SHA1, getEmptySHA1Digest());
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d1.compare(d2));
|
||||
Assertions.assertEquals(DigestComparisonResultType.MISMATCH, d2.compare(d1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that if someone tries to recreate a Digest using an invalid String, an error is thrown.
|
||||
*/
|
||||
@Test
|
||||
public final void testFromStringInvalid() {
|
||||
String invalidDigestString = "SHA1 00000000000000000000";
|
||||
Assertions.assertThrows(IllegalArgumentException.class,
|
||||
() -> Digest.fromString(invalidDigestString));
|
||||
}
|
||||
|
||||
private byte[] getEmptySHA1Digest() {
|
||||
return DigestUtils.sha1(new byte[]{});
|
||||
return DigestUtils.sha1(new byte[] {});
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,11 @@ package hirs.data.persist;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.info.FirmwareInfo;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
|
||||
|
||||
/**
|
||||
* FirmwareInfoTest is a unit test class for FirmwareInfo.
|
||||
*/
|
||||
@ -15,18 +15,20 @@ public class FirmwareInfoTest {
|
||||
private static final String BIOS_VENDOR = "test bios vendor";
|
||||
private static final String BIOS_VERSION = "test bios version";
|
||||
private static final String BIOS_RELEASE_DATE = "test bios release date";
|
||||
private static final int PRIMARY_SIZE = 257;
|
||||
private static final int SECONDARY_SIZE = 33;
|
||||
|
||||
private static final String LONG_BIOS_VENDOR = StringUtils.rightPad(
|
||||
"test bios vendor",
|
||||
257
|
||||
BIOS_VENDOR,
|
||||
PRIMARY_SIZE
|
||||
);
|
||||
private static final String LONG_BIOS_VERSION = StringUtils.rightPad(
|
||||
"test bios version",
|
||||
257
|
||||
BIOS_VERSION,
|
||||
PRIMARY_SIZE
|
||||
);
|
||||
private static final String LONG_BIOS_RELEASE_DATE = StringUtils.rightPad(
|
||||
"test bios release date",
|
||||
33
|
||||
BIOS_RELEASE_DATE,
|
||||
SECONDARY_SIZE
|
||||
);
|
||||
|
||||
/**
|
||||
@ -44,8 +46,8 @@ public class FirmwareInfoTest {
|
||||
public final void firmwareInfoNoParams() {
|
||||
FirmwareInfo firmwareInfo = new FirmwareInfo();
|
||||
Assertions.assertEquals(NOT_SPECIFIED, firmwareInfo.getBiosVendor());
|
||||
Assertions.assertEquals(NOT_SPECIFIED,firmwareInfo.getBiosVersion());
|
||||
Assertions.assertEquals(NOT_SPECIFIED,firmwareInfo.getBiosReleaseDate());
|
||||
Assertions.assertEquals(NOT_SPECIFIED, firmwareInfo.getBiosVersion());
|
||||
Assertions.assertEquals(NOT_SPECIFIED, firmwareInfo.getBiosReleaseDate());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,12 +1,12 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.info.HardwareInfo;
|
||||
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
|
||||
|
||||
/**
|
||||
* HardwareInfoTest is a unit test class for HardwareInfo.
|
||||
*/
|
||||
@ -18,30 +18,32 @@ public class HardwareInfoTest {
|
||||
private static final String SERIAL_NUMBER = "test serial number";
|
||||
private static final String CHASSIS_SERIAL_NUMBER = "test chassis serial number";
|
||||
private static final String BASEBOARD_SERIAL_NUMBER = "test baseboard serial number";
|
||||
private static final int PRIMARY_SIZE = 257;
|
||||
private static final int SECONDARY_SIZE = 65;
|
||||
|
||||
private static final String LONG_MANUFACTURER = StringUtils.rightPad(
|
||||
"test manufacturer",
|
||||
257
|
||||
MANUFACTURER,
|
||||
PRIMARY_SIZE
|
||||
);
|
||||
private static final String LONG_PRODUCT_NAME = StringUtils.rightPad(
|
||||
"test product name",
|
||||
257
|
||||
PRODUCT_NAME,
|
||||
PRIMARY_SIZE
|
||||
);
|
||||
private static final String LONG_VERSION = StringUtils.rightPad(
|
||||
"test version",
|
||||
65
|
||||
VERSION,
|
||||
SECONDARY_SIZE
|
||||
);
|
||||
private static final String LONG_SERIAL_NUMBER = StringUtils.rightPad(
|
||||
"test serial number",
|
||||
257
|
||||
SERIAL_NUMBER,
|
||||
PRIMARY_SIZE
|
||||
);
|
||||
private static final String LONG_CHASSIS_SERIAL_NUMBER = StringUtils.rightPad(
|
||||
"test chassis serial number",
|
||||
257
|
||||
CHASSIS_SERIAL_NUMBER,
|
||||
PRIMARY_SIZE
|
||||
);
|
||||
private static final String LONG_BASEBOARD_SERIAL_NUMBER = StringUtils.rightPad(
|
||||
"test baseboard serial number",
|
||||
257
|
||||
BASEBOARD_SERIAL_NUMBER,
|
||||
PRIMARY_SIZE
|
||||
);
|
||||
|
||||
/**
|
||||
|
@ -1,12 +1,12 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.info.NetworkInfo;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
/**
|
||||
* NetworkInfoTest is a unit test class for NetworkInfo.
|
||||
*/
|
||||
@ -17,6 +17,15 @@ public class NetworkInfoTest {
|
||||
private static final byte[] MAC_ADDRESS = new byte[] {11, 22, 33, 44, 55,
|
||||
66};
|
||||
|
||||
private static InetAddress getTestIpAddress() {
|
||||
try {
|
||||
final byte[] byteAddress = new byte[] {127, 0, 0, 1};
|
||||
return InetAddress.getByAddress(byteAddress);
|
||||
} catch (UnknownHostException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests instantiation of a NetworkInfo object.
|
||||
*/
|
||||
@ -103,14 +112,14 @@ public class NetworkInfoTest {
|
||||
* Tests that hashcodes generated by NetworkInfo objects with different IP
|
||||
* addresses are not equal.
|
||||
*
|
||||
* @throws UnknownHostException
|
||||
* in case the InetAddress is not created correctly
|
||||
* @throws UnknownHostException in case the InetAddress is not created correctly
|
||||
*/
|
||||
@Test
|
||||
public final void testHashCodeNotEqualsIpAddress()
|
||||
throws UnknownHostException {
|
||||
final byte[] byteAddress = new byte[] {127, 0, 0, 2};
|
||||
final InetAddress ipAddress2 =
|
||||
InetAddress.getByAddress(new byte[] {127, 0, 0, 2});
|
||||
InetAddress.getByAddress(byteAddress);
|
||||
NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
|
||||
NetworkInfo ni2 = new NetworkInfo(HOSTNAME, ipAddress2, MAC_ADDRESS);
|
||||
Assertions.assertNotEquals(ni2.hashCode(), ni1.hashCode());
|
||||
@ -155,13 +164,13 @@ public class NetworkInfoTest {
|
||||
* Tests that two NetworkInfo objects are not equal if they have different
|
||||
* IP addresses.
|
||||
*
|
||||
* @throws UnknownHostException
|
||||
* in case InetAddress is not created correctly
|
||||
* @throws UnknownHostException in case InetAddress is not created correctly
|
||||
*/
|
||||
@Test
|
||||
public final void testNotEqualsIpAddress() throws UnknownHostException {
|
||||
final byte[] byteAddress = new byte[] {127, 0, 0, 2};
|
||||
final InetAddress ipAddress2 =
|
||||
InetAddress.getByAddress(new byte[] {127, 0, 0, 2});
|
||||
InetAddress.getByAddress(byteAddress);
|
||||
NetworkInfo ni1 = new NetworkInfo(HOSTNAME, IP_ADDRESS, MAC_ADDRESS);
|
||||
NetworkInfo ni2 = new NetworkInfo(HOSTNAME, ipAddress2, MAC_ADDRESS);
|
||||
Assertions.assertNotEquals(ni2, ni1);
|
||||
@ -178,12 +187,4 @@ public class NetworkInfoTest {
|
||||
NetworkInfo ni2 = new NetworkInfo(HOSTNAME, IP_ADDRESS, macAddress2);
|
||||
Assertions.assertNotEquals(ni2, ni1);
|
||||
}
|
||||
|
||||
private static InetAddress getTestIpAddress() {
|
||||
try {
|
||||
return InetAddress.getByAddress(new byte[] {127, 0, 0, 1});
|
||||
} catch (UnknownHostException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package hirs.data.persist;
|
||||
|
||||
import hirs.attestationca.persist.entity.userdefined.info.OSInfo;
|
||||
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static hirs.utils.enums.DeviceInfoEnums.NOT_SPECIFIED;
|
||||
|
||||
/**
|
||||
* OSInfoTest is a unit test class for OSInfo.
|
||||
*/
|
||||
@ -17,10 +17,12 @@ public class OSInfoTest {
|
||||
private static final String OS_ARCH = "test osArch";
|
||||
private static final String DISTRIBUTION = "test distribution";
|
||||
private static final String DISTRIBUTION_RELEASE = "test distribution release";
|
||||
private static final int PRIMARY_SIZE = 257;
|
||||
private static final int SECONDARY_SIZE = 33;
|
||||
|
||||
private static final String LONG_OS_NAME = StringUtils.rightPad("test os", 257);
|
||||
private static final String LONG_OS_VERSION = StringUtils.rightPad("test osVersion", 257);
|
||||
private static final String LONG_OS_ARCH = StringUtils.rightPad("test osArch", 33);
|
||||
private static final String LONG_OS_NAME = StringUtils.rightPad(OS_NAME, PRIMARY_SIZE);
|
||||
private static final String LONG_OS_VERSION = StringUtils.rightPad(OS_VERSION, PRIMARY_SIZE);
|
||||
private static final String LONG_OS_ARCH = StringUtils.rightPad(OS_ARCH, SECONDARY_SIZE);
|
||||
|
||||
/**
|
||||
* Tests instantiation of an OSInfo object.
|
||||
|
@ -0,0 +1 @@
|
||||
package hirs.data.persist;
|
@ -1,25 +1,29 @@
|
||||
package hirs.tpm.eventlog.uefi;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
import com.eclipsesource.json.JsonObject;
|
||||
import hirs.utils.HexUtils;
|
||||
import hirs.utils.JsonUtils;
|
||||
import hirs.utils.tpm.eventlog.uefi.*;
|
||||
import hirs.utils.tpm.eventlog.uefi.UefiDevicePath;
|
||||
import hirs.utils.tpm.eventlog.uefi.UefiFirmware;
|
||||
import hirs.utils.tpm.eventlog.uefi.UefiGuid;
|
||||
import hirs.utils.tpm.eventlog.uefi.UefiPartition;
|
||||
import hirs.utils.tpm.eventlog.uefi.UefiVariable;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import hirs.utils.HexUtils;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
|
||||
/**
|
||||
* Class for testing TCG Event Log processing of UEFI defined Data.
|
||||
*/
|
||||
@ -70,7 +74,7 @@ public class UefiProcessingTest {
|
||||
Path jsonPath = Paths.get(this.getClass()
|
||||
.getResource(JSON_FILE).toURI());
|
||||
String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_VARIABLE_BOOT),
|
||||
"UTF-8");
|
||||
StandardCharsets.UTF_8);
|
||||
byte[] uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt);
|
||||
UefiVariable uefiVariable = new UefiVariable(uefiVariableBytes);
|
||||
UefiGuid guid = uefiVariable.getUefiVarGuid();
|
||||
@ -83,7 +87,7 @@ public class UefiProcessingTest {
|
||||
|
||||
uefiTxt = IOUtils.toString(this.getClass()
|
||||
.getResourceAsStream(UEFI_VARIABLE_BOOT_SECURE_BOOT),
|
||||
"UTF-8");
|
||||
StandardCharsets.UTF_8);
|
||||
uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt);
|
||||
uefiVariable = new UefiVariable(uefiVariableBytes);
|
||||
guid = uefiVariable.getUefiVarGuid();
|
||||
@ -94,7 +98,7 @@ public class UefiProcessingTest {
|
||||
Assertions.assertEquals("SecureBoot", varName);
|
||||
|
||||
uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(
|
||||
UEFI_VARIABLE_BOOT_DRIVER_CONFIG_KEK), "UTF-8");
|
||||
UEFI_VARIABLE_BOOT_DRIVER_CONFIG_KEK), StandardCharsets.UTF_8);
|
||||
uefiVariableBytes = HexUtils.hexStringToByteArray(uefiTxt);
|
||||
uefiVariable = new UefiVariable(uefiVariableBytes);
|
||||
varName = uefiVariable.getEfiVarName();
|
||||
@ -116,7 +120,7 @@ public class UefiProcessingTest {
|
||||
Path jsonPath = Paths.get(this.getClass()
|
||||
.getResource(JSON_FILE).toURI());
|
||||
String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_GPT_EVENT),
|
||||
"UTF-8");
|
||||
StandardCharsets.UTF_8);
|
||||
byte[] uefiPartitionBytes = HexUtils.hexStringToByteArray(uefiTxt);
|
||||
UefiPartition gptPart = new UefiPartition(uefiPartitionBytes);
|
||||
String gptPartName = gptPart.getPartitionName();
|
||||
@ -143,13 +147,17 @@ public class UefiProcessingTest {
|
||||
CertificateException, NoSuchAlgorithmException {
|
||||
LOGGER.debug("Testing the parsing of Uefi Firmware Blob");
|
||||
String uefiTxt = IOUtils.toString(this.getClass()
|
||||
.getResourceAsStream(UEFI_FW_BLOB), "UTF-8");
|
||||
.getResourceAsStream(UEFI_FW_BLOB), StandardCharsets.UTF_8);
|
||||
byte[] uefiFwBlobBytes = HexUtils.hexStringToByteArray(uefiTxt);
|
||||
UefiFirmware uefiFWBlob = new UefiFirmware(uefiFwBlobBytes);
|
||||
int fwAddress = uefiFWBlob.getPhysicalBlobAddress();
|
||||
int fwLength = uefiFWBlob.getBlobLength();
|
||||
Assertions.assertEquals(1797287936, fwAddress);
|
||||
Assertions.assertEquals(851968, fwLength);
|
||||
|
||||
final int expectedFwAddress = 1797287936;
|
||||
Assertions.assertEquals(expectedFwAddress, fwAddress);
|
||||
|
||||
final int expectedFwLength = 851968;
|
||||
Assertions.assertEquals(expectedFwLength, fwLength);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -162,7 +170,7 @@ public class UefiProcessingTest {
|
||||
public final void testUefiDevicePath() throws IOException, URISyntaxException {
|
||||
LOGGER.debug("Testing the parsing of Uefi Device Path");
|
||||
String uefiTxt = IOUtils.toString(this.getClass().getResourceAsStream(UEFI_DEVICE_PATH),
|
||||
"UTF-8");
|
||||
StandardCharsets.UTF_8);
|
||||
byte[] uefiFwBlobBytes = HexUtils.hexStringToByteArray(uefiTxt);
|
||||
UefiDevicePath uefiDevPath = new UefiDevicePath(uefiFwBlobBytes);
|
||||
String devPathType = uefiDevPath.getType();
|
||||
|
@ -0,0 +1 @@
|
||||
package hirs.tpm.eventlog.uefi;
|
@ -2,8 +2,9 @@ package hirs.utils;
|
||||
|
||||
import org.apache.logging.log4j.util.Strings;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Tests methods in the (@link BouncyCastleUtils) utility class.
|
||||
|
@ -1,6 +1,7 @@
|
||||
package hirs.utils;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@ -14,11 +15,10 @@ public class HexUtilsTest {
|
||||
*/
|
||||
@Test
|
||||
public void testHexStringToByteArray() {
|
||||
String s = "abcd1234";
|
||||
byte[] target = {-85, -51, 18, 52};
|
||||
|
||||
byte[] b = HexUtils.hexStringToByteArray(s);
|
||||
assertArrayEquals(b, target);
|
||||
final String testString = "abcd1234";
|
||||
final byte[] expectedBytes = {-85, -51, 18, 52};
|
||||
final byte[] actualBytes = HexUtils.hexStringToByteArray(testString);
|
||||
assertArrayEquals(expectedBytes, actualBytes);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -26,11 +26,10 @@ public class HexUtilsTest {
|
||||
*/
|
||||
@Test
|
||||
public void testByteArrayToHexString() {
|
||||
String target = "abcd1234";
|
||||
byte[] b = {-85, -51, 18, 52};
|
||||
|
||||
String s = HexUtils.byteArrayToHexString(b);
|
||||
assertEquals(s, target);
|
||||
final byte[] byteArray = {-85, -51, 18, 52};
|
||||
final String expectedString = "abcd1234";
|
||||
final String actualString = HexUtils.byteArrayToHexString(byteArray);
|
||||
assertEquals(expectedString, actualString);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -38,11 +37,10 @@ public class HexUtilsTest {
|
||||
*/
|
||||
@Test
|
||||
public void testByteArrayToHexStringConditional() {
|
||||
String target = "abcd0100";
|
||||
byte[] b = {-85, -51, 1, 0};
|
||||
|
||||
String s = HexUtils.byteArrayToHexString(b);
|
||||
assertEquals(s, target);
|
||||
final byte[] byteArray = {-85, -51, 1, 0};
|
||||
final String expectedHexString = "abcd0100";
|
||||
final String actualHexString = HexUtils.byteArrayToHexString(byteArray);
|
||||
assertEquals(expectedHexString, actualHexString);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,9 +48,10 @@ public class HexUtilsTest {
|
||||
*/
|
||||
@Test
|
||||
public void testHexToInt() {
|
||||
String s = "ff";
|
||||
Integer i = HexUtils.hexToInt(s);
|
||||
assertEquals((int) i, HexUtils.FF_BYTE);
|
||||
final String testString = "ff";
|
||||
final int expectedInt = HexUtils.FF_BYTE;
|
||||
final Integer actualInt = HexUtils.hexToInt(testString);
|
||||
assertEquals(expectedInt, (int) actualInt);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -60,14 +59,11 @@ public class HexUtilsTest {
|
||||
*/
|
||||
@Test
|
||||
public void testSubarray() {
|
||||
byte[] b = {-85, -51, 18, 52};
|
||||
byte[] target = {-51, 18};
|
||||
|
||||
byte[] sub = HexUtils.subarray(b, 1, 2);
|
||||
|
||||
assertArrayEquals(sub, target);
|
||||
final byte[] b = {-85, -51, 18, 52};
|
||||
final byte[] expectedSubArray = {-51, 18};
|
||||
final byte[] actualSubArray = HexUtils.subarray(b, 1, 2);
|
||||
assertArrayEquals(expectedSubArray, actualSubArray);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
package hirs.utils;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.mockito.Mockito;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
||||
/**
|
||||
|
1
HIRS_Utils/src/test/java/hirs/utils/package-info.java
Normal file
1
HIRS_Utils/src/test/java/hirs/utils/package-info.java
Normal file
@ -0,0 +1 @@
|
||||
package hirs.utils;
|
@ -1,20 +1,20 @@
|
||||
package hirs.utils.tpm.eventlog;
|
||||
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static hirs.utils.tpm.eventlog.TCGEventLog.PCR_COUNT;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
@ -36,7 +36,6 @@ public class TCGEventLogTest {
|
||||
@BeforeAll
|
||||
public static final void setup() {
|
||||
LOGGER.debug("retrieving session factory");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -49,6 +48,7 @@ public class TCGEventLogTest {
|
||||
|
||||
/**
|
||||
* Tests the processing of a crypto agile event log.
|
||||
*
|
||||
* @throws IOException when processing the test fails
|
||||
* @throws NoSuchAlgorithmException if an unknown algorithm is encountered.
|
||||
* @throws CertificateException if a certificate fails to parse.
|
||||
@ -57,28 +57,33 @@ public class TCGEventLogTest {
|
||||
public final void testCryptoAgileTCGEventLog() throws IOException, CertificateException,
|
||||
NoSuchAlgorithmException {
|
||||
LOGGER.debug("Testing the parsing of a Crypto Agile formatted TCG Event Log");
|
||||
InputStream log, pcrs;
|
||||
|
||||
|
||||
try {
|
||||
// setup
|
||||
final InputStream log = this.getClass().getResourceAsStream(DEFAULT_EVENT_LOG);
|
||||
final InputStream pcrs = this.getClass().getResourceAsStream(DEFAULT_EXPECTED_PCRS);
|
||||
final byte[] rawLogBytes = IOUtils.toByteArray(log);
|
||||
final TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
|
||||
final String[] pcrFromLog = evlog.getExpectedPCRValues();
|
||||
final Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
|
||||
final String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
|
||||
|
||||
boolean testPass = true;
|
||||
log = this.getClass().getResourceAsStream(DEFAULT_EVENT_LOG);
|
||||
byte[] rawLogBytes = IOUtils.toByteArray(log);
|
||||
TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
|
||||
String[] pcrFromLog = evlog.getExpectedPCRValues();
|
||||
pcrs = this.getClass().getResourceAsStream(DEFAULT_EXPECTED_PCRS);
|
||||
Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
|
||||
String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
|
||||
|
||||
// Test 1 get all PCRs
|
||||
for (int i = 0; i < 24; i++) {
|
||||
for (int i = 0; i < PCR_COUNT; i++) {
|
||||
if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) {
|
||||
testPass = false;
|
||||
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR " + i);
|
||||
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR {}", i);
|
||||
}
|
||||
}
|
||||
assertTrue(testPass);
|
||||
|
||||
// Test 2 get an individual PCR
|
||||
String pcr3 = evlog.getExpectedPCRValue(3);
|
||||
assertThat(pcrFromLog[3], equalTo(pcr3));
|
||||
final int pcrIndex = 3;
|
||||
String pcr3 = evlog.getExpectedPCRValue(pcrIndex);
|
||||
assertThat(pcrFromLog[pcrIndex], equalTo(pcr3));
|
||||
|
||||
// Test 3 check the Algorithm String Identifier used in the log
|
||||
String algStr = evlog.getEventLogHashAlgorithm();
|
||||
@ -89,10 +94,14 @@ public class TCGEventLogTest {
|
||||
assertThat(TcgTpmtHa.TPM_ALG_SHA256, equalTo(id));
|
||||
|
||||
LOGGER.debug("OK. Parsing of a Crypto Agile Format Success");
|
||||
} catch (Throwable throwable) {
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the processing of a SHA1 formatted Event log.
|
||||
*
|
||||
* @throws IOException when processing the test fails
|
||||
* @throws NoSuchAlgorithmException if an unknown algorithm is encountered.
|
||||
* @throws CertificateException if a certificate fails to parse.
|
||||
@ -101,21 +110,24 @@ public class TCGEventLogTest {
|
||||
public final void testSHA1TCGEventLog() throws IOException, CertificateException,
|
||||
NoSuchAlgorithmException {
|
||||
LOGGER.debug("Testing the parsing of a SHA1 formated TCG Event Log");
|
||||
InputStream log, pcrs;
|
||||
|
||||
try {
|
||||
// setup
|
||||
final InputStream log = this.getClass().getResourceAsStream(SHA1_EVENT_LOG);
|
||||
final InputStream pcrs = this.getClass().getResourceAsStream(SHA1_EXPECTED_PCRS);
|
||||
final byte[] rawLogBytes = IOUtils.toByteArray(log);
|
||||
final TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
|
||||
final String[] pcrFromLog = evlog.getExpectedPCRValues();
|
||||
final Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
|
||||
final String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
|
||||
|
||||
boolean testPass = true;
|
||||
log = this.getClass().getResourceAsStream(SHA1_EVENT_LOG);
|
||||
byte[] rawLogBytes = IOUtils.toByteArray(log);
|
||||
TCGEventLog evlog = new TCGEventLog(rawLogBytes, false, false, false);
|
||||
String[] pcrFromLog = evlog.getExpectedPCRValues();
|
||||
pcrs = this.getClass().getResourceAsStream(SHA1_EXPECTED_PCRS);
|
||||
Object[] pcrObj = IOUtils.readLines(pcrs, "UTF-8").toArray();
|
||||
String[] pcrTxt = Arrays.copyOf(pcrObj, pcrObj.length, String[].class);
|
||||
|
||||
// Test 1 get all PCRs
|
||||
for (int i = 0; i < 24; i++) {
|
||||
for (int i = 0; i < PCR_COUNT; i++) {
|
||||
if (pcrFromLog[i].compareToIgnoreCase(pcrTxt[i]) != 0) {
|
||||
testPass = false;
|
||||
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR " + i);
|
||||
LOGGER.error("\ntestTCGEventLogProcessorParser error with PCR {}", i);
|
||||
}
|
||||
}
|
||||
assertTrue(testPass);
|
||||
@ -133,6 +145,8 @@ public class TCGEventLogTest {
|
||||
assertThat(TcgTpmtHa.TPM_ALG_SHA1, equalTo(id));
|
||||
|
||||
LOGGER.debug("OK. Parsing of a SHA1 formatted TCG Event Log Success");
|
||||
} catch (Throwable throwable) {
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
package hirs.utils.tpm.eventlog;
|
16
build.gradle
16
build.gradle
@ -1,5 +1,4 @@
|
||||
import java.util.concurrent.TimeUnit
|
||||
import org.gradle.api.tasks.Copy
|
||||
|
||||
plugins {
|
||||
// Apply the application plugin to add support for building a CLI application in Java.
|
||||
@ -8,7 +7,7 @@ plugins {
|
||||
}
|
||||
|
||||
// Global checkstyle file
|
||||
ext.checkstyleConfigFile = new File(rootDir, "/config/checkstyle/sun_checks.xml")
|
||||
ext.checkstyleConfigFile = new File(rootDir, "/config/checkstyle/sun_checks.xml")
|
||||
|
||||
subprojects {
|
||||
apply plugin: "com.github.spotbugs"
|
||||
@ -19,13 +18,12 @@ subprojects {
|
||||
|
||||
tasks.withType(com.github.spotbugs.snom.SpotBugsTask) {
|
||||
reports {
|
||||
html {
|
||||
enabled = true
|
||||
}
|
||||
html.required = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
repositories {
|
||||
// Use Maven Central for resolving dependencies.
|
||||
@ -36,10 +34,10 @@ dependencies {
|
||||
def projectVersion = rootProject.file('VERSION').text.trim()
|
||||
|
||||
def buildTime = { ->
|
||||
Date latestdate = new Date();
|
||||
def time = latestdate.getTime();
|
||||
long seconds = TimeUnit.MILLISECONDS.toSeconds(time);
|
||||
return seconds;
|
||||
Date latestdate = new Date()
|
||||
def time = latestdate.getTime()
|
||||
long seconds = TimeUnit.MILLISECONDS.toSeconds(time)
|
||||
return seconds
|
||||
}
|
||||
|
||||
def gitHash = { ->
|
||||
|
Loading…
Reference in New Issue
Block a user