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 {
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,9 +40,6 @@ 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
@ -52,7 +51,7 @@ public class BannerConfiguration {
if (!Files.exists(BANNER_PROPERTIES_PATH)) {
log.info(String.format(
"No file found at %s. Banner will not display.",
BANNER_PROPERTIES_PATH.toString()
BANNER_PROPERTIES_PATH
));
return;
}
@ -69,8 +68,8 @@ public class BannerConfiguration {
/**
* This method applies any dynamically configuration found in the properties file,
* if it exists.
* @param bannerProps
* @return the banner level for the web site.
*
* @param bannerProps banner props
*/
private void setBannerProperties(final Properties bannerProps) {
@ -103,10 +102,7 @@ public class BannerConfiguration {
* @return if the banner was set.
*/
public Boolean getHasBanner() {
if (!bannerColor.isEmpty() || !bannerString.isEmpty()) {
return true;
}
return false;
return !bannerColor.isEmpty() || !bannerString.isEmpty();
}
/**

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -50,8 +50,7 @@ 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) {

View File

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

View File

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

View File

@ -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_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() {
}
}

View File

@ -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"/>