mirror of
https://github.com/nsacyber/HIRS.git
synced 2025-01-18 02:39:56 +00:00
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:
parent
7bb9d8698d
commit
962ca45bb7
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user