Closed GoogleCodeExporter closed 9 years ago
The XMLDSIG code uses a KeyValueKeySelector which will look for a KeyValue
element in KeyInfo. However, XAdES signatures need the signer's certificate,
which in your case is also in the signature. XAdES4j will extract the
certificate and supply it on the otherCerts parameter of the validate method of
the CertificateValidationProvider in use. You can use a custom
CertificateValidationProvider implementation or the implementation provided in
the library (PKIXCertificateValidationProvider). This implementation expects a
key store with the trust roots for certificate validation and, optionally, some
additional intermediate certificates and CRLs (if revocation is used).
Check the usage examples on:
http://code.google.com/p/xades4j/source/browse/tags/version-1.2.0/src/test/java/
xades4j/verification/VerifierTestBase.java
Note: this isn't really an issue on the library; I'm marking it accordingly.
Nevertheless, it makes me realize that the CertificateValidationProvider
documentation can be improved
Original comment by luis.fgoncalv
on 20 Mar 2012 at 10:43
Hello
My basic code to use x509 in xades file. You can reuse code or idea for your
librarie
<--------- VALIDATOR----------->
/**
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
// Instantiate the document to be validated
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(new FileInputStream("c:/firstXades.xml"));
// Find Signature element
Element sigElement = getSigElement(doc);
if (null == sigElement) {
throw new Exception("Cannot find Signature element");
}
SignatureSpecificVerificationOptions ssvo = new SignatureSpecificVerificationOptions();
ssvo.useDataForAnonymousReference(new FileInputStream("c:/firstXades.xml"));
Key validationKey = null;
X509Certificate cert = null;
MyKeySelectorResult ksResult;
try {
ksResult = X509KeySelectorXades.getX509FromXadesFile(doc, "RSA");
validationKey = ksResult.getKey();
cert = ksResult.getCertificate();
if (validationKey == null) {
throw new XMLSignatureException("the keyselector did " + "not find a validation key");
}
} catch (KeySelectorException kse) {
throw new XMLSignatureException("cannot find validation " + "key", kse);
}
CertificateValidationProvider certValidator = new CertificateValidationProviderWithX509(cert, false, null);
XadesVerificationProfile p = new XadesVerificationProfile(certValidator);
XadesVerifier verifier = p.newVerifier();
// XAdESVerificationResult r = verifier.verify(sigElement, ssvo);
XAdESVerificationResult r = null;
boolean isOK = false;
try {
r = verifier.verify(sigElement, ssvo);
isOK = true;
} catch (xades4j.verification.ReferenceValueException e1) {
e1.printStackTrace();
}
XAdESForm xe = r.getSignatureForm();
if (!isOK) {
System.out.println("XADES KO -------------------->");
} else {
System.out.println("XADES OK-------------------->");
System.out.println(r.getCanonicalizationAlgorithmUri());
System.out.println(r.getXmlSignature());
System.out.println(r.getSignatureForm());
System.out.println(r.getSignatureAlgorithmUri());
System.out.println(r.getSignedDataObjects().size());
System.out.println(r.getQualifyingProperties().all().size());
}
}
public static Element getSigElement(Document doc) throws Exception {
return (Element) doc.getElementsByTagNameNS(Constants.SignatureSpecNS, Constants._TAG_SIGNATURE).item(0);
}
<------END--- VALIDATOR----------->
CertificateValidationProviderWithX509 it's your code from
PKIXCertificateValidationProvider with modification. lokk for /* langlade*/
for find modification
<--------- CertificateValidationProviderWithX509----------->
package protoSign.xades.verifier;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertPathBuilder;
import java.security.cert.CertPathBuilderException;
import java.security.cert.CertSelector;
import java.security.cert.CertStore;
import java.security.cert.CertStoreException;
import java.security.cert.CollectionCertStoreParameters;
import java.security.cert.PKIXBuilderParameters;
import java.security.cert.PKIXCertPathBuilderResult;
import java.security.cert.TrustAnchor;
import java.security.cert.X509CRL;
import java.security.cert.X509CRLSelector;
import java.security.cert.X509CertSelector;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.security.auth.x500.X500Principal;
import xades4j.providers.CannotBuildCertificationPathException;
import xades4j.providers.CannotSelectCertificateException;
import xades4j.providers.CertificateValidationException;
import xades4j.providers.CertificateValidationProvider;
import xades4j.providers.ValidationData;
import xades4j.verification.UnexpectedJCAException;
public class CertificateValidationProviderWithX509 implements
CertificateValidationProvider {
/* langlade*/
private final X509Certificate certX509;
/* langlade*/
private final boolean revocationEnabled;
private final int maxPathLength;
private final CertStore[] intermCertsAndCrls;
private final CertPathBuilder certPathBuilder;
/**
* @param certX509 the X509Certificate
* @param revocationEnabled whether revocation is enabled
* @param intermCertsAndCrls a set of {@code CertStore}s that contain certificates to be
* used in the construction of the certification path. May contain CRLs to be used
* if revocation is enabled
* @see xades4j.utils.FileSystemDirectoryCertStore
* @throws NoSuchAlgorithmException if there is no provider for PKIX CertPathBuilder
*/
public CertificateValidationProviderWithX509(/* langlade*/
X509Certificate certX509,/* langlade*/
boolean revocationEnabled,
int maxPathLength,
CertStore... intermCertsAndCrls) throws NoSuchAlgorithmException
{
if (null == certX509)
throw new NullPointerException();
/* langlade*/
this.certX509 = certX509;
/* langlade*/
this.revocationEnabled = revocationEnabled;
this.maxPathLength = maxPathLength;
this.intermCertsAndCrls = intermCertsAndCrls;
this.certPathBuilder = CertPathBuilder.getInstance("PKIX");
}
public CertificateValidationProviderWithX509(/* langlade*/
X509Certificate certX509,/* langlade*/
boolean revocationEnabled,
CertStore... intermCertsAndCrls) throws NoSuchAlgorithmException
{
this(certX509, revocationEnabled, 6, intermCertsAndCrls);
}
@Override
public ValidationData validate(
X509CertSelector certSelector,
Date validationDate,
Collection<X509Certificate> otherCerts) throws CertificateValidationException, UnexpectedJCAException
{
PKIXBuilderParameters builderParams;
try
{
/* langlade*/
Set<TrustAnchor> hashSet = new HashSet<TrustAnchor>();
hashSet.add(new TrustAnchor(this.certX509, null));
builderParams = new PKIXBuilderParameters(hashSet, certSelector);
/* langlade*/
} catch (InvalidAlgorithmParameterException ex)
{
throw new CannotBuildCertificationPathException(certSelector, "Trust anchors KeyStore has no trusted certificate entries");
}
PKIXCertPathBuilderResult builderRes;
try
{
// Certificates to be used to build the certification path.
// - The other certificates from the signature (e.g. from KeyInfo).
if (otherCerts != null)
{
CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(otherCerts);
CertStore othersCertStore = CertStore.getInstance("Collection", ccsp);
builderParams.addCertStore(othersCertStore);
}
// - The external certificates/CRLs.
/* langlade*/
if(null != this.intermCertsAndCrls){
for (int i = 0; i < this.intermCertsAndCrls.length; i++)
{
builderParams.addCertStore(this.intermCertsAndCrls[i]);
}
}
/* langlade*/
builderParams.setRevocationEnabled(revocationEnabled);
builderParams.setMaxPathLength(maxPathLength);
builderParams.setDate(validationDate);
builderRes = (PKIXCertPathBuilderResult)certPathBuilder.build(builderParams);
} catch (CertPathBuilderException ex)
{
throw new CannotBuildCertificationPathException(certSelector, ex.getMessage());
} catch (InvalidAlgorithmParameterException ex)
{
// SHOULD NOT be thrown due to wrong type of parameters.
// Seems to be thrown when the CertSelector (in builderParams) criteria
// cannot be applied.
throw new CannotSelectCertificateException(certSelector, ex.getMessage());
} catch (NoSuchAlgorithmException ex)
{
// SHOULD NOT be thrown.
throw new UnexpectedJCAException("No provider for Collection CertStore", ex);
}
// The cert path returned by the builder ends in a certificate issued by
// the trust anchor. However, the complete path may be needed for property
// verification.
List<X509Certificate> certPath = (List<X509Certificate>)builderRes.getCertPath().getCertificates();
// - Create a new list since the previous is immutable.
certPath = new ArrayList<X509Certificate>(certPath);
// - Add the trust anchor certificate.
certPath.add(builderRes.getTrustAnchor().getTrustedCert());
if (revocationEnabled)
return new ValidationData(certPath, getCRLsForCertPath(certPath, validationDate));
return new ValidationData(certPath);
}
private Collection<X509CRL> getCRLsForCertPath(
List<X509Certificate> certPath,
Date validationDate) throws CertificateValidationException
{
// Map the issuers certificates in the chain. This is used to know the issuers
// and later to verify the signatures in the CRLs.
Map<X500Principal, X509Certificate> issuersCerts = new HashMap<X500Principal, X509Certificate>(certPath.size() - 1);
for (int i = 0; i < certPath.size() - 1; i++)
{
// The issuer of one certificate is the subject of the following one.
issuersCerts.put(certPath.get(i).getIssuerX500Principal(), certPath.get(i + 1));
}
// Select all the CRLs from the issuers involved in the certification path
// that are valid at the moment.
X509CRLSelector crlSelector = new X509CRLSelector();
for (X500Principal issuer : issuersCerts.keySet())
{
// - "The issuer distinguished name in the X509CRL must match at least
// one of the specified distinguished names."
crlSelector.addIssuer(issuer);
}
// - "The specified date must be equal to or later than the value of the
// thisUpdate component of the X509CRL and earlier than the value of the
// nextUpdate component."
crlSelector.setDateAndTime(validationDate);
Set<X509CRL> crls = new HashSet<X509CRL>();
try
{
// Get the CRLs on each CertStore.
/* langlade*/
if(null != this.intermCertsAndCrls){
for (int i = 0; i < this.intermCertsAndCrls.length; i++)
{
Collection storeCRLs = this.intermCertsAndCrls[i].getCRLs(crlSelector);
crls.addAll(Collections.checkedCollection(storeCRLs, X509CRL.class));
}
}
/* langlade*/
} catch (CertStoreException ex)
{
throw new CertificateValidationException(null, "Cannot get CRLs: " + ex.getMessage());
}
// Verify the CRLs' signatures. The issuers' certificates were validated
// as part of the cert path creation.
for (X509CRL crl : crls)
{
try
{
X509Certificate crlIssuerCert = issuersCerts.get(crl.getIssuerX500Principal());
crl.verify(crlIssuerCert.getPublicKey());
} catch (Exception ex)
{
throw new CertificateValidationException(null, "Invalid CRL signature: " + crl.getIssuerX500Principal().getName());
}
}
return crls;
}
}
<-------------END ------CertificateValidationProviderWithX509----------->
and a X509KeySelectorXades for extrac x509 from xades file
<---------------X509KeySelectorXades------>
package protoSign.xades.dnsce;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.Key;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.KeySelectorException;
import javax.xml.crypto.KeySelectorResult;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.X509Data;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import protoSign.xmldesig.X509KeySelector;
public class X509KeySelectorXades {
public static void main(String[] args) throws Exception {
MyKeySelectorResult ksr = getX509FromXadesFile(new FileInputStream("c:/firstXades.xml"), "RAS");
ksr.getKey();
}
public static MyKeySelectorResult getX509FromXadesFile(Document doc, String algorithmeMethod) throws Exception {
// Find Signature element
NodeList nl = doc.getElementsByTagName("ds:Signature");
if (nl.getLength() == 0) {
throw new Exception("Cannot find Signature element");
}
/*
* ---------------
*/
DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(), nl.item(0));
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
fac.newDigestMethod(DigestMethod.SHA1, null);
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
KeyInfo keyInfo = signature.getKeyInfo();
MyKeySelectorResult ksr = select(keyInfo, algorithmeMethod);
return ksr;
}
public static MyKeySelectorResult getX509FromXadesFile(InputStream fileInput, String algorithmeMethod) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
Document doc = dbf.newDocumentBuilder().parse(fileInput);
return getX509FromXadesFile(doc, algorithmeMethod);
}
public static MyKeySelectorResult select(KeyInfo keyInfo, String method) throws KeySelectorException {
if (keyInfo == null) {
throw new KeySelectorException("ERROR: KeyInfo object null!");
}
Iterator hKeyInfo = keyInfo.getContent().iterator();
while (hKeyInfo.hasNext()) {
XMLStructure hX509Data = (XMLStructure) hKeyInfo.next();
if (!(hX509Data instanceof X509Data))
continue;
X509Data x509Data = (X509Data) hX509Data;
Iterator hX509Certificate = x509Data.getContent().iterator();
while (hX509Certificate.hasNext()) {
Object oX509Certificate = hX509Certificate.next();
if (!(oX509Certificate instanceof X509Certificate))
continue;
final X509Certificate x509Certificate = ((X509Certificate) oX509Certificate);
final PublicKey key = x509Certificate.getPublicKey();
// System.out.println(x509Certificate.getSubjectDN());
if (algEquals(method, key.getAlgorithm())) {
return new MyKeySelectorResult() {
public Key getKey() {
return key;
}
public X509Certificate getCertificate() {
return x509Certificate;
}
};
}
}
}
throw new KeySelectorException("ERROR: No X509Certificate found!");
}
static boolean algEquals(String algURI, String algName) {
if ((algName.equalsIgnoreCase("DSA") && algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1))
|| (algName.equalsIgnoreCase("RSA") && algURI.equalsIgnoreCase("RSA"))) {
return true;
} else {
return false;
}
}
}
<------END---------X509KeySelectorXades------>
See you soon and thanks.
Original comment by louloutr...@gmail.com
on 21 Mar 2012 at 1:11
[deleted comment]
Can you add a source code for protoSign.xmldesig.X509KeySelector. It's missing
to properly compile this code...
Original comment by Michal.T...@gmail.com
on 5 Sep 2014 at 6:14
Hi, look join file
2014-09-05 8:14 GMT+02:00 <xades4j@googlecode.com>:
Original comment by louloutr...@gmail.com
on 5 Sep 2014 at 1:02
Original issue reported on code.google.com by
louloutr...@gmail.com
on 20 Mar 2012 at 10:23