Add SKI to front end. Extract PK from base RIM to validate signature if not found in db

This commit is contained in:
chubtub 2020-11-13 10:33:01 -05:00
parent dbfdcdf9fd
commit e3b5d164a3
3 changed files with 89 additions and 35 deletions

View File

@ -5,7 +5,6 @@ import hirs.data.persist.EventLogMeasurements;
import hirs.data.persist.ReferenceManifest; import hirs.data.persist.ReferenceManifest;
import hirs.data.persist.SupportReferenceManifest; import hirs.data.persist.SupportReferenceManifest;
import hirs.data.persist.SwidResource; import hirs.data.persist.SwidResource;
import hirs.data.persist.certificate.Certificate;
import hirs.data.persist.certificate.CertificateAuthorityCredential; import hirs.data.persist.certificate.CertificateAuthorityCredential;
import hirs.persist.CertificateManager; import hirs.persist.CertificateManager;
import hirs.persist.DBManagerException; import hirs.persist.DBManagerException;
@ -26,6 +25,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.UUID; import java.util.UUID;
import hirs.tpm.eventlog.TpmPcrEvent; import hirs.tpm.eventlog.TpmPcrEvent;
@ -262,17 +262,20 @@ public class ReferenceManifestDetailsPageController
RIM_VALIDATOR.validateXmlSignature(new ByteArrayInputStream(baseRim.getRimBytes())); RIM_VALIDATOR.validateXmlSignature(new ByteArrayInputStream(baseRim.getRimBytes()));
data.put("signatureValid", RIM_VALIDATOR.isSignatureValid()); data.put("signatureValid", RIM_VALIDATOR.isSignatureValid());
if (RIM_VALIDATOR.isSignatureValid()) { data.put("skID", RIM_VALIDATOR.getSubjectKeyIdentifier());
LOGGER.info("Public key: " + RIM_VALIDATOR.getPublicKey().toString()); try {
try { Set<CertificateAuthorityCredential> certificates =
Certificate certificate = CertificateAuthorityCredential.select(certificateManager)
CertificateAuthorityCredential.select(certificateManager) .getCertificates();
.byEncodedPublicKey(RIM_VALIDATOR.getPublicKey().getEncoded()) for (CertificateAuthorityCredential cert : certificates) {
.getCertificate(); if (Arrays.equals(cert.getEncodedPublicKey(),
data.put("issuerID", certificate.getId().toString()); RIM_VALIDATOR.getPublicKey().getEncoded())) {
} catch (NullPointerException e) { LOGGER.info("Found matching cert!");
LOGGER.info("Unable to get signing certificate link: " + e.getMessage()); data.put("issuerID", cert.getId().toString());
}
} }
} catch (NullPointerException e) {
LOGGER.error("Unable to link signing certificate: " + e.getMessage());
} }
return data; return data;
} }

View File

@ -335,15 +335,27 @@
<c:choose> <c:choose>
<c:when test="${initialData.signatureValid}"> <c:when test="${initialData.signatureValid}">
<img src="${passIcon}" title="${signatureValidText}"/> <img src="${passIcon}" title="${signatureValidText}"/>
<c:if test="${not empty initialData.issuerID}">
<div><a href="${portal}/certificate-details?id=${initialData.issuerID}&type=certificateauthority">Signing certificate</a></div>
</c:if>
</c:when> </c:when>
<c:otherwise> <c:otherwise>
<img src="${failIcon}" title="${signatureInvalidText}"/> <img src="${failIcon}" title="${signatureInvalidText}"/>
</c:otherwise> </c:otherwise>
</c:choose> </c:choose>
</span></div> </span>
</div>
<div>
<span>
<c:if test="${not empty initialData.issuerID}">
<div><a href="${portal}/certificate-details?id=${initialData.issuerID}&type=certificateauthority">Signing certificate</a></div>
</c:if>
</span>
</div>
<div>
<span>
<c:if test="${not empty initialData.skID}">
<div>Subject Key Identifier: ${initialData.skID}</div>
</c:if>
</span>
</div>
</div> </div>
</div> </div>
</c:otherwise> </c:otherwise>

View File

@ -23,6 +23,7 @@ import javax.xml.crypto.dsig.XMLSignatureException;
import javax.xml.crypto.dsig.XMLSignatureFactory; import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext; import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfo; import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.KeyValue;
import javax.xml.crypto.dsig.keyinfo.X509Data; import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.transform.Source; import javax.xml.transform.Source;
import javax.xml.transform.Transformer; import javax.xml.transform.Transformer;
@ -36,6 +37,7 @@ import javax.xml.validation.SchemaFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.security.Key; import java.security.Key;
import java.security.KeyException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.PublicKey; import java.security.PublicKey;
@ -64,6 +66,7 @@ public class ReferenceManifestValidator {
private Unmarshaller unmarshaller; private Unmarshaller unmarshaller;
private PublicKey publicKey; private PublicKey publicKey;
private Schema schema; private Schema schema;
private String subjectKeyIdentifier;
private boolean signatureValid, supportRimValid; private boolean signatureValid, supportRimValid;
/** /**
@ -93,6 +96,14 @@ public class ReferenceManifestValidator {
return publicKey; return publicKey;
} }
/**
* Getter for subjectKeyIdentifier.
* @return subjectKeyIdentifier
*/
public String getSubjectKeyIdentifier() {
return subjectKeyIdentifier;
}
/** /**
* This default constructor creates the Schema object from SCHEMA_URL immediately to save * This default constructor creates the Schema object from SCHEMA_URL immediately to save
* time during validation calls later. * time during validation calls later.
@ -106,6 +117,7 @@ public class ReferenceManifestValidator {
signatureValid = false; signatureValid = false;
supportRimValid = false; supportRimValid = false;
publicKey = null; publicKey = null;
subjectKeyIdentifier = "";
} catch (SAXException e) { } catch (SAXException e) {
LOGGER.warn("Error setting schema for validation!"); LOGGER.warn("Error setting schema for validation!");
} }
@ -192,22 +204,21 @@ public class ReferenceManifestValidator {
if (nodes.getLength() == 0) { if (nodes.getLength() == 0) {
throw new Exception("Signature element not found!"); throw new Exception("Signature element not found!");
} }
NodeList embeddedCert = doc.getElementsByTagName("X509Data"); X509KeySelector keySelector = new ReferenceManifestValidator.X509KeySelector();
if (embeddedCert.getLength() > 0) { context = new DOMValidateContext(keySelector, nodes.item(0));
X509KeySelector keySelector = new ReferenceManifestValidator.X509KeySelector(); XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
context = new DOMValidateContext(keySelector, nodes.item(0)); XMLSignature signature = sigFactory.unmarshalXMLSignature(context);
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM"); isValid = signature.validate(context);
XMLSignature signature = sigFactory.unmarshalXMLSignature(context); publicKey = keySelector.getPublicKey();
isValid = signature.validate(context); subjectKeyIdentifier = getKeyName(doc);
publicKey = keySelector.getPublicKey(); } catch (MarshalException e) {
} else { LOGGER.warn("Error while unmarshalling XML signature: " + e.getMessage());
LOGGER.info("Signing certificate not found for validation!"); } catch (XMLSignatureException e) {
} LOGGER.warn("Error while validating XML signature: " + e.getMessage());
} catch (MarshalException | XMLSignatureException e) { } catch (KeySelectorException e) {
LOGGER.warn(e.getMessage()); LOGGER.warn("Public key not found in XML signature: " + e.getMessage());
} catch (Exception e) { } catch (Exception e) {
LOGGER.warn(e.getMessage()); LOGGER.warn(e.getMessage());
LOGGER.info(e.getMessage());
} }
return isValid; return isValid;
@ -222,7 +233,12 @@ public class ReferenceManifestValidator {
private PublicKey publicKey; private PublicKey publicKey;
/** /**
* This method selects an X509 cert based on the provided algorithm. * 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 keyinfo object containing the cert.
* @param purpose purpose. * @param purpose purpose.
@ -246,15 +262,23 @@ public class ReferenceManifestValidator {
Object object = dataItr.next(); Object object = dataItr.next();
if (object instanceof X509Certificate) { if (object instanceof X509Certificate) {
publicKey = ((X509Certificate) object).getPublicKey(); publicKey = ((X509Certificate) object).getPublicKey();
if (areAlgorithmsEqual(algorithm.getAlgorithm(), break;
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!"); throw new KeySelectorException("No key found!");
} }
@ -295,6 +319,21 @@ public class ReferenceManifestValidator {
} }
} }
/**
* This method parses the subject key identifier from the KeyName element of a signature.
*
* @param doc
* @return SKID if found, or an empty string.
*/
private String getKeyName(final Document doc) {
NodeList keyName = doc.getElementsByTagName("KeyName");
if (keyName.getLength() > 0) {
return keyName.item(0).getTextContent();
} else {
return null;
}
}
/** /**
* This method validates the Document against the schema. * This method validates the Document against the schema.
* *