diff --git a/HIRS_AttestationCA/src/main/java/hirs/attestationca/service/SupplyChainValidationServiceImpl.java b/HIRS_AttestationCA/src/main/java/hirs/attestationca/service/SupplyChainValidationServiceImpl.java index d9870e98..6877a824 100644 --- a/HIRS_AttestationCA/src/main/java/hirs/attestationca/service/SupplyChainValidationServiceImpl.java +++ b/HIRS_AttestationCA/src/main/java/hirs/attestationca/service/SupplyChainValidationServiceImpl.java @@ -1,5 +1,6 @@ package hirs.attestationca.service; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.KeyStore; import java.security.KeyStoreException; @@ -9,11 +10,13 @@ import java.security.cert.CertificateException; import hirs.data.persist.BaseReferenceManifest; import hirs.data.persist.EventLogMeasurements; import hirs.data.persist.SupportReferenceManifest; +import hirs.data.persist.SwidResource; import hirs.data.persist.TPMMeasurementRecord; import hirs.data.persist.PCRPolicy; import hirs.data.persist.ArchivableEntity; import hirs.tpm.eventlog.TCGEventLog; import hirs.tpm.eventlog.TpmPcrEvent; +import hirs.utils.ReferenceManifestValidator; import hirs.validation.SupplyChainCredentialValidator; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -351,6 +354,8 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe .byManufacturer(manufacturer).getRIM(); supportReferenceManifest = SupportReferenceManifest.select(referenceManifestManager) .byManufacturer(manufacturer).getRIM(); + List resources = + ((BaseReferenceManifest) baseReferenceManifest).parseResource(); measurement = EventLogMeasurements.select(referenceManifestManager) .byManufacturer(manufacturer).includeArchived().getRIM(); @@ -371,97 +376,126 @@ public class SupplyChainValidationServiceImpl implements SupplyChainValidationSe if (passed) { fwStatus = new AppraisalStatus(PASS, SupplyChainCredentialValidator.FIRMWARE_VALID); - TCGEventLog logProcessor; - try { - logProcessor = new TCGEventLog(supportReferenceManifest.getRimBytes()); - baseline = logProcessor.getExpectedPCRValues(); - } catch (CertificateException cEx) { - LOGGER.error(cEx); - } catch (NoSuchAlgorithmException noSaEx) { - LOGGER.error(noSaEx); - } catch (IOException ioEx) { - LOGGER.error(ioEx); + + // verify signatures + ReferenceManifestValidator referenceManifestValidator = + new ReferenceManifestValidator( + new ByteArrayInputStream(baseReferenceManifest.getRimBytes())); + + for (SwidResource swidRes : resources) { + if (swidRes.getName().equals(supportReferenceManifest.getFileName())) { + referenceManifestValidator.validateSupportRimHash( + supportReferenceManifest.getRimBytes(), swidRes.getHashValue()); + } } - // part 1 of firmware validation check: PCR baseline match - pcrPolicy.setBaselinePcrs(baseline); + if (!referenceManifestValidator.isSignatureValid()) { + passed = false; + fwStatus = new AppraisalStatus(FAIL, + "Firmware validation failed: Signature validation " + + "failed for Base RIM."); + } - if (baseline.length > 0) { - String pcrContent = ""; - pcrContent = new String(device.getDeviceInfo().getTPMInfo().getPcrValues()); + if (passed && !referenceManifestValidator.isSupportRimValid()) { + passed = false; + fwStatus = new AppraisalStatus(FAIL, + "Firmware validation failed: Hash validation " + + "failed for Support RIM."); + } - if (pcrContent.isEmpty()) { - fwStatus = new AppraisalStatus(FAIL, - "Firmware validation failed: Client did not " - + "provide pcr values."); - LOGGER.warn(String.format( - "Firmware validation failed: Client (%s) did not " - + "provide pcr values.", device.getName())); - } else { - // we have a full set of PCR values - int algorithmLength = baseline[0].length(); - String[] storedPcrs = buildStoredPcrs(pcrContent, algorithmLength); + if (passed) { + TCGEventLog logProcessor; + try { + logProcessor = new TCGEventLog(supportReferenceManifest.getRimBytes()); + baseline = logProcessor.getExpectedPCRValues(); + } catch (CertificateException cEx) { + LOGGER.error(cEx); + } catch (NoSuchAlgorithmException noSaEx) { + LOGGER.error(noSaEx); + } catch (IOException ioEx) { + LOGGER.error(ioEx); + } - if (storedPcrs[0].isEmpty()) { - // validation fail + // part 1 of firmware validation check: PCR baseline match + pcrPolicy.setBaselinePcrs(baseline); + + if (baseline.length > 0) { + String pcrContent = ""; + pcrContent = new String(device.getDeviceInfo().getTPMInfo().getPcrValues()); + + if (pcrContent.isEmpty()) { fwStatus = new AppraisalStatus(FAIL, - "Firmware validation failed: " - + "Client provided PCR " - + "values are not the same algorithm " - + "as associated RIM."); + "Firmware validation failed: Client did not " + + "provide pcr values."); + LOGGER.warn(String.format( + "Firmware validation failed: Client (%s) did not " + + "provide pcr values.", device.getName())); } else { - StringBuilder sb = pcrPolicy.validatePcrs(storedPcrs); - if (sb.length() > 0) { - level = Level.ERROR; - fwStatus = new AppraisalStatus(FAIL, sb.toString()); + // we have a full set of PCR values + int algorithmLength = baseline[0].length(); + String[] storedPcrs = buildStoredPcrs(pcrContent, algorithmLength); + + if (storedPcrs[0].isEmpty()) { + // validation fail + fwStatus = new AppraisalStatus(FAIL, + "Firmware validation failed: " + + "Client provided PCR " + + "values are not the same algorithm " + + "as associated RIM."); } else { - level = Level.INFO; - } - } - // part 2 of firmware validation check: bios measurements - // vs baseline tcg event log - // find the measurement - TCGEventLog tcgEventLog; - TCGEventLog tcgMeasurementLog; - LinkedList tpmPcrEvents = new LinkedList<>(); - try { - if (measurement.getPlatformManufacturer().equals(manufacturer)) { - tcgMeasurementLog = new TCGEventLog(measurement.getRimBytes()); - tcgEventLog = new TCGEventLog( - supportReferenceManifest.getRimBytes()); - for (TpmPcrEvent tpe : tcgEventLog.getEventList()) { - if (!tpe.eventCompare( - tcgMeasurementLog.getEventByNumber( - tpe.getEventNumber()))) { - tpmPcrEvents.add(tpe); - } + StringBuilder sb = pcrPolicy.validatePcrs(storedPcrs); + if (sb.length() > 0) { + level = Level.ERROR; + fwStatus = new AppraisalStatus(FAIL, sb.toString()); + } else { + level = Level.INFO; } } - } catch (CertificateException cEx) { - LOGGER.error(cEx); - } catch (NoSuchAlgorithmException noSaEx) { - LOGGER.error(noSaEx); - } catch (IOException ioEx) { - LOGGER.error(ioEx); - } + // part 2 of firmware validation check: bios measurements + // vs baseline tcg event log + // find the measurement + TCGEventLog tcgEventLog; + TCGEventLog tcgMeasurementLog; + LinkedList tpmPcrEvents = new LinkedList<>(); + try { + if (measurement.getPlatformManufacturer().equals(manufacturer)) { + tcgMeasurementLog = new TCGEventLog(measurement.getRimBytes()); + tcgEventLog = new TCGEventLog( + supportReferenceManifest.getRimBytes()); + for (TpmPcrEvent tpe : tcgEventLog.getEventList()) { + if (!tpe.eventCompare( + tcgMeasurementLog.getEventByNumber( + tpe.getEventNumber()))) { + tpmPcrEvents.add(tpe); + } + } + } + } catch (CertificateException cEx) { + LOGGER.error(cEx); + } catch (NoSuchAlgorithmException noSaEx) { + LOGGER.error(noSaEx); + } catch (IOException ioEx) { + LOGGER.error(ioEx); + } - if (!tpmPcrEvents.isEmpty()) { - StringBuilder sb = new StringBuilder(); - for (TpmPcrEvent tpe : tpmPcrEvents) { - sb.append(String.format("Event %s - %s%n", - tpe.getEventNumber(), - tpe.getEventTypeStr())); - } - if (fwStatus.getAppStatus().equals(FAIL)) { - fwStatus = new AppraisalStatus(FAIL, String.format("%s%n%s", - fwStatus.getMessage(), sb.toString())); - } else { - fwStatus = new AppraisalStatus(FAIL, sb.toString()); + if (!tpmPcrEvents.isEmpty()) { + StringBuilder sb = new StringBuilder(); + for (TpmPcrEvent tpe : tpmPcrEvents) { + sb.append(String.format("Event %s - %s%n", + tpe.getEventNumber(), + tpe.getEventTypeStr())); + } + if (fwStatus.getAppStatus().equals(FAIL)) { + fwStatus = new AppraisalStatus(FAIL, String.format("%s%n%s", + fwStatus.getMessage(), sb.toString())); + } else { + fwStatus = new AppraisalStatus(FAIL, sb.toString()); + } } } + } else { + fwStatus = new AppraisalStatus(FAIL, "The RIM baseline could not be found."); } - } else { - fwStatus = new AppraisalStatus(FAIL, "The RIM baseline could not be found."); } } else { fwStatus = new AppraisalStatus(FAIL, String.format("Firmware Validation failed: " diff --git a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java index 19e0df39..508df472 100644 --- a/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java +++ b/HIRS_AttestationCAPortal/src/main/java/hirs/attestationca/portal/page/controllers/ReferenceManifestDetailsPageController.java @@ -4,6 +4,9 @@ import hirs.data.persist.BaseReferenceManifest; import hirs.data.persist.ReferenceManifest; import hirs.data.persist.SupportReferenceManifest; import hirs.data.persist.SwidResource; +import hirs.data.persist.certificate.Certificate; +import hirs.data.persist.certificate.CertificateAuthorityCredential; +import hirs.persist.CertificateManager; import hirs.persist.DBManagerException; import hirs.persist.ReferenceManifestManager; import hirs.tpm.eventlog.TCGEventLog; @@ -12,6 +15,7 @@ import hirs.attestationca.portal.page.PageController; import hirs.attestationca.portal.page.PageMessages; import hirs.attestationca.portal.page.params.ReferenceManifestDetailsPageParams; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; @@ -21,6 +25,7 @@ import java.util.List; import java.util.ArrayList; import java.util.UUID; +import hirs.utils.ReferenceManifestValidator; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -38,19 +43,25 @@ public class ReferenceManifestDetailsPageController extends PageController { private final ReferenceManifestManager referenceManifestManager; + private final CertificateManager certificateManager; + private static final ReferenceManifestValidator RIM_VALIDATOR + = new ReferenceManifestValidator(); private static final Logger LOGGER = LogManager.getLogger(ReferenceManifestDetailsPageController.class); /** * Constructor providing the Page's display and routing specification. * - * @param referenceManifestManager the reference manifest manager + * @param referenceManifestManager the reference manifest manager. + * @param certificateManager the certificate manager. */ @Autowired public ReferenceManifestDetailsPageController( - final ReferenceManifestManager referenceManifestManager) { + final ReferenceManifestManager referenceManifestManager, + final CertificateManager certificateManager) { super(Page.RIM_DETAILS); this.referenceManifestManager = referenceManifestManager; + this.certificateManager = certificateManager; } /** @@ -80,7 +91,7 @@ public class ReferenceManifestDetailsPageController } else { try { UUID uuid = UUID.fromString(params.getId()); - data.putAll(getRimDetailInfo(uuid, referenceManifestManager)); + data.putAll(getRimDetailInfo(uuid, referenceManifestManager, certificateManager)); } catch (IllegalArgumentException iaEx) { String uuidError = "Failed to parse ID from: " + params.getId(); messages.addError(uuidError); @@ -108,13 +119,15 @@ public class ReferenceManifestDetailsPageController * * @param uuid database reference for the requested RIM. * @param referenceManifestManager the reference manifest 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 getRimDetailInfo(final UUID uuid, - final ReferenceManifestManager referenceManifestManager) throws IOException, + final ReferenceManifestManager referenceManifestManager, + final CertificateManager certificateManager) throws IOException, CertificateException, NoSuchAlgorithmException { HashMap data = new HashMap<>(); @@ -183,11 +196,19 @@ public class ReferenceManifestDetailsPageController logProcessor = new TCGEventLog(support.getRimBytes()); } } + // going to have to pull the filename and grab that from the DB // to get the id to make the link for (SwidResource swidRes : resources) { if (support != null && swidRes.getName() .equals(support.getFileName())) { + RIM_VALIDATOR.validateSupportRimHash(support.getRimBytes(), + swidRes.getHashValue()); + if (RIM_VALIDATOR.isSupportRimValid()) { + data.put("supportRimHashValid", true); + } else { + data.put("supportRimHashValid", false); + } swidRes.setPcrValues(Arrays.asList( logProcessor.getExpectedPCRValues())); break; @@ -198,6 +219,21 @@ public class ReferenceManifestDetailsPageController data.put("associatedRim", bRim.getAssociatedRim()); data.put("swidFiles", resources); + + RIM_VALIDATOR.validateXmlSignature(new ByteArrayInputStream(bRim.getRimBytes())); + data.put("signatureValid", RIM_VALIDATOR.isSignatureValid()); + if (RIM_VALIDATOR.isSignatureValid()) { + LOGGER.info("Public key: " + RIM_VALIDATOR.getPublicKey().toString()); + try { + Certificate certificate = + CertificateAuthorityCredential.select(certificateManager) + .byEncodedPublicKey(RIM_VALIDATOR.getPublicKey().getEncoded()) + .getCertificate(); + data.put("issuerID", certificate.getId().toString()); + } catch (NullPointerException e) { + LOGGER.info("Unable to get signing certificate link: " + e.getMessage()); + } + } } else { SupportReferenceManifest sRim = SupportReferenceManifest .select(referenceManifestManager) diff --git a/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/rim-details.jsp b/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/rim-details.jsp index 21ae4324..dab7c407 100644 --- a/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/rim-details.jsp +++ b/HIRS_AttestationCAPortal/src/main/webapp/WEB-INF/jsp/rim-details.jsp @@ -17,7 +17,13 @@ -
+ + + + + + +
@@ -171,6 +177,14 @@ ${resource.getName()} + + + + + + + + ${resource.getName()} @@ -237,6 +251,24 @@
+
+
Signature
+
+
Validity:  + + + + + + + + + + + +
+
+
diff --git a/HIRS_Utils/src/main/java/hirs/data/persist/BaseReferenceManifest.java b/HIRS_Utils/src/main/java/hirs/data/persist/BaseReferenceManifest.java index 00a544f2..e8fefe5d 100644 --- a/HIRS_Utils/src/main/java/hirs/data/persist/BaseReferenceManifest.java +++ b/HIRS_Utils/src/main/java/hirs/data/persist/BaseReferenceManifest.java @@ -151,6 +151,7 @@ public class BaseReferenceManifest extends ReferenceManifest { public BaseReferenceManifest(final byte[] rimBytes) throws IOException { super(rimBytes); this.setRimType(BASE_RIM); + this.setFileName(""); SoftwareIdentity si = validateSwidTag(new ByteArrayInputStream(rimBytes)); // begin parsing valid swid tag diff --git a/HIRS_Utils/src/main/java/hirs/utils/ReferenceManifestValidator.java b/HIRS_Utils/src/main/java/hirs/utils/ReferenceManifestValidator.java new file mode 100644 index 00000000..d8963592 --- /dev/null +++ b/HIRS_Utils/src/main/java/hirs/utils/ReferenceManifestValidator.java @@ -0,0 +1,349 @@ +package hirs.utils; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import javax.xml.XMLConstants; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBException; +import javax.xml.bind.UnmarshalException; +import javax.xml.bind.Unmarshaller; +import javax.xml.crypto.AlgorithmMethod; +import javax.xml.crypto.KeySelector; +import javax.xml.crypto.KeySelectorException; +import javax.xml.crypto.KeySelectorResult; +import javax.xml.crypto.MarshalException; +import javax.xml.crypto.XMLCryptoContext; +import javax.xml.crypto.XMLStructure; +import javax.xml.crypto.dsig.XMLSignature; +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.X509Data; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +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.IOException; +import java.io.InputStream; +import java.security.Key; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.Iterator; + + +/** + * This class handles validation functions of RIM files. + * Currently supports validation of support RIM hashes and + * base RIM signatures. + */ +public class ReferenceManifestValidator { + private static final String SIGNATURE_ALGORITHM_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; + private static final String IDENTITY_TRANSFORM = "identity_transform.xslt"; + private static final String SHA256 = "SHA-256"; + private static final int EIGHT_BIT_MASK = 0xff; + private static final int LEFT_SHIFT = 0x100; + private static final int RADIX = 16; + private static final Logger LOGGER = LogManager.getLogger(ReferenceManifestValidator.class); + + private Unmarshaller unmarshaller; + private PublicKey publicKey; + private Schema schema; + private boolean signatureValid, supportRimValid; + + /** + * 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; + } + + /** + * This default constructor creates the Schema object from SCHEMA_URL immediately to save + * time during validation calls later. + */ + public ReferenceManifestValidator() { + try { + InputStream is = ReferenceManifestValidator.class + .getClassLoader().getResourceAsStream(SCHEMA_URL); + SchemaFactory schemaFactory = SchemaFactory.newInstance(SCHEMA_LANGUAGE); + schema = schemaFactory.newSchema(new StreamSource(is)); + signatureValid = false; + supportRimValid = false; + publicKey = null; + } 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. + * + * @param input the xml data stream. + */ + public void validateXmlSignature(final InputStream input) { + try { + Document doc = validateSwidtagSchema(removeXMLWhitespace(new StreamSource(input))); + signatureValid = validateSignedXMLDocument(doc); + } catch (IOException e) { + LOGGER.warn("Error during unmarshal: " + e.getMessage()); + } + } + + /** + * This method calculates the digest of a byte array based on the hashing algorithm passed in. + * @param input byte array. + * @param sha hash algorithm. + * @return String digest. + */ + private String getHashValue(final byte[] input, final String sha) { + String resultString = null; + try { + MessageDigest md = MessageDigest.getInstance(sha); + byte[] bytes = md.digest(input); + StringBuilder sb = new StringBuilder(); + + for (int i = 0; i < bytes.length; i++) { + sb.append(Integer.toString((bytes[i] & EIGHT_BIT_MASK) + + LEFT_SHIFT, RADIX).substring(1)); + } + resultString = sb.toString(); + } catch (NoSuchAlgorithmException grex) { + LOGGER.warn(grex.getMessage()); + } + + return resultString; + } + + /** + * This method validates a Document with a signature element. + * + * @param doc + */ + private boolean validateSignedXMLDocument(final Document doc) { + DOMValidateContext context; + boolean isValid = false; + try { + NodeList nodes = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature"); + if (nodes.getLength() == 0) { + throw new Exception("Signature element not found!"); + } + NodeList embeddedCert = doc.getElementsByTagName("X509Data"); + if (embeddedCert.getLength() > 0) { + 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(); + } else { + LOGGER.info("Signing certificate not found for validation!"); + } + } catch (MarshalException | XMLSignatureException e) { + LOGGER.warn(e.getMessage()); + } catch (Exception e) { + LOGGER.warn(e.getMessage()); + LOGGER.info(e.getMessage()); + } + + return isValid; + } + + /** + * 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 static class X509KeySelector extends KeySelector { + private PublicKey publicKey; + + /** + * This method selects an X509 cert based on the provided algorithm. + * + * @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) { + publicKey = ((X509Certificate) object).getPublicKey(); + 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 name string 2 + * @return true if equal, false if not + */ + public boolean areAlgorithmsEqual(final String uri, final String name) { + 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 Key key; + + RIMKeySelectorResult(final Key key) { + this.key = key; + } + + public Key getKey() { + return key; + } + } + } + + /** + * This method validates the Document against the schema. + * + * @param doc of the input swidtag. + * @return document validated against the schema. + */ + private Document validateSwidtagSchema(final Document doc) { + try { + JAXBContext jaxbContext = JAXBContext.newInstance(SCHEMA_PACKAGE); + unmarshaller = jaxbContext.createUnmarshaller(); + unmarshaller.setSchema(schema); + unmarshaller.unmarshal(doc); + } catch (UnmarshalException e) { + LOGGER.warn("Error validating swidtag file!"); + } catch (IllegalArgumentException e) { + LOGGER.warn("Input file empty."); + } catch (JAXBException e) { + e.printStackTrace(); + } + + return doc; + } + + /** + * This method strips all whitespace from an xml file, including indents and spaces + * added for human-readability. + * + * @param source of the input xml. + * @return Document representation of the xml. + */ + private Document removeXMLWhitespace(final StreamSource source) throws IOException { + TransformerFactory tf = TransformerFactory.newInstance(); + Source identitySource = new StreamSource( + ReferenceManifestValidator.class.getClassLoader() + .getResourceAsStream(IDENTITY_TRANSFORM)); + Document doc = null; + try { + Transformer transformer = tf.newTransformer(identitySource); + DOMResult result = new DOMResult(); + transformer.transform(source, result); + doc = (Document) result.getNode(); + } catch (TransformerConfigurationException e) { + LOGGER.warn("Error configuring transformer!"); + e.printStackTrace(); + } catch (TransformerException e) { + LOGGER.warn("Error transforming input!"); + e.printStackTrace(); + } + + return doc; + } +} diff --git a/HIRS_Utils/src/main/resources/identity_transform.xslt b/HIRS_Utils/src/main/resources/identity_transform.xslt new file mode 100644 index 00000000..d249ca61 --- /dev/null +++ b/HIRS_Utils/src/main/resources/identity_transform.xslt @@ -0,0 +1,10 @@ + + + + + + + + + +