Modify ACA RIM validation to search for a signing cert if the base RIM does not have an embedded cert. Validate the ca chain of the found signing cert.

This commit is contained in:
chubtub 2021-10-21 18:45:46 -04:00
parent 7bb9d8698d
commit 962ca45bb7
3 changed files with 193 additions and 152 deletions

View File

@ -46,15 +46,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Service;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -95,7 +92,8 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
/**
* Constructor to set just the CertificateManager, so that cert chain validating
* methods can be called from outside classes.
* @param certificateManager the cert manager
*
* @param certificateManager the cert manager
*/
public SupplyChainValidationServiceImpl(final CertificateManager certificateManager) {
this.certificateManager = certificateManager;
@ -135,6 +133,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
/**
* Allows other service access to the policy information.
*
* @return supply chain policy
*/
public SupplyChainPolicy getPolicy() {
@ -243,7 +242,7 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
} else {
validations.add(new SupplyChainValidation(platformType,
AppraisalStatus.Status.FAIL, new ArrayList<>(pcs), pcErrorMessage));
}
}
}
}
@ -425,33 +424,20 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
// verify signatures
ReferenceManifestValidator referenceManifestValidator =
new ReferenceManifestValidator(
new ByteArrayInputStream(baseReferenceManifest.getRimBytes()));
new ReferenceManifestValidator();
referenceManifestValidator.setRim(baseReferenceManifest);
for (SwidResource swidRes : resources) {
supportReferenceManifest = SupportReferenceManifest.select(referenceManifestManager)
.byHexDecHash(swidRes.getHashValue()).getRIM();
if (supportReferenceManifest != null
&& swidRes.getName().equals(supportReferenceManifest.getFileName())) {
referenceManifestValidator.validateSupportRimHash(
supportReferenceManifest.getRimBytes(), swidRes.getHashValue());
} else {
supportReferenceManifest = null;
}
}
//Validate signing cert
Set<CertificateAuthorityCredential> allCerts =
CertificateAuthorityCredential.select(certificateManager).getCertificates();
CertificateAuthorityCredential signingCert = null;
for (CertificateAuthorityCredential cert : allCerts) {
if (Arrays.equals(cert.getEncodedPublicKey(),
referenceManifestValidator.getPublicKey().getEncoded())) {
signingCert = cert;
KeyStore keyStore = getCaChain(signingCert);
signingCert = cert;
KeyStore keyStore = getCaChain(signingCert);
if (referenceManifestValidator.validateXmlSignature(signingCert)) {
try {
X509Certificate x509Cert = signingCert.getX509Certificate();
if (!SupplyChainCredentialValidator.verifyCertificate(x509Cert, keyStore)) {
if (!SupplyChainCredentialValidator.verifyCertificate(
signingCert.getX509Certificate(), keyStore)) {
passed = false;
fwStatus = new AppraisalStatus(FAIL,
"Firmware validation failed: invalid certificate path.");
@ -467,6 +453,18 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe
}
}
for (SwidResource swidRes : resources) {
supportReferenceManifest = SupportReferenceManifest.select(referenceManifestManager)
.byHexDecHash(swidRes.getHashValue()).getRIM();
if (supportReferenceManifest != null
&& swidRes.getName().equals(supportReferenceManifest.getFileName())) {
referenceManifestValidator.validateSupportRimHash(
supportReferenceManifest.getRimBytes(), swidRes.getHashValue());
} else {
supportReferenceManifest = null;
}
}
if (signingCert == null) {
passed = false;
fwStatus = new AppraisalStatus(FAIL,

View File

@ -31,12 +31,10 @@ import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@ -68,9 +66,9 @@ public class ReferenceManifestDetailsPageController
* Constructor providing the Page's display and routing specification.
*
* @param referenceManifestManager the reference manifest manager.
* @param referenceDigestManager the reference digest manager.
* @param referenceEventManager the reference event manager.
* @param certificateManager the certificate manager.
* @param referenceDigestManager the reference digest manager.
* @param referenceEventManager the reference event manager.
* @param certificateManager the certificate manager.
*/
@Autowired
public ReferenceManifestDetailsPageController(
@ -144,19 +142,19 @@ public class ReferenceManifestDetailsPageController
*
* @param uuid database reference for the requested RIM.
* @param referenceManifestManager the reference manifest manager.
* @param referenceDigestManager the reference digest manager.
* @param referenceEventManager the reference event manager.
* @param certificateManager the certificate manager.
* @param referenceDigestManager the reference digest manager.
* @param referenceEventManager the reference event manager.
* @param certificateManager the certificate manager.
* @return mapping of the RIM information from the database.
* @throws java.io.IOException error for reading file bytes.
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
* @throws CertificateException if a certificate doesn't parse.
*/
public static HashMap<String, Object> getRimDetailInfo(final UUID uuid,
final ReferenceManifestManager referenceManifestManager,
final ReferenceDigestManager referenceDigestManager,
final ReferenceEventManager referenceEventManager,
final CertificateManager certificateManager) throws IOException,
final ReferenceManifestManager referenceManifestManager,
final ReferenceDigestManager referenceDigestManager,
final ReferenceEventManager referenceEventManager,
final CertificateManager certificateManager) throws IOException,
CertificateException, NoSuchAlgorithmException {
HashMap<String, Object> data = new HashMap<>();
@ -189,9 +187,9 @@ public class ReferenceManifestDetailsPageController
* This method takes the place of an entire class for a string builder.
* Gathers all information and returns it for displays.
*
* @param baseRim established ReferenceManifest Type.
* @param baseRim established ReferenceManifest Type.
* @param referenceManifestManager the reference manifest manager.
* @param certificateManager the certificate manager.
* @param certificateManager the certificate manager.
* @return mapping of the RIM information from the database.
* @throws java.io.IOException error for reading file bytes.
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.
@ -284,6 +282,7 @@ public class ReferenceManifestDetailsPageController
}
// going to have to pull the filename and grab that from the DB
// to get the id to make the link
RIM_VALIDATOR.setRim(baseRim);
for (SwidResource swidRes : resources) {
if (support != null && swidRes.getHashValue()
.equalsIgnoreCase(support.getHexDecHash())) {
@ -305,29 +304,25 @@ public class ReferenceManifestDetailsPageController
data.put("pcrList", support.getExpectedPCRList());
}
RIM_VALIDATOR.validateXmlSignature(new ByteArrayInputStream(baseRim.getRimBytes()));
// RIM_VALIDATOR.validateXmlSignature(new ByteArrayInputStream(baseRim.getRimBytes()));
Set<CertificateAuthorityCredential> certificates =
CertificateAuthorityCredential.select(certificateManager)
.getCertificates();
//Report invalid signature unless RIM_VALIDATOR validates it and cert path is valid
data.put("signatureValid", false);
if (RIM_VALIDATOR.isSignatureValid()) {
for (CertificateAuthorityCredential cert : certificates) {
if (Arrays.equals(cert.getEncodedPublicKey(),
RIM_VALIDATOR.getPublicKey().getEncoded())) {
SupplyChainValidationServiceImpl scvsImpl =
new SupplyChainValidationServiceImpl(certificateManager);
KeyStore keystore = scvsImpl.getCaChain(cert);
X509Certificate signingCert = cert.getX509Certificate();
try {
if (SupplyChainCredentialValidator.verifyCertificate(signingCert,
keystore)) {
data.replace("signatureValid", true);
}
} catch (SupplyChainValidatorException e) {
LOGGER.error("Error verifying cert chain: " + e.getMessage());
for (CertificateAuthorityCredential cert : certificates) {
SupplyChainValidationServiceImpl scvsImpl =
new SupplyChainValidationServiceImpl(certificateManager);
KeyStore keystore = scvsImpl.getCaChain(cert);
if (RIM_VALIDATOR.validateXmlSignature(cert)) {
try {
if (SupplyChainCredentialValidator.verifyCertificate(
cert.getX509Certificate(), keystore)) {
data.replace("signatureValid", true);
break;
}
break;
} catch (SupplyChainValidatorException e) {
LOGGER.error("Error verifying cert chain: " + e.getMessage());
}
}
}
@ -349,7 +344,7 @@ public class ReferenceManifestDetailsPageController
* This method takes the place of an entire class for a string builder.
* Gathers all information and returns it for displays.
*
* @param support established ReferenceManifest Type.
* @param support established ReferenceManifest Type.
* @param referenceManifestManager the reference manifest manager.
* @return mapping of the RIM information from the database.
* @throws java.io.IOException error for reading file bytes.
@ -414,8 +409,8 @@ public class ReferenceManifestDetailsPageController
digestMap.put(tpe.getEventDigestStr(), tpe);
if (!support.isSwidSupplemental()
&& !tpe.eventCompare(
measurementsProcess.getEventByNumber(
tpe.getEventNumber()))) {
measurementsProcess.getEventByNumber(
tpe.getEventNumber()))) {
tpe.setError(true);
}
tpmPcrEvents.add(tpe);
@ -509,10 +504,10 @@ public class ReferenceManifestDetailsPageController
* This method takes the place of an entire class for a string builder.
* Gathers all information and returns it for displays.
*
* @param measurements established ReferenceManifest Type.
* @param measurements established ReferenceManifest Type.
* @param referenceManifestManager the reference manifest manager.
* @param referenceDigestManager the reference digest manager.
* @param referenceEventManager the reference event manager.
* @param referenceDigestManager the reference digest manager.
* @param referenceEventManager the reference event manager.
* @return mapping of the RIM information from the database.
* @throws java.io.IOException error for reading file bytes.
* @throws NoSuchAlgorithmException If an unknown Algorithm is encountered.

View File

@ -1,7 +1,11 @@
package hirs.utils;
import hirs.data.persist.ReferenceManifest;
import hirs.data.persist.certificate.CertificateAuthorityCredential;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
@ -23,7 +27,6 @@ import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyValue;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
@ -34,14 +37,17 @@ import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.Key;
import java.security.KeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Iterator;
@ -52,7 +58,7 @@ import java.util.Iterator;
*/
public class ReferenceManifestValidator {
private static final String SIGNATURE_ALGORITHM_RSA_SHA256 =
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
private static final String SCHEMA_PACKAGE = "hirs.utils.xjc";
private static final String SCHEMA_URL = "swid_schema.xsd";
private static final String SCHEMA_LANGUAGE = XMLConstants.W3C_XML_SCHEMA_NS_URI;
@ -63,12 +69,29 @@ public class ReferenceManifestValidator {
private static final int RADIX = 16;
private static final Logger LOGGER = LogManager.getLogger(ReferenceManifestValidator.class);
private Document rim;
private Unmarshaller unmarshaller;
private PublicKey publicKey;
private Schema schema;
private String subjectKeyIdentifier;
private boolean signatureValid, supportRimValid;
/**
* Setter for the RIM to be validated. The ReferenceManifest object is converted into a
* Document for processing.
*
* @param rim ReferenceManifest object
*/
public void setRim(ReferenceManifest rim) {
try {
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(
new ByteArrayInputStream(rim.getRimBytes()))));
this.rim = doc;
} catch (IOException e) {
LOGGER.error("Error while unmarshalling rim bytes: " + e.getMessage());
}
}
/**
* Getter for signatureValid.
*
@ -98,6 +121,7 @@ public class ReferenceManifestValidator {
/**
* Getter for subjectKeyIdentifier.
*
* @return subjectKeyIdentifier
*/
public String getSubjectKeyIdentifier() {
@ -114,43 +138,16 @@ public class ReferenceManifestValidator {
.getClassLoader().getResourceAsStream(SCHEMA_URL);
SchemaFactory schemaFactory = SchemaFactory.newInstance(SCHEMA_LANGUAGE);
schema = schemaFactory.newSchema(new StreamSource(is));
rim = null;
signatureValid = false;
supportRimValid = false;
publicKey = null;
subjectKeyIdentifier = "";
subjectKeyIdentifier = "(not found)";
} catch (SAXException e) {
LOGGER.warn("Error setting schema for validation!");
}
}
/**
* This constructor is used for a quick signature check which bypasses the loading of
* the schema url into memory. As a result the full stream is not validated against the schema.
*
* @param input xml data byte array.
*/
public ReferenceManifestValidator(final InputStream input) {
try {
signatureValid = validateSignedXMLDocument(
removeXMLWhitespace(new StreamSource(input)));
} catch (IOException e) {
LOGGER.warn("Error during unmarshal: " + e.getMessage());
}
}
/**
* This method calculates the SHA256 hash of the input byte array and compares it against
* the value passed in.
*
* @param input byte array to hash.
* @param expected value to compare against.
*/
public void validateSupportRimHash(final byte[] input, final String expected) {
String calculatedHash = getHashValue(input, SHA256);
LOGGER.info("Calculated hash: " + calculatedHash + ", actual: " + expected);
supportRimValid = calculatedHash.equals(expected);
}
/**
* This method validates the xml signature in the stream and stores the
* result for public access.
@ -160,16 +157,67 @@ public class ReferenceManifestValidator {
public void validateXmlSignature(final InputStream input) {
try {
Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(input)));
signatureValid = validateSignedXMLDocument(doc);
//signatureValid = validateSignedXMLDocument(doc);
} catch (IOException e) {
LOGGER.warn("Error during unmarshal: " + e.getMessage());
}
}
public boolean validateXmlSignature(final CertificateAuthorityCredential cert) {
DOMValidateContext context = null;
try {
NodeList nodes = rim.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (nodes.getLength() == 0) {
LOGGER.error("Cannot validate RIM, signature element not found!");
return false;
}
NodeList certElement = rim.getElementsByTagName("X509Certificate");
if (certElement.getLength() > 0) {
X509Certificate embeddedCert = parseCertFromPEMString(
certElement.item(0).getTextContent());
subjectKeyIdentifier = getCertificateSubjectKeyIdentifier(embeddedCert);
if (Arrays.equals(embeddedCert.getPublicKey().getEncoded(),
cert.getEncodedPublicKey())) {
context = new DOMValidateContext(new X509KeySelector(), nodes.item(0));
}
} else {
subjectKeyIdentifier = getKeyName(rim);
if (subjectKeyIdentifier.equals(cert.getSubjectKeyIdString())) {
context = new DOMValidateContext(cert.getX509Certificate().getPublicKey(),
nodes.item(0));
}
}
if (context != null) {
publicKey = cert.getX509Certificate().getPublicKey();
return validateSignedXMLDocument(context);
}
} catch (CertificateException e) {
LOGGER.warn("Error parsing embedded certificate from RIM: " + e.getMessage());
} catch (IOException e) {
LOGGER.warn("Error while parsing certificate data: " + e.getMessage());
}
return false;
}
/**
* This method calculates the SHA256 hash of the input byte array and compares it against
* the value passed in.
*
* @param input byte array to hash.
* @param expected value to compare against.
*/
public void validateSupportRimHash(final byte[] input, final String expected) {
String calculatedHash = getHashValue(input, SHA256);
LOGGER.info("Calculated hash: " + calculatedHash + ", actual: " + expected);
supportRimValid = calculatedHash.equals(expected);
}
/**
* This method calculates the digest of a byte array based on the hashing algorithm passed in.
*
* @param input byte array.
* @param sha hash algorithm.
* @param sha hash algorithm.
* @return String digest.
*/
private String getHashValue(final byte[] input, final String sha) {
@ -181,7 +229,7 @@ public class ReferenceManifestValidator {
for (int i = 0; i < bytes.length; i++) {
sb.append(Integer.toString((bytes[i] & EIGHT_BIT_MASK)
+ LEFT_SHIFT, RADIX).substring(1));
+ LEFT_SHIFT, RADIX).substring(1));
}
resultString = sb.toString();
} catch (NoSuchAlgorithmException grex) {
@ -191,37 +239,18 @@ public class ReferenceManifestValidator {
return resultString;
}
/**
* This method validates a Document with a signature element.
*
* @param doc
*/
private boolean validateSignedXMLDocument(final Document doc) {
DOMValidateContext context;
boolean isValid = false;
private boolean validateSignedXMLDocument(final DOMValidateContext context) {
try {
NodeList nodes = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (nodes.getLength() == 0) {
throw new Exception("Signature element not found!");
}
X509KeySelector keySelector = new ReferenceManifestValidator.X509KeySelector();
context = new DOMValidateContext(keySelector, nodes.item(0));
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
XMLSignature signature = sigFactory.unmarshalXMLSignature(context);
isValid = signature.validate(context);
publicKey = keySelector.getPublicKey();
subjectKeyIdentifier = getKeyName(doc);
return signature.validate(context);
} catch (MarshalException e) {
LOGGER.warn("Error while unmarshalling XML signature: " + e.getMessage());
} catch (XMLSignatureException e) {
LOGGER.warn("Error while validating XML signature: " + e.getMessage());
} catch (KeySelectorException e) {
LOGGER.warn("Public key not found in XML signature: " + e.getMessage());
} catch (Exception e) {
LOGGER.warn(e.getMessage());
}
return isValid;
return false;
}
/**
@ -230,8 +259,6 @@ public class ReferenceManifestValidator {
* an XML signature.
*/
public static class X509KeySelector extends KeySelector {
private PublicKey publicKey;
/**
* This method selects a public key for validation.
* PKs are parsed preferentially from the following elements:
@ -240,10 +267,10 @@ public class ReferenceManifestValidator {
* 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 keyinfo object containing the cert.
* @param purpose purpose.
* @param algorithm algorithm.
* @param context XMLCryptoContext.
* @param context XMLCryptoContext.
* @return KeySelectorResult holding the PublicKey.
* @throws KeySelectorException exception.
*/
@ -251,7 +278,7 @@ public class ReferenceManifestValidator {
final KeySelector.Purpose purpose,
final AlgorithmMethod algorithm,
final XMLCryptoContext context)
throws KeySelectorException {
throws KeySelectorException {
Iterator keyinfoItr = keyinfo.getContent().iterator();
while (keyinfoItr.hasNext()) {
XMLStructure element = (XMLStructure) keyinfoItr.next();
@ -261,32 +288,22 @@ public class ReferenceManifestValidator {
while (dataItr.hasNext()) {
Object object = dataItr.next();
if (object instanceof X509Certificate) {
publicKey = ((X509Certificate) object).getPublicKey();
break;
final PublicKey publicKey = ((X509Certificate) object).getPublicKey();
if (areAlgorithmsEqual(algorithm.getAlgorithm(), publicKey.getAlgorithm())) {
return new ReferenceManifestValidator.X509KeySelector
.RIMKeySelectorResult(publicKey);
}
}
}
} else if (element instanceof KeyValue) {
try {
publicKey = ((KeyValue) element).getPublicKey();
} catch (KeyException e) {
LOGGER.warn("KeyException thrown while getting PK from KeyValue: "
+ e.getMessage());
}
}
}
if (areAlgorithmsEqual(algorithm.getAlgorithm(),
publicKey.getAlgorithm())) {
return new ReferenceManifestValidator.X509KeySelector
.RIMKeySelectorResult(publicKey);
}
throw new KeySelectorException("No key found!");
}
/**
* This method checks if two strings refer to the same algorithm.
*
* @param uri string 1
* @param uri string 1
* @param name string 2
* @return true if equal, false if not
*/
@ -294,19 +311,10 @@ public class ReferenceManifestValidator {
return uri.equals(SIGNATURE_ALGORITHM_RSA_SHA256) && name.equalsIgnoreCase("RSA");
}
/**
* Getter for the public key that is parsed in the select() method above.
*
* @return PublicKey encoded in the X509 cert.
*/
public PublicKey getPublicKey() {
return publicKey;
}
/**
* This internal class creates a KeySelectorResult from the public key.
*/
private static class RIMKeySelectorResult implements KeySelectorResult {
private class RIMKeySelectorResult implements KeySelectorResult {
private Key key;
RIMKeySelectorResult(final Key key) {
@ -319,6 +327,46 @@ public class ReferenceManifestValidator {
}
}
/**
* 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
* facilitate proper parsing.
*
* @param pemString the input string
* @return an X509Certificate created from the string
* @throws CertificateException if instantiating the CertificateFactory errors
*/
public X509Certificate parseCertFromPEMString(String pemString) throws CertificateException {
String CERTIFICATE_HEADER = "-----BEGIN CERTIFICATE-----";
String CERTIFICATE_FOOTER = "-----END CERTIFICATE-----";
try {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
InputStream inputStream = new ByteArrayInputStream((CERTIFICATE_HEADER
+ System.lineSeparator()
+ pemString
+ System.lineSeparator()
+ CERTIFICATE_FOOTER).getBytes());
return (X509Certificate) factory.generateCertificate(inputStream);
} catch (CertificateException e) {
throw e;
}
}
/**
* This method returns the subjectKeyIdentifier from a given X509Certificate.
* @param certificate the cert to pull the subjectKeyIdentifier from
* @return the String representation of the subjectKeyIdentifier
* @throws IOException
*/
private String getCertificateSubjectKeyIdentifier(X509Certificate certificate) throws IOException {
String decodedValue = null;
byte[] extension = certificate.getExtensionValue(Extension.subjectKeyIdentifier.getId());
if (extension != null && extension.length > 0) {
decodedValue = JcaX509ExtensionUtils.parseExtensionValue(extension).toString();
}
return decodedValue.substring(1);//Drop the # at the beginning of the string
}
/**
* This method parses the subject key identifier from the KeyName element of a signature.
*
@ -368,7 +416,7 @@ public class ReferenceManifestValidator {
TransformerFactory tf = TransformerFactory.newInstance();
Source identitySource = new StreamSource(
ReferenceManifestValidator.class.getClassLoader()
.getResourceAsStream(IDENTITY_TRANSFORM));
.getResourceAsStream(IDENTITY_TRANSFORM));
Document doc = null;
try {
Transformer transformer = tf.newTransformer(identitySource);