1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package es.accv.arangi.certificate.validation;
22
23 import java.util.Arrays;
24 import java.util.Date;
25 import java.util.HashMap;
26 import java.util.Map;
27 import java.util.Properties;
28
29 import org.apache.log4j.Logger;
30 import org.bouncycastle.asn1.ASN1EncodableVector;
31 import org.bouncycastle.asn1.ASN1Enumerated;
32 import org.bouncycastle.asn1.ASN1InputStream;
33 import org.bouncycastle.asn1.ASN1ObjectIdentifier;
34 import org.bouncycastle.asn1.DEROctetString;
35 import org.bouncycastle.asn1.DERSequence;
36 import org.bouncycastle.asn1.DERTaggedObject;
37 import org.bouncycastle.asn1.ocsp.BasicOCSPResponse;
38 import org.bouncycastle.cert.ocsp.BasicOCSPResp;
39 import org.bouncycastle.cert.ocsp.CertificateStatus;
40 import org.bouncycastle.cert.ocsp.OCSPResp;
41 import org.bouncycastle.cert.ocsp.RevokedStatus;
42
43 import es.accv.arangi.base.certificate.Certificate;
44 import es.accv.arangi.base.certificate.validation.CertificateValidationService;
45 import es.accv.arangi.base.certificate.validation.CertificateValidationServiceResult;
46 import es.accv.arangi.base.certificate.validation.OCSPResponse;
47 import es.accv.arangi.base.exception.certificate.NormalizeCertificateException;
48 import es.accv.arangi.base.exception.certificate.validation.ServiceException;
49 import es.accv.arangi.base.exception.certificate.validation.ServiceNotFoundException;
50 import es.accv.arangi.base.util.Util;
51 import es.accv.arangi.base.util.validation.ValidationResult;
52 import es.gob.afirma.afirma5ServiceInvoker.Afirma5ServiceInvokerContent;
53 import es.gob.afirma.afirma5ServiceInvoker.Afirma5ServiceInvokerFacade;
54 import es.gob.afirma.transformers.TransformersConstants;
55 import es.gob.afirma.transformers.TransformersException;
56 import es.gob.afirma.transformers.TransformersFacade;
57 import es.gob.afirma.utils.DSSConstants.DSSTagsRequest;
58 import es.gob.afirma.utils.DSSConstants.ReportDetailLevel;
59 import es.gob.afirma.utils.DSSConstants.ResultProcessIds;
60 import es.gob.afirma.utils.GeneralConstants;
61
62
63
64
65
66
67
68
69 public class AFirma6CertificateValidationService implements CertificateValidationService {
70
71
72
73
74 public static final String AFIRMA_MINOR_RESULT_CERTIFICATE_NOT_SUPPORTED = "urn:afirma:dss:1.0:profile:XSS:resultminor:Certificate:NotSupported";
75
76
77
78
79 public static final String AFIRMA_MINOR_RESULT_CERTIFICATE_REVOKED = "urn:oasis:names:tc:dss:1.0:profiles:XSS:resultminor:invalid:certificate:Revoked";
80
81
82
83
84 private static final int AFIRMA_CLASIFICACION_PERSONA_FISICA = 0;
85 private static final int AFIRMA_CLASIFICACION_PERSONA_JURIDICA = 1;
86 private static final int AFIRMA_CLASIFICACION_EMPLEADO_PUBLICO = 5;
87 private static final int AFIRMA_CLASIFICACION_ENTIDAD = 6;
88 private static final int AFIRMA_CLASIFICACION_CUALIFICADO_SELLO = 8;
89 private static final int AFIRMA_CLASIFICACION_AUTENTICACION = 9;
90 private static final int AFIRMA_CLASIFICACION_REPRESENTANTE_CPJ = 11;
91 private static final int AFIRMA_CLASIFICACION_REPRESENTANTE_SPJ = 12;
92
93
94
95
96 Logger logger = Logger.getLogger(AFirma6CertificateValidationService.class);
97
98
99
100
101 private String url;
102
103
104
105
106 private String idAplicacion;
107
108
109
110
111 private String user;
112
113
114
115
116 private String password;
117
118
119
120
121 private String configuracionWSS4J;
122
123
124
125
126
127
128
129 public AFirma6CertificateValidationService() {
130 super();
131 }
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 public AFirma6CertificateValidationService(String url, String idAplicacion, String user,
150 String password, String configuracionWSS4J) {
151 super();
152 initialize(url, idAplicacion, user, password, configuracionWSS4J);
153 }
154
155
156
157
158
159
160
161 public AFirma6CertificateValidationService(AFirma6CertificateValidationParameters parameters) {
162 super();
163 initialize(parameters.getAFirma6URL(), parameters.getAFirma6IdAplicacion(), parameters.getAFirma6User(),
164 parameters.getAFirma6Password(), parameters.getAFirma6ConfiguracionWSS4J());
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181 public void initialize (String url, String idAplicacion, String user, String password, String configuracionWSS4J) {
182 this.idAplicacion = idAplicacion;
183 this.user = user;
184 this.password = password;
185 this.configuracionWSS4J = configuracionWSS4J;
186
187 if (url.indexOf("//") > -1) {
188 url = url.substring(url.indexOf("//") + 2);
189 if (url.indexOf("/") > -1) {
190 url = url.substring(0, url.indexOf("/"));
191 }
192 }
193 this.url = url;
194 }
195
196
197
198
199
200
201
202
203
204
205
206
207 public CertificateValidationServiceResult validate(Certificate certificate,
208 Map<String, Object> extraParams) throws ServiceNotFoundException, ServiceException {
209
210 logger.debug("[AFirmaCertificateValidationService.validate]::Entrada::" + Arrays.asList(new Object[] { certificate, extraParams }));
211
212
213 ArangiServiceContent serviceContent = new ArangiServiceContent(url, user, password, configuracionWSS4J);
214
215 Map<String, Object> inParams = new HashMap<String, Object>();
216
217 inParams.put(DSSTagsRequest.CLAIMED_IDENTITY, this.idAplicacion);
218 inParams.put(DSSTagsRequest.INCLUDE_CERTIFICATE, "true");
219 inParams.put(DSSTagsRequest.INCLUDE_REVOCATION, "true");
220 inParams.put(DSSTagsRequest.REPORT_DETAIL_LEVEL, ReportDetailLevel.ALL_DETAILS);
221 inParams.put(DSSTagsRequest.CHECK_CERTIFICATE_STATUS, "true");
222 inParams.put(DSSTagsRequest.RETURN_READABLE_CERT_INFO, "");
223 try {
224 inParams.put(DSSTagsRequest.X509_CERTIFICATE, Util.encodeBase64(certificate.toDER()));
225 } catch (NormalizeCertificateException e) {
226
227 logger.info ("[AFirmaCertificateValidationService.validate]", e);
228 }
229
230 String xmlInput;
231 try {
232 xmlInput = TransformersFacade.getInstance().generateXml(inParams, GeneralConstants.DSS_AFIRMA_VERIFY_CERTIFICATE_REQUEST, GeneralConstants.DSS_AFIRMA_VERIFY_METHOD, TransformersConstants.VERSION_10);
233 } catch (TransformersException e) {
234 logger.info("No se puede crear la petición para @Firma", e);
235 throw new ServiceException("No se puede crear la petición para @Firma", e);
236 }
237 String xmlOutput;
238 try {
239 xmlOutput = Afirma5ServiceInvokerFacade.getInstance().invokeService(xmlInput, GeneralConstants.DSS_AFIRMA_VERIFY_CERTIFICATE_REQUEST, GeneralConstants.DSS_AFIRMA_VERIFY_METHOD, this.idAplicacion, serviceContent);
240 } catch (Exception e) {
241 logger.info("No se puede obtener la respuesta de @Firma", e);
242 throw new ServiceNotFoundException("No se puede obtener la respuesta de @Firma", e);
243 }
244
245 Map<String, Object> propertiesResult;
246 try {
247 propertiesResult = TransformersFacade.getInstance().parseResponse(xmlOutput, GeneralConstants.DSS_AFIRMA_VERIFY_CERTIFICATE_REQUEST, GeneralConstants.DSS_AFIRMA_VERIFY_METHOD, TransformersConstants.VERSION_10);
248 } catch (TransformersException e) {
249 logger.info("No se puede parsear la respuesta de @Firma", e);
250 throw new ServiceException("No se puede parsear la respuesta de @Firma", e);
251 }
252
253
254 String valorResultado = (String) propertiesResult.get(TransformersFacade.getInstance().getParserParameterValue("ResultMayor"));
255 String valorResultadoMenor = (String) propertiesResult.get(TransformersFacade.getInstance().getParserParameterValue("ResultMinor"));
256
257
258 int resultado = ValidationResult.RESULT_VALID;
259 Date fechaRevocacion = null;
260 BasicOCSPResp respuestaOCSP = null;
261 int motivoRevocacion = -1;
262
263 HashMap<String,Object>[] hmCertVal = (HashMap<String,Object>[]) propertiesResult.get("dss:OptionalOutputs/vr:CertificatePathValidity/vr:PathValidityDetail/vr:CertificateValidity");
264 HashMap<String,Object> camposCertificado = (HashMap<String,Object>) propertiesResult.get("dss:OptionalOutputs/afxp:ReadableCertificateInfo");
265
266
267 if (camposCertificado != null && hmCertVal != null) {
268 String numeroSerie = (String) camposCertificado.get("numeroSerie");
269 String issuer = (String) camposCertificado.get("idEmisor");
270 for (HashMap<String,Object> certVal : hmCertVal) {
271 if (certVal.get("dss:OptionalOutputs/vr:CertificatePathValidity/vr:PathValidityDetail/vr:CertificateValidity/vr:CertificateIdentifier/ds:X509IssuerName").equals(issuer) &&
272 certVal.get("dss:OptionalOutputs/vr:CertificatePathValidity/vr:PathValidityDetail/vr:CertificateValidity/vr:CertificateIdentifier/ds:X509SerialNumber").equals(numeroSerie)) {
273 String ocspResponseB64 = (String) certVal.get("dss:OptionalOutputs/vr:CertificatePathValidity/vr:PathValidityDetail/vr:CertificateValidity/vr:CertificateStatus/vr:RevocationEvidence/vr:OCSPValidity/OCSPValue");
274 if (ocspResponseB64 != null) {
275 try {
276 ASN1InputStream inp = new ASN1InputStream(Util.decodeBase64(ocspResponseB64));
277 BasicOCSPResponse basicResp = BasicOCSPResponse.getInstance(inp.readObject());
278 respuestaOCSP = new BasicOCSPResp(basicResp);
279 CertificateStatus status = respuestaOCSP.getResponses()[0].getCertStatus();
280 if (status instanceof RevokedStatus) {
281 RevokedStatus revokedStatus = (RevokedStatus) status;
282 fechaRevocacion = revokedStatus.getRevocationTime();
283 if (!revokedStatus.hasRevocationReason()) {
284 motivoRevocacion = -1;
285 } else {
286 motivoRevocacion = revokedStatus.getRevocationReason();
287 }
288 }
289 } catch (Exception e) {
290 logger.info("No se ha podido leer la respuesta OCSP", e);
291 }
292 } else {
293 logger.info("No existe la respuesta OCSP");
294 }
295 }
296 }
297 }
298
299 if (valorResultado.equals(ResultProcessIds.SUCESS)) {
300 if (valorResultadoMenor.equals(AFIRMA_MINOR_RESULT_CERTIFICATE_REVOKED)) {
301 resultado = ValidationResult.RESULT_CERTIFICATE_REVOKED;
302 }
303 } else {
304 logger.info("Resultado: " + propertiesResult.get(TransformersFacade.getInstance().getParserParameterValue("ResultMessage")));
305 if (valorResultado.equals(ResultProcessIds.REQUESTER_ERROR) && valorResultadoMenor.equals(AFIRMA_MINOR_RESULT_CERTIFICATE_NOT_SUPPORTED)) {
306 resultado = ValidationResult.RESULT_CERTIFICATE_NOT_BELONGS_TRUSTED_CAS;
307 } else {
308 resultado = ValidationResult.RESULT_INVALID;
309 }
310 }
311
312
313 CertificateValidationServiceResult certResult = new CertificateValidationServiceResult(resultado, camposCertificado);
314 if (fechaRevocacion != null) {
315 certResult.setRevocationDate(fechaRevocacion);
316 certResult.setRevocationReason(motivoRevocacion);
317 }
318 if (respuestaOCSP != null) {
319 try {
320 ASN1EncodableVector v1 = new ASN1EncodableVector();
321 v1.add(new ASN1Enumerated(0));
322
323 ASN1EncodableVector v2 = new ASN1EncodableVector();
324 ASN1ObjectIdentifier id = new ASN1ObjectIdentifier("1.3.6.1.5.5.7.48.1.1");
325 v2.add(id);
326 v2.add(new DEROctetString(DERSequence.fromByteArray(respuestaOCSP.getEncoded())));
327 DERTaggedObject tagged = new DERTaggedObject(true, 0, new DERSequence(v2));
328 v1.add(tagged);
329 DERSequence seq1 = new DERSequence(v1);
330
331 OCSPResp r = new OCSPResp(seq1.getEncoded());
332 OCSPResponse ocspResponse = new OCSPResponse(r);
333 certResult.setOcspResponse(ocspResponse);
334 } catch (Exception e) {
335 logger.info("No se ha podido construir la respuesta OCSP");
336 }
337 }
338
339
340 if (propertiesResult.get("dss:OptionalOutputs/vr:VerificationReport/vr:IndividualSignatureReport") != null) {
341 Map<String, Object> individualSignatureReport = ((Map<String, Object>[]) propertiesResult.get("dss:OptionalOutputs/vr:VerificationReport/vr:IndividualSignatureReport"))[0];
342 if (individualSignatureReport != null) {
343 Map<String, Object> certificateInfo = (Map<String, Object>) individualSignatureReport.get("dss:OptionalOutputs/vr:VerificationReport/vr:IndividualSignatureReport/vr:Details/afxp:ReadableCertificateInfo");
344 if (certificateInfo != null) {
345 try {
346 certResult.setCertificateCategory(Integer.parseInt((String)certificateInfo.get("clasificacion")));
347 } catch (Exception e) {
348 logger.info("La clasificación de certificado devuelta por @Firma no es un entero: " + certificateInfo.get("clasificacion"));
349 }
350 }
351 }
352 } else if (camposCertificado.get("clasificacion") != null) {
353 try {
354 certResult.setCertificateCategory(Integer.parseInt((String)camposCertificado.get("clasificacion")));
355 } catch (Exception e) {
356 logger.info("La clasificación de certificado devuelta por @Firma no es un entero: " + camposCertificado.get("clasificacion"));
357 }
358 }
359
360 return certResult;
361 }
362
363
364
365
366 public static boolean isEntidad(int clasificacion) {
367 return clasificacion == AFIRMA_CLASIFICACION_PERSONA_JURIDICA ||
368 clasificacion == AFIRMA_CLASIFICACION_ENTIDAD ||
369 clasificacion == AFIRMA_CLASIFICACION_CUALIFICADO_SELLO ||
370 clasificacion == AFIRMA_CLASIFICACION_REPRESENTANTE_CPJ ||
371 clasificacion == AFIRMA_CLASIFICACION_REPRESENTANTE_SPJ;
372 }
373
374
375
376
377 public static boolean isPersonaFisica(int clasificacion) {
378 return clasificacion == AFIRMA_CLASIFICACION_PERSONA_FISICA ||
379 clasificacion == AFIRMA_CLASIFICACION_EMPLEADO_PUBLICO ||
380 clasificacion == AFIRMA_CLASIFICACION_AUTENTICACION ||
381 clasificacion == AFIRMA_CLASIFICACION_REPRESENTANTE_CPJ ||
382 clasificacion == AFIRMA_CLASIFICACION_REPRESENTANTE_SPJ;
383 }
384
385
386
387
388
389
390
391
392
393 public class ArangiServiceContent implements Afirma5ServiceInvokerContent {
394
395 Properties afirmaProperties;
396
397 public ArangiServiceContent(String url, String user, String password,
398 String configuracionWSS4J) {
399 afirmaProperties = new Properties();
400 afirmaProperties.put("com.certificatesCache.use","true");
401 afirmaProperties.put("com.certificatesCache.entries","2");
402 afirmaProperties.put("com.certificatesCache.lifeTime","120");
403 afirmaProperties.put("secureMode", configuracionWSS4J==null?"false":"true");
404 afirmaProperties.put("endPoint", url);
405 afirmaProperties.put("servicePath", "afirmaws/services");
406 afirmaProperties.put("callTimeout", "20000");
407 if (configuracionWSS4J!=null) {
408 afirmaProperties.put("authorizationMethod", "BinarySecurityToken");
409 afirmaProperties.put("authorizationMethod.signaturePropFile", configuracionWSS4J);
410 } else if (user != null && password != null) {
411 afirmaProperties.put("authorizationMethod", "UsernameToken");
412 afirmaProperties.put("authorizationMethod.user", user);
413 afirmaProperties.put("authorizationMethod.password", password);
414 } else {
415 afirmaProperties.put("authorizationMethod", "none");
416 }
417 afirmaProperties.put("response.validate", "false");
418 afirmaProperties.put("response.certificateAlias", "DefaultFirma");
419 }
420
421 public long getLastModified() {
422 return new Date().getTime();
423 }
424
425 public Properties getProperties() throws Exception {
426 return afirmaProperties;
427 }
428
429 }
430
431 }