mirror of
https://github.com/nsacyber/HIRS.git
synced 2024-12-19 21:17:59 +00:00
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:
parent
2dcdc15c54
commit
b80d7221c1
@ -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,9 +72,10 @@ public final class HexUtils {
|
||||
|
||||
/**
|
||||
* 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 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
|
||||
*/
|
||||
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.
|
||||
* @param in byte array to reverse
|
||||
*
|
||||
* @param in byte array to reverse
|
||||
* @return reversed byte array
|
||||
*/
|
||||
public static byte[] leReverseByte(final byte[] in) {
|
||||
public static byte[] leReverseByte(final byte[] in) {
|
||||
byte[] finished = new byte[in.length];
|
||||
for (int i = 0; i < finished.length; i++) {
|
||||
finished[i] = in[(in.length - 1) - i];
|
||||
}
|
||||
return finished;
|
||||
for (int i = 0; i < finished.length; i++) {
|
||||
finished[i] = in[(in.length - 1) - i];
|
||||
}
|
||||
return finished;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
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.
|
||||
* @param bytes byte array to convert
|
||||
*
|
||||
* @param bytes byte array to convert
|
||||
* @return long representation of the 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();
|
||||
}
|
||||
}
|
||||
|
@ -21,16 +21,17 @@ 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
|
||||
* mapped in the associated JSON file.
|
||||
* 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
|
||||
* @return a JSON object
|
||||
*/
|
||||
@ -44,9 +45,9 @@ public final class JsonUtils {
|
||||
* mapped in the associated JSON file.
|
||||
* 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 charset the character set to use
|
||||
* @param charset the character set to use
|
||||
* @return a JSON object
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public static JsonObject getJsonObject(final Path jsonPath, final Charset charset) {
|
||||
@ -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());
|
||||
@ -106,7 +107,7 @@ public final class JsonUtils {
|
||||
* Default {@link java.nio.charset.Charset} is UTF 8
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @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 charset the character set to use
|
||||
* @param elementName the specific object to pull from the file
|
||||
* @param charset the character set to use
|
||||
* @return a JSON object
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public static JsonObject getJsonObject(final String jsonFilename, final Charset charset) {
|
||||
|
@ -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,8 +124,9 @@ 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
|
||||
* @param refModel ASN1UTF8String, likely from a ComponentIdentifier
|
||||
* @return ASN1UTF8String with the discovered device name, or the original model value.
|
||||
*/
|
||||
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.
|
||||
* 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
|
||||
* @param refModel String, likely from a ComponentResult
|
||||
* @return String with the discovered device name, or the original model value.
|
||||
*/
|
||||
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.
|
||||
* 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"
|
||||
* Subclass: "08"
|
||||
* Programming Interface: "02"
|
||||
* Example "010802":
|
||||
* Class: "01"
|
||||
* Subclass: "08"
|
||||
* Programming Interface: "02"
|
||||
* @return List<String> 3-element list with the class code
|
||||
* 1st element: human-readable description of Class
|
||||
* 2nd element: human-readable description of Subclass
|
||||
* 3rd element: human-readable description of Programming Interface
|
||||
* 1st element: human-readable description of Class
|
||||
* 2nd element: human-readable description of Subclass
|
||||
* 3rd element: human-readable description of Programming Interface
|
||||
*/
|
||||
public static List<String> translateDeviceClass(final String refClassCode) {
|
||||
List<String> translatedClassCode = new ArrayList<>();
|
||||
|
||||
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 final boolean validFileSize = 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.
|
||||
@ -43,7 +59,7 @@ public class SwidResource {
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public SwidResource(final File file, final DigestAlgorithm digest) {
|
||||
@ -81,4 +97,4 @@ public class SwidResource {
|
||||
this.digest = digest;
|
||||
// tpmWhiteList = new TpmWhiteListBaseline(this.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
@ -63,4 +62,4 @@ public enum DigestAlgorithm {
|
||||
throw new IllegalArgumentException(String.format("No constant with text \"%s\" found",
|
||||
standardAlgorithmName));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
}
|
||||
}
|
||||
|
@ -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,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
|
||||
* 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,
|
||||
* 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 encodedPublicKey the encoded public key
|
||||
* @param encodedPublicKey the encoded public key
|
||||
* @return true if the signature element is validated, false otherwise
|
||||
*/
|
||||
@SuppressWarnings("magicnumber")
|
||||
@ -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,26 +224,27 @@ 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,
|
||||
signingCert.getPublicKey().getEncoded());
|
||||
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,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 sha the algorithm to use
|
||||
* @param sha the algorithm to use
|
||||
* @return String digest
|
||||
*/
|
||||
private String getHashValue(final String filepath, final String sha) {
|
||||
@ -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;
|
||||
@ -415,11 +376,11 @@ public class ReferenceManifestValidator {
|
||||
* results are logged.
|
||||
*
|
||||
* @param signature the signature that failed to validate
|
||||
* @param context the context used for validation
|
||||
* @param context the context used for validation
|
||||
* @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,14 +452,15 @@ 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 cert the signed certificate
|
||||
* @param issuer the signing certificate
|
||||
* @return true if they match, false if not
|
||||
* @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.
|
||||
* @param cert the signed certificate
|
||||
*
|
||||
* @param cert the signed certificate
|
||||
* @param issuer the signing certificate
|
||||
* @return true if they match, false if not
|
||||
* @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.
|
||||
* @param cert the signed certificate
|
||||
*
|
||||
* @param cert the signed certificate
|
||||
* @param signer the signing certificate
|
||||
* @return true if they 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.
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,24 +10,17 @@ import javax.xml.namespace.QName;
|
||||
*/
|
||||
public 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,18 +69,15 @@ 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 +
|
||||
@ -116,8 +106,6 @@ public class SwidTagConstants {
|
||||
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() {
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +109,10 @@
|
||||
|
||||
<!-- Checks for Naming Conventions. -->
|
||||
<!-- 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="LocalVariableName"/>
|
||||
<module name="MemberName"/>
|
||||
@ -163,7 +166,9 @@
|
||||
<!-- See https://checkstyle.org/checks/coding/index.html -->
|
||||
<module name="EmptyStatement"/>
|
||||
<module name="EqualsHashCode"/>
|
||||
<module name="HiddenField"/>
|
||||
<module name="HiddenField">
|
||||
<property name="tokens" value="VARIABLE_DEF"/>
|
||||
</module>
|
||||
<module name="IllegalInstantiation"/>
|
||||
<module name="InnerAssignment"/>
|
||||
<module name="MagicNumber"/>
|
||||
|
Loading…
Reference in New Issue
Block a user