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.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;
@ -26,6 +25,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import hirs.tpm.eventlog.TpmPcrEvent;
@ -262,17 +262,20 @@ public class ReferenceManifestDetailsPageController
RIM_VALIDATOR.validateXmlSignature(new ByteArrayInputStream(baseRim.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());
data.put("skID", RIM_VALIDATOR.getSubjectKeyIdentifier());
try {
Set<CertificateAuthorityCredential> certificates =
CertificateAuthorityCredential.select(certificateManager)
.getCertificates();
for (CertificateAuthorityCredential cert : certificates) {
if (Arrays.equals(cert.getEncodedPublicKey(),
RIM_VALIDATOR.getPublicKey().getEncoded())) {
LOGGER.info("Found matching cert!");
data.put("issuerID", cert.getId().toString());
}
}
} catch (NullPointerException e) {
LOGGER.error("Unable to link signing certificate: " + e.getMessage());
}
return data;
}

View File

@ -335,15 +335,27 @@
<c:choose>
<c:when test="${initialData.signatureValid}">
<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:otherwise>
<img src="${failIcon}" title="${signatureInvalidText}"/>
</c:otherwise>
</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>
</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.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;
@ -36,6 +37,7 @@ import javax.xml.validation.SchemaFactory;
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;
@ -64,6 +66,7 @@ public class ReferenceManifestValidator {
private Unmarshaller unmarshaller;
private PublicKey publicKey;
private Schema schema;
private String subjectKeyIdentifier;
private boolean signatureValid, supportRimValid;
/**
@ -93,6 +96,14 @@ public class ReferenceManifestValidator {
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
* time during validation calls later.
@ -106,6 +117,7 @@ public class ReferenceManifestValidator {
signatureValid = false;
supportRimValid = false;
publicKey = null;
subjectKeyIdentifier = "";
} catch (SAXException e) {
LOGGER.warn("Error setting schema for validation!");
}
@ -192,22 +204,21 @@ public class ReferenceManifestValidator {
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());
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);
} 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());
LOGGER.info(e.getMessage());
}
return isValid;
@ -222,7 +233,12 @@ public class ReferenceManifestValidator {
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 purpose purpose.
@ -246,15 +262,23 @@ public class ReferenceManifestValidator {
Object object = dataItr.next();
if (object instanceof X509Certificate) {
publicKey = ((X509Certificate) object).getPublicKey();
if (areAlgorithmsEqual(algorithm.getAlgorithm(),
publicKey.getAlgorithm())) {
return new ReferenceManifestValidator.X509KeySelector
.RIMKeySelectorResult(publicKey);
}
break;
}
}
} 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!");
}
@ -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.
*