mirror of
https://github.com/nsacyber/HIRS.git
synced 2024-12-19 04:58:00 +00:00
Moved KeyValue processing to KeySelector inner class
This commit is contained in:
parent
e5e6db75f4
commit
4b3c01f990
@ -39,11 +39,9 @@ import java.io.File;
|
|||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
import java.security.KeyException;
|
import java.security.KeyException;
|
||||||
import java.security.KeyFactory;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
@ -52,9 +50,7 @@ import java.security.SignatureException;
|
|||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
import java.security.cert.X509Certificate;
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.spec.InvalidKeySpecException;
|
import java.security.spec.InvalidKeySpecException;
|
||||||
import java.security.spec.RSAPublicKeySpec;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -66,6 +62,7 @@ public class SwidTagValidator {
|
|||||||
private String rimEventLog;
|
private String rimEventLog;
|
||||||
private String certificateFile;
|
private String certificateFile;
|
||||||
private String trustStoreFile;
|
private String trustStoreFile;
|
||||||
|
private List<X509Certificate> trustStore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
|
* Ensure that BouncyCastle is configured as a javax.security.Security provider, as this
|
||||||
@ -159,7 +156,7 @@ public class SwidTagValidator {
|
|||||||
DOMValidateContext context;
|
DOMValidateContext context;
|
||||||
CredentialParser cp = new CredentialParser();
|
CredentialParser cp = new CredentialParser();
|
||||||
X509Certificate signingCert = null;
|
X509Certificate signingCert = null;
|
||||||
List<X509Certificate> trustStore = cp.parseCertsFromPEM(trustStoreFile);
|
trustStore = cp.parseCertsFromPEM(trustStoreFile);
|
||||||
X509KeySelector keySelector = new X509KeySelector();
|
X509KeySelector keySelector = new X509KeySelector();
|
||||||
NodeList nodes = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
|
NodeList nodes = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
|
||||||
if (nodes.getLength() == 0) {
|
if (nodes.getLength() == 0) {
|
||||||
@ -167,30 +164,9 @@ public class SwidTagValidator {
|
|||||||
} else {
|
} else {
|
||||||
context = new DOMValidateContext(keySelector, nodes.item(0));
|
context = new DOMValidateContext(keySelector, nodes.item(0));
|
||||||
}
|
}
|
||||||
NodeList embeddedCert = doc.getElementsByTagName("X509Certificate");
|
NodeList keyName = doc.getElementsByTagName("KeyName");
|
||||||
if (embeddedCert.getLength() > 0) {
|
if (keyName.getLength() > 0) {
|
||||||
signingCert = cp.parseCertFromPEMString(embeddedCert.item(0).getTextContent());
|
String skId = keyName.item(0).getTextContent();
|
||||||
} else {
|
|
||||||
NodeList keyValue = doc.getElementsByTagName("KeyValue");
|
|
||||||
if (keyValue.getLength() > 0) {
|
|
||||||
String modulus = doc.getElementsByTagName("Modulus").item(0).getTextContent();
|
|
||||||
String exponent =
|
|
||||||
doc.getElementsByTagName("Exponent").item(0).getTextContent();
|
|
||||||
PublicKey signingKey = calculatePublicKey(modulus, exponent);
|
|
||||||
for (X509Certificate trustedCert : trustStore) {
|
|
||||||
System.out.println(trustedCert.getPublicKey().toString());
|
|
||||||
if (Arrays.equals(trustedCert.getPublicKey().getEncoded(),
|
|
||||||
signingKey.getEncoded())) {
|
|
||||||
signingCert = trustedCert;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (signingCert == null) {
|
|
||||||
System.out.println("Calculated public key not found: " + signingKey.toString());
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
String skId = doc.getElementsByTagName("KeyName").item(0).getTextContent();
|
|
||||||
if (skId != null && !skId.isEmpty()) {
|
if (skId != null && !skId.isEmpty()) {
|
||||||
for (X509Certificate trustedCert : trustStore) {
|
for (X509Certificate trustedCert : trustStore) {
|
||||||
String trustedSkId = cp.getCertificateSubjectKeyIdentifier(trustedCert);
|
String trustedSkId = cp.getCertificateSubjectKeyIdentifier(trustedCert);
|
||||||
@ -199,27 +175,30 @@ public class SwidTagValidator {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (signingCert == null) {
|
if (signingCert != null) {
|
||||||
|
context = new DOMValidateContext(signingCert.getPublicKey(),
|
||||||
|
nodes.item(0));
|
||||||
|
} else {
|
||||||
System.out.println("Issuer certificate with subject key identifier = "
|
System.out.println("Issuer certificate with subject key identifier = "
|
||||||
+ skId + " not found");
|
+ skId + " not found");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
System.out.println("No credentials found with which to validate this swidtag");
|
System.out.println("Base RIM must have a non-empty, non-null " +
|
||||||
|
"Subject Key Identifier (SKID) in the <KeyName> element");
|
||||||
System.exit(1);
|
System.exit(1);
|
||||||
}
|
}
|
||||||
context = new DOMValidateContext(signingCert.getPublicKey(), nodes.item(0));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
cp.setCertificate(signingCert);
|
|
||||||
System.out.println(cp.getCertificateAuthorityInfoAccess());
|
|
||||||
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
|
XMLSignatureFactory sigFactory = XMLSignatureFactory.getInstance("DOM");
|
||||||
XMLSignature signature = sigFactory.unmarshalXMLSignature(context);
|
XMLSignature signature = sigFactory.unmarshalXMLSignature(context);
|
||||||
boolean signatureIsValid = signature.validate(context);
|
boolean signatureIsValid = signature.validate(context);
|
||||||
boolean certChainIsValid = validateCertChain(signingCert, trustStore);
|
|
||||||
System.out.println("Signature validity: " + signatureIsValid);
|
System.out.println("Signature validity: " + signatureIsValid);
|
||||||
System.out.println("Cert chain validity: " + certChainIsValid);
|
if (signingCert == null) {
|
||||||
return signatureIsValid && certChainIsValid;
|
signingCert = keySelector.getSigningCert();
|
||||||
|
}
|
||||||
|
cp.setCertificate(signingCert);
|
||||||
|
System.out.println(System.lineSeparator() + cp.getCertificateAuthorityInfoAccess());
|
||||||
|
return signatureIsValid;
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
System.out.println("Error parsing truststore: " + e.getMessage());
|
System.out.println("Error parsing truststore: " + e.getMessage());
|
||||||
} catch (NoSuchAlgorithmException e) {
|
} catch (NoSuchAlgorithmException e) {
|
||||||
@ -237,37 +216,104 @@ public class SwidTagValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method calculates an RSA public key from the <KeyValue> element of an XML
|
* This internal class handles parsing the public key from a KeyInfo element.
|
||||||
* signature block.
|
|
||||||
*
|
|
||||||
* @param mod the modulus string
|
|
||||||
* @param exp the exponent string
|
|
||||||
* @return the calculated public key
|
|
||||||
*/
|
*/
|
||||||
private PublicKey calculatePublicKey(final String mod, final String exp)
|
public class X509KeySelector extends KeySelector {
|
||||||
throws NoSuchAlgorithmException, InvalidKeySpecException{
|
PublicKey publicKey;
|
||||||
|
X509Certificate signingCert;
|
||||||
|
|
||||||
System.out.println("Decoding " + exp);
|
public PublicKey getPublicKey() {
|
||||||
BigInteger exponent = new BigInteger(Base64.getMimeDecoder().decode(exp));
|
return publicKey;
|
||||||
System.out.println("MIME: " + exponent);
|
}
|
||||||
System.out.println("Decoding " + mod);
|
|
||||||
BigInteger modulus = new BigInteger(Base64.getMimeDecoder().decode(mod));
|
|
||||||
System.out.println("MIME: " + modulus);
|
|
||||||
|
|
||||||
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
|
public X509Certificate getSigningCert() {
|
||||||
return keyFactory.generatePublic(new RSAPublicKeySpec(modulus, exponent));
|
return signingCert;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method extracts a public key from either an X509Certificate element
|
||||||
|
* or a KeyValue element. If the public key's algorithm matches the declared
|
||||||
|
* algorithm it is returned in a KeySelecctorResult.
|
||||||
|
* @param keyinfo the KeyInfo element
|
||||||
|
* @param purpose
|
||||||
|
* @param algorithm the encapsulating signature's declared signing algorithm
|
||||||
|
* @param context
|
||||||
|
* @return a KeySelectorResult if the public key's algorithm matches the declared algorithm
|
||||||
|
* @throws KeySelectorException if the algorithms do not match
|
||||||
|
*/
|
||||||
|
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) {
|
||||||
|
X509Certificate embeddedCert = (X509Certificate) object;
|
||||||
|
try {
|
||||||
|
if (isCertChainValid(embeddedCert)) {
|
||||||
|
publicKey = ((X509Certificate) embeddedCert).getPublicKey();
|
||||||
|
signingCert = embeddedCert;
|
||||||
|
System.out.println("Certificate chain validity: true");
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Certificate chain invalid: "
|
||||||
|
+ e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (element instanceof KeyValue) {
|
||||||
|
try {
|
||||||
|
PublicKey pk = ((KeyValue) element).getPublicKey();
|
||||||
|
if (isPublicKeyTrusted(pk)) {
|
||||||
|
publicKey = pk;
|
||||||
|
try {
|
||||||
|
System.out.println("Certificate chain validity: "
|
||||||
|
+ isCertChainValid(signingCert));
|
||||||
|
} catch (Exception e) {
|
||||||
|
System.out.println("Certificate chain invalid: "
|
||||||
|
+ e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (KeyException e) {
|
||||||
|
System.out.println("Unable to convert KeyValue data to PK.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (publicKey != null) {
|
||||||
|
if (areAlgorithmsEqual(algorithm.getAlgorithm(), publicKey.getAlgorithm())) {
|
||||||
|
return new
|
||||||
|
SwidTagValidator.X509KeySelector.RIMKeySelectorResult(publicKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new KeySelectorException("No key found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method checks that the signature and public key algorithms match.
|
||||||
|
* @param uri to match the signature algorithm
|
||||||
|
* @param name to match the public key algorithm
|
||||||
|
* @return true if both match, false otherwise
|
||||||
|
*/
|
||||||
|
public boolean areAlgorithmsEqual(String uri, String name) {
|
||||||
|
return uri.equals(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256)
|
||||||
|
&& name.equalsIgnoreCase("RSA");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method validates the cert chain for a given certificate. The truststore is iterated
|
* This method validates the cert chain for a given certificate. The truststore is iterated
|
||||||
* over until a root CA is found, otherwise an error is returned.
|
* over until a root CA is found, otherwise an error is returned.
|
||||||
* @param cert the certificate at the start of the chain
|
* @param cert the certificate at the start of the chain
|
||||||
* @param trustStore from which to find the chain of intermediate and root CAs
|
|
||||||
* @return true if the chain is valid
|
* @return true if the chain is valid
|
||||||
* @throws Exception if a valid chain is not found in the truststore
|
* @throws Exception if a valid chain is not found in the truststore
|
||||||
*/
|
*/
|
||||||
private boolean validateCertChain(final X509Certificate cert,
|
private boolean isCertChainValid(final X509Certificate cert)
|
||||||
final List<X509Certificate> trustStore)
|
|
||||||
throws Exception {
|
throws Exception {
|
||||||
if (cert == null || trustStore == null) {
|
if (cert == null || trustStore == null) {
|
||||||
throw new Exception("Null certificate or truststore received");
|
throw new Exception("Null certificate or truststore received");
|
||||||
@ -361,65 +407,20 @@ public class SwidTagValidator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This internal class handles parsing the public key from a KeyInfo element.
|
* This method compares a public key against those in the truststore.
|
||||||
|
* @param pk a public key
|
||||||
|
* @return true if pk is found in the trust store, false otherwise
|
||||||
*/
|
*/
|
||||||
public class X509KeySelector extends KeySelector {
|
private boolean isPublicKeyTrusted(final PublicKey pk) {
|
||||||
/**
|
for (X509Certificate trustedCert : trustStore) {
|
||||||
* This method extracts a public key from either an X509Certificate element
|
if (Arrays.equals(trustedCert.getPublicKey().getEncoded(),
|
||||||
* or a KeyValue element. If the public key's algorithm matches the declared
|
pk.getEncoded())) {
|
||||||
* algorithm it is returned in a KeySelecctorResult.
|
signingCert = trustedCert;
|
||||||
* @param keyinfo the KeyInfo element
|
return true;
|
||||||
* @param purpose
|
|
||||||
* @param algorithm the encapsulating signature's declared signing algorithm
|
|
||||||
* @param context
|
|
||||||
* @return a KeySelectorResult if the public key's algorithm matches the declared algorithm
|
|
||||||
* @throws KeySelectorException if the algorithms do not match
|
|
||||||
*/
|
|
||||||
public KeySelectorResult select(final KeyInfo keyinfo,
|
|
||||||
final KeySelector.Purpose purpose,
|
|
||||||
final AlgorithmMethod algorithm,
|
|
||||||
final XMLCryptoContext context)
|
|
||||||
throws KeySelectorException {
|
|
||||||
Iterator keyinfoItr = keyinfo.getContent().iterator();
|
|
||||||
PublicKey publicKey = null;
|
|
||||||
System.out.println("Parsing KeyInfo");
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (element instanceof KeyValue) {
|
|
||||||
try {
|
|
||||||
publicKey = ((KeyValue) element).getPublicKey();
|
|
||||||
System.out.println("PK parsed from KeyValue: " + publicKey.toString());
|
|
||||||
} catch (KeyException e) {
|
|
||||||
System.out.println("Unable to convert KeyValue data to PK.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (publicKey != null) {
|
|
||||||
if (areAlgorithmsEqual(algorithm.getAlgorithm(), publicKey.getAlgorithm())) {
|
|
||||||
return new SwidTagValidator.X509KeySelector.RIMKeySelectorResult(publicKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new KeySelectorException("No key found!");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return false;
|
||||||
* This method checks that the signature and public key algorithms match.
|
|
||||||
* @param uri to match the signature algorithm
|
|
||||||
* @param name to match the public key algorithm
|
|
||||||
* @return true if both match, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean areAlgorithmsEqual(String uri, String name) {
|
|
||||||
return uri.equals(SwidTagConstants.SIGNATURE_ALGORITHM_RSA_SHA256)
|
|
||||||
&& name.equalsIgnoreCase("RSA");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RIMKeySelectorResult implements KeySelectorResult {
|
private class RIMKeySelectorResult implements KeySelectorResult {
|
||||||
|
Loading…
Reference in New Issue
Block a user