issue_844: Made updates using the checkstyle configuration to various files. Have also made some config changes to the checkstyle.xml file.

This commit is contained in:
TheSilentCoder 2024-10-10 16:43:47 -04:00
parent 2dcdc15c54
commit b80d7221c1
11 changed files with 417 additions and 417 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,24 +10,17 @@ import javax.xml.namespace.QName;
*/ */
public class SwidTagConstants { public class SwidTagConstants {
/** public static final String DEFAULT_KEYSTORE_FILE = "keystore.jks"; //"/opt/hirs/rimtool/keystore.jks";
* Default private constructor so checkstyles doesn't complain
*/
private SwidTagConstants() { }
public static final String DEFAULT_KEYSTORE_FILE = "keystore.jks";//"/opt/hirs/rimtool/keystore.jks";
public static final String DEFAULT_KEYSTORE_PASSWORD = "password"; public static final String DEFAULT_KEYSTORE_PASSWORD = "password";
public static final String DEFAULT_PRIVATE_KEY_ALIAS = "1"; public static final String DEFAULT_PRIVATE_KEY_ALIAS = "1";
public static final String DEFAULT_ATTRIBUTES_FILE = "/opt/hirs/rimtool/rim_fields.json"; public static final String DEFAULT_ATTRIBUTES_FILE = "/opt/hirs/rimtool/rim_fields.json";
public static final String DEFAULT_ENGLISH = "en"; public static final String DEFAULT_ENGLISH = "en";
public static final String SIGNATURE_ALGORITHM_RSA_SHA256 =
public static final String SIGNATURE_ALGORITHM_RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
public static final String SCHEMA_PACKAGE = "hirs.swid.xjc"; public static final String SCHEMA_PACKAGE = "hirs.swid.xjc";
public static final String SCHEMA_LANGUAGE = XMLConstants.W3C_XML_SCHEMA_NS_URI; public static final String SCHEMA_LANGUAGE = XMLConstants.W3C_XML_SCHEMA_NS_URI;
public static final String SCHEMA_URL = "swid_schema.xsd"; public static final String SCHEMA_URL = "swid_schema.xsd";
public static final String SWIDTAG_NAMESPACE = "http://standards.iso.org/iso/19770/-2/2015/schema.xsd"; public static final String SWIDTAG_NAMESPACE = "http://standards.iso.org/iso/19770/-2/2015/schema.xsd";
public static final String SOFTWARE_IDENTITY = "SoftwareIdentity"; public static final String SOFTWARE_IDENTITY = "SoftwareIdentity";
public static final String ENTITY = "Entity"; public static final String ENTITY = "Entity";
public static final String LINK = "Link"; public static final String LINK = "Link";
@ -76,18 +69,15 @@ public class SwidTagConstants {
public static final String SUPPORT_RIM_FORMAT_MISSING = "supportRIMFormat missing"; public static final String SUPPORT_RIM_FORMAT_MISSING = "supportRIMFormat missing";
public static final String SUPPORT_RIM_URI_GLOBAL = "supportRIMURIGlobal"; public static final String SUPPORT_RIM_URI_GLOBAL = "supportRIMURIGlobal";
public static final String DATETIME = "dateTime"; public static final String DATETIME = "dateTime";
public static final String NIST_NS = "http://csrc.nist.gov/ns/swid/2015-extensions/1.0"; public static final String NIST_NS = "http://csrc.nist.gov/ns/swid/2015-extensions/1.0";
public static final String TCG_NS = "https://trustedcomputinggroup.org/wp-content/uploads/TCG_RIM_Model"; public static final String TCG_NS = "https://trustedcomputinggroup.org/wp-content/uploads/TCG_RIM_Model";
public static final String RFC3852_NS = "https://www.ietf.org/rfc/rfc3852.txt"; public static final String RFC3852_NS = "https://www.ietf.org/rfc/rfc3852.txt";
public static final String RFC3339_NS = "https://www.ietf.org/rfc/rfc3339.txt"; public static final String RFC3339_NS = "https://www.ietf.org/rfc/rfc3339.txt";
public static final String N8060_PFX = "n8060"; public static final String N8060_PFX = "n8060";
public static final String RIM_PFX = "rim"; public static final String RIM_PFX = "rim";
public static final String FX_SEPARATOR = ":"; public static final String FX_SEPARATOR = ":";
public static final String RFC3852_PFX = "rcf3852"; public static final String RFC3852_PFX = "rcf3852";
public static final String RFC3339_PFX = "rcf3339"; public static final String RFC3339_PFX = "rcf3339";
public static final String _COLLOQUIAL_VERSION_STR = N8060_PFX + FX_SEPARATOR + public static final String _COLLOQUIAL_VERSION_STR = N8060_PFX + FX_SEPARATOR +
COLLOQUIAL_VERSION; COLLOQUIAL_VERSION;
public static final String _PRODUCT_STR = N8060_PFX + FX_SEPARATOR + public static final String _PRODUCT_STR = N8060_PFX + FX_SEPARATOR +
@ -116,8 +106,6 @@ public class SwidTagConstants {
PC_URI_LOCAL; PC_URI_LOCAL;
public static final String _PC_URI_GLOBAL_STR = RIM_PFX + FX_SEPARATOR + public static final String _PC_URI_GLOBAL_STR = RIM_PFX + FX_SEPARATOR +
PC_URI_GLOBAL; PC_URI_GLOBAL;
public static final QName _SHA256_HASH = new QName( public static final QName _SHA256_HASH = new QName(
"http://www.w3.org/2001/04/xmlenc#sha256", HASH, "SHA256"); "http://www.w3.org/2001/04/xmlenc#sha256", HASH, "SHA256");
public static final QName _COLLOQUIAL_VERSION = new QName( public static final QName _COLLOQUIAL_VERSION = new QName(
@ -168,6 +156,11 @@ public class SwidTagConstants {
NIST_NS, "envVarSuffix", N8060_PFX); NIST_NS, "envVarSuffix", N8060_PFX);
public static final QName _N8060_PATHSEPARATOR = new QName( public static final QName _N8060_PATHSEPARATOR = new QName(
NIST_NS, "pathSeparator", N8060_PFX); NIST_NS, "pathSeparator", N8060_PFX);
public static final String CA_ISSUERS = "1.3.6.1.5.5.7.48.2"; public static final String CA_ISSUERS = "1.3.6.1.5.5.7.48.2";
/**
* Default private constructor so checkstyles doesn't complain.
*/
private SwidTagConstants() {
}
} }

View File

@ -109,7 +109,10 @@
<!-- Checks for Naming Conventions. --> <!-- Checks for Naming Conventions. -->
<!-- See https://checkstyle.org/checks/naming/index.html --> <!-- See https://checkstyle.org/checks/naming/index.html -->
<module name="ConstantName"/> <module name="ConstantName">
<property name="format"
value="[A-Z_][A-Z0-9]*(_[A-Z0-9]+)*$"/>
</module>
<module name="LocalFinalVariableName"/> <module name="LocalFinalVariableName"/>
<module name="LocalVariableName"/> <module name="LocalVariableName"/>
<module name="MemberName"/> <module name="MemberName"/>
@ -163,7 +166,9 @@
<!-- See https://checkstyle.org/checks/coding/index.html --> <!-- See https://checkstyle.org/checks/coding/index.html -->
<module name="EmptyStatement"/> <module name="EmptyStatement"/>
<module name="EqualsHashCode"/> <module name="EqualsHashCode"/>
<module name="HiddenField"/> <module name="HiddenField">
<property name="tokens" value="VARIABLE_DEF"/>
</module>
<module name="IllegalInstantiation"/> <module name="IllegalInstantiation"/>
<module name="InnerAssignment"/> <module name="InnerAssignment"/>
<module name="MagicNumber"/> <module name="MagicNumber"/>