/* * XAdES4j - A Java library for generation and verification of XAdES signatures. * Copyright (C) 2010 Luis Goncalves. * * XAdES4j is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 3 of the License, or any later version. * * XAdES4j is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License along * with XAdES4j. If not, see <http://www.gnu.org/licenses/>. */ package xades4j.verification; import java.security.cert.X509CertSelector; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.xml.security.exceptions.XMLSecurityException; import org.apache.xml.security.keys.KeyInfo; import org.apache.xml.security.keys.content.X509Data; import org.apache.xml.security.keys.content.x509.XMLX509IssuerSerial; import xades4j.properties.data.CertRef; import xades4j.providers.CertificateValidationException; import xades4j.providers.X500NameStyleProvider; /** * * @author Luís */ class KeyInfoProcessor { private KeyInfoProcessor() { } /**/ static class KeyInfoRes { X509CertSelector certSelector; List<X509Certificate> keyInfoCerts; XMLX509IssuerSerial issuerSerial; KeyInfoRes( X509CertSelector certSelector, List<X509Certificate> keyInfoCerts, XMLX509IssuerSerial issuerSerial) { this.keyInfoCerts = keyInfoCerts; this.certSelector = certSelector; this.issuerSerial = issuerSerial; } KeyInfoRes(X509CertSelector certSelector) { this.certSelector = certSelector; this.keyInfoCerts = Collections.emptyList(); this.issuerSerial = null; } } static KeyInfoRes process( KeyInfo keyInfo, CertRef signingCertRef, X500NameStyleProvider x500NameStyleProvider) throws CertificateValidationException { if (null == keyInfo || !keyInfo.containsX509Data()) { return tryUseSigningCertificateReference(signingCertRef, x500NameStyleProvider); } List<X509Certificate> keyInfoCerts = new ArrayList<X509Certificate>(1); XMLX509IssuerSerial issuerSerial = null; X509CertSelector certSelector = new X509CertSelector(); // XML-DSIG 4.4.4: "Any X509IssuerSerial, X509SKI, and X509SubjectName elements // that appear MUST refer to the certificate or certificates containing the // validation key." // "All certificates appearing in an X509Data element MUST relate to the // validation key by either containing it or being part of a certification // chain that terminates in a certificate containing the validation key". // Scan ds:X509Data to find ds:IssuerSerial or ds:SubjectName elements. The // first to be found is used to select the leaf certificate. If none of those // elements is present, the first ds:X509Certificate is assumed as the signing // certificate. boolean hasSelectionCriteria = false; try { for (int i = 0; i < keyInfo.lengthX509Data(); ++i) { X509Data x509Data = keyInfo.itemX509Data(i); if (!hasSelectionCriteria) { if (x509Data.containsIssuerSerial()) { issuerSerial = x509Data.itemIssuerSerial(0); certSelector.setIssuer(x500NameStyleProvider.fromString(issuerSerial.getIssuerName())); certSelector.setSerialNumber(issuerSerial.getSerialNumber()); hasSelectionCriteria = true; } else if (x509Data.containsSubjectName()) { certSelector.setSubject(x500NameStyleProvider.fromString(x509Data.itemSubjectName(0).getSubjectName())); hasSelectionCriteria = true; } } // Collect all certificates as they may be needed to build the cert path. if (x509Data.containsCertificate()) { for (int j = 0; j < x509Data.lengthCertificate(); ++j) { keyInfoCerts.add(x509Data.itemCertificate(j).getX509Certificate()); } } } if (!hasSelectionCriteria) { if (keyInfoCerts.isEmpty()) { return tryUseSigningCertificateReference(signingCertRef, x500NameStyleProvider); } certSelector.setCertificate(keyInfoCerts.get(0)); } } catch (XMLSecurityException ex) { throw new InvalidKeyInfoDataException("Cannot process X509Data", ex); } return new KeyInfoRes(certSelector, keyInfoCerts, issuerSerial); } private static KeyInfoRes tryUseSigningCertificateReference(CertRef signingCertRef, X500NameStyleProvider x500NameStyleProvider) throws CertificateValidationException { if (signingCertRef == null) { throw new InvalidKeyInfoDataException("Could not identify the leaf certificate using X509Datas in KeyInfo"); } X509CertSelector certSelector = new X509CertSelector(); certSelector.setIssuer(x500NameStyleProvider.fromString(signingCertRef.issuerDN)); certSelector.setSerialNumber(signingCertRef.serialNumber); return new KeyInfoRes(certSelector); } }