/**
*
*/
package net.conselldemallorca.helium.integracio.plugins.signatura;
import java.io.ByteArrayInputStream;
import java.security.Provider;
import java.security.Security;
import java.security.cert.CertStore;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Vector;
import net.conselldemallorca.helium.core.util.GlobalProperties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.DERObjectIdentifier;
import org.bouncycastle.asn1.pkcs.ContentInfo;
import org.bouncycastle.asn1.pkcs.SignedData;
import org.bouncycastle.asn1.x509.X509CertificateStructure;
import org.bouncycastle.asn1.x509.X509Name;
import org.bouncycastle.cms.CMSSignedData;
import org.bouncycastle.cms.SignerInformation;
import org.bouncycastle.cms.SignerInformationStore;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.lowagie.text.pdf.AcroFields;
import com.lowagie.text.pdf.PdfPKCS7;
import com.lowagie.text.pdf.PdfReader;
/**
* Implementació de test del plugin de signatura. Aquest plugin
* només extreu les dades del certificat sense comprovar la seva
* validesa. Només té utilitat en entorns de proves.
*
* @author Limit Tecnologies <limit@limit.es>
*/
public class SignaturaPluginTest implements SignaturaPlugin {
public RespostaValidacioSignatura verificarSignatura(
byte[] document,
byte[] signatura,
boolean obtenirDadesCertificat) throws SignaturaPluginException {
RespostaValidacioSignatura resposta = new RespostaValidacioSignatura();
resposta.setEstat(RespostaValidacioSignatura.ESTAT_OK);
if (obtenirDadesCertificat) {
try {
if (isSignaturaFileAttached()) {
resposta.setDadesCertificat(
obtenirDadesCertificatPdf(signatura));
} else {
resposta.setDadesCertificat(
obtenirDadesCertificatNoPdf(signatura));
}
} catch (Exception ex) {
logger.error("Error en la validació de la signatura", ex);
}
}
return resposta;
}
@SuppressWarnings("unchecked")
private List<DadesCertificat> obtenirDadesCertificatPdf(
byte[] signatura) throws Exception {
PdfReader reader = new PdfReader(new ByteArrayInputStream(signatura));
AcroFields af = reader.getAcroFields();
ArrayList<String> names = af.getSignatureNames();
for (String name: names) {
PdfPKCS7 pk = af.verifySignature(name);
Certificate pkc[] = pk.getCertificates();
List<DadesCertificat> dadesCertificats = new ArrayList<DadesCertificat>();
for (Certificate cert: pkc) {
if (cert instanceof X509Certificate) {
int basicConstraints = ((X509Certificate)cert).getBasicConstraints();
// Només afegeix els certificats que no son de CA
if (basicConstraints == -1)
dadesCertificats.add(getDadesCertificat((X509Certificate)cert));
}
}
return dadesCertificats;
}
return null;
}
@SuppressWarnings({ "unchecked", "resource" })
private List<DadesCertificat> obtenirDadesCertificatNoPdf(
byte[] signatura) throws Exception {
X509Certificate[] certificats = null;
byte[] pkcs7Bytes = signatura;
ASN1InputStream asn1is = new ASN1InputStream(new ByteArrayInputStream(pkcs7Bytes));
ContentInfo pkcs7Info = ContentInfo.getInstance(asn1is.readObject());
SignedData signedData = SignedData.getInstance(pkcs7Info.getContent());
ASN1Set signerInfos = signedData.getSignerInfos();
int numSignatures = signerInfos.size();
if (numSignatures > 0) {
afegirProveidorBouncyCastle();
CMSSignedData cmsSignedData = new CMSSignedData(pkcs7Bytes);
SignerInformationStore signers = cmsSignedData.getSignerInfos();
CertStore certStore = cmsSignedData.getCertificatesAndCRLs("Collection", "BC");
List<X509Certificate> certs = new ArrayList<X509Certificate>();
for (SignerInformation signer: (Collection<SignerInformation>)signers.getSigners()) {
for (Certificate cert: certStore.getCertificates(signer.getSID())) {
if (cert instanceof X509Certificate)
certs.add((X509Certificate)cert);
}
}
certificats = certs.toArray(new X509Certificate[certs.size()]);
if (certificats.length != 1)
throw new SignaturaPluginException("Aquesta signatura conté més d'un certificat");
//resposta.setInfoCertificat(getInfoCertificat(certificats[0]));
List<DadesCertificat> dadesCertificats = new ArrayList<DadesCertificat>();
dadesCertificats.add(getDadesCertificat(certificats[0]));
return dadesCertificats;
}
return null;
}
private void afegirProveidorBouncyCastle() {
Provider[] proveidors = Security.getProviders();
boolean existeix = false;
for (int i = 0; i < proveidors.length; i++) {
if (proveidors[i].getName().equalsIgnoreCase("BC")) {
existeix = true;
break;
}
}
if (!existeix)
Security.addProvider(new BouncyCastleProvider());
}
@SuppressWarnings({ "rawtypes", "resource" })
private DadesCertificat getDadesCertificat(X509Certificate cert) throws Exception {
ASN1InputStream asn1is = new ASN1InputStream(cert.getEncoded());
org.bouncycastle.asn1.DERObject obj = asn1is.readObject();
/*byte[] value = cert.getExtensionValue(X509Extensions.BasicConstraints.toString());
BasicConstraints basicConstraints = new BasicConstraints(cert.getBasicConstraints());
if (basicConstraints.isCA())
return null;*/
DadesCertificat resposta = new DadesCertificat();
X509CertificateStructure certificate = new X509CertificateStructure((ASN1Sequence)obj);
X509Name name = certificate.getSubject();
Vector oids = name.getOIDs();
Vector values = name.getValues();
for (int i = 0; i < oids.size(); i++) {
if (oids.get(i).equals(X509Name.CN)) {
processName(values.get(i).toString(), resposta);
} else if (oids.get(i).equals(X509Name.SURNAME)) {
resposta.setApellidosResponsable(values.get(i).toString());
} else if (oids.get(i).equals(X509Name.GIVENNAME)) {
resposta.setNombreResponsable(values.get(i).toString());
} else if (oids.get(i).equals(X509Name.SN)) {
resposta.setNifCif(values.get(i).toString());
resposta.setNifResponsable(values.get(i).toString());
} else if (oids.get(i).equals(OID_NIF_RESPONSABLE)) {
resposta.setNifResponsable(values.get(i).toString());
} else if (oids.get(i).equals(X509Name.EmailAddress)) {
resposta.setEmail(values.get(i).toString());
} else if (oids.get(i).equals(X509Name.C)) {
//resposta.setPais(values.get(i).toString());
} else if (oids.get(i).equals(X509Name.O)) {
resposta.setRazonSocial(values.get(i).toString());
} else if (oids.get(i).equals(X509Name.OU)) {
//resposta.setDepartament(values.get(i).toString());
} else if (oids.get(i).equals(X509Name.T)) {
//resposta.setCarrec(values.get(i).toString());
}
}
return resposta;
}
private void processName(String cn, DadesCertificat dadesCertificat) {
if (cn != null && cn.startsWith("NOMBRE ")) {
int i = cn.indexOf(" - ");
if (i > 0 && cn.substring(i).startsWith(" - NIF ")) {
dadesCertificat.setNifResponsable(cn.substring(i + 7));
dadesCertificat.setNombreCompletoResponsable(cn.substring(7, i));
}
} else if (cn != null && cn.startsWith("ENTIDAD ")) {
int i = cn.indexOf(" - ");
if (i > 0 && cn.substring(i).startsWith(" - CIF ")) {
int j = cn.indexOf(" - ", i + 7);
int k = cn.indexOf(" - NIF ", i + 7);
if (j > 0 && k > 0) {
dadesCertificat.setNifCif(cn.substring(i + 8, j));
dadesCertificat.setNombreCompletoResponsable(cn.substring(7, i));
dadesCertificat.setNifResponsable(cn.substring(k + 7));
}
}
} else {
dadesCertificat.setNombreCompletoResponsable(cn);
}
}
private boolean isSignaturaFileAttached() {
return "true".equalsIgnoreCase((String)GlobalProperties.getInstance().get("app.signatura.plugin.file.attached"));
}
private static final DERObjectIdentifier OID_NIF_RESPONSABLE = new DERObjectIdentifier("1.3.6.1.4.1.18838.1.1");
private static final Log logger = LogFactory.getLog(SignaturaPluginTest.class);
}