source: murachi/murachi/src/main/java/ve/gob/cenditel/murachi/MurachiRESTWS.java @ 8e7e007

Last change on this file since 8e7e007 was 8e7e007, checked in by antonioaraujob <aaraujo@…>, 9 years ago

Cambio en el mapeo de url del servicio: de /Murachi/murachi/archivos a /Murachi/0.1/archivos para mantener la versión del servicio en la url. Corrección de error en verificación de archivos PDF firmados con certificados que ya expiraron; ahora se obtiene la información de la verificación con algunos campos que identifican el estado que invalida un certificado firmante.

  • Property mode set to 100644
File size: 80.6 KB
Line 
1package ve.gob.cenditel.murachi;
2
3import static java.util.Arrays.asList;
4
5import java.io.BufferedReader;
6import java.io.ByteArrayInputStream;
7import java.io.ByteArrayOutputStream;
8import java.io.File;
9import java.io.FileInputStream;
10import java.io.FileOutputStream;
11import java.io.IOException;
12import java.io.InputStream;
13import java.io.InputStreamReader;
14import java.io.ObjectInputStream;
15import java.io.ObjectOutputStream;
16import java.io.OutputStream;
17import java.net.URISyntaxException;
18import java.net.URL;
19import java.nio.file.Files;
20import java.nio.file.Paths;
21import java.security.GeneralSecurityException;
22import java.security.InvalidKeyException;
23import java.security.KeyStore;
24import java.security.KeyStoreException;
25import java.security.MessageDigest;
26import java.security.NoSuchAlgorithmException;
27import java.security.NoSuchProviderException;
28import java.security.Security;
29import java.security.cert.Certificate;
30import java.security.cert.CertificateException;
31import java.security.cert.CertificateExpiredException;
32import java.security.cert.CertificateFactory;
33import java.security.cert.CertificateNotYetValidException;
34import java.security.cert.X509Certificate;
35import java.util.ArrayList;
36import java.util.Calendar;
37import java.util.Date;
38import java.util.HashMap;
39import java.util.List;
40import java.util.Map.Entry;
41import java.util.UUID;
42import java.text.DateFormat;
43import java.text.NumberFormat;
44import java.text.SimpleDateFormat;
45
46import javax.ws.rs.Consumes;
47import javax.ws.rs.FormParam;
48import javax.ws.rs.GET;
49import javax.ws.rs.POST;
50import javax.ws.rs.Path;
51import javax.ws.rs.PathParam;
52import javax.ws.rs.Produces;
53import javax.ws.rs.core.Context;
54import javax.ws.rs.core.HttpHeaders;
55import javax.ws.rs.core.MediaType;
56import javax.ws.rs.core.Response;
57import javax.ws.rs.core.Response.ResponseBuilder;
58
59import org.bouncycastle.jce.provider.BouncyCastleProvider;
60import org.bouncycastle.tsp.TimeStampToken;
61import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
62import org.glassfish.jersey.media.multipart.FormDataParam;
63import org.json.JSONArray;
64import org.json.JSONObject;
65
66import com.itextpdf.text.DocumentException;
67import com.itextpdf.text.Rectangle;
68import com.itextpdf.text.exceptions.InvalidPdfException;
69import com.itextpdf.text.pdf.AcroFields;
70import com.itextpdf.text.pdf.PdfDate;
71import com.itextpdf.text.pdf.PdfDictionary;
72import com.itextpdf.text.pdf.PdfName;
73import com.itextpdf.text.pdf.PdfReader;
74import com.itextpdf.text.pdf.PdfSignature;
75import com.itextpdf.text.pdf.PdfSignatureAppearance;
76import com.itextpdf.text.pdf.PdfStamper;
77import com.itextpdf.text.pdf.PdfString;
78import com.itextpdf.text.pdf.security.CertificateInfo;
79import com.itextpdf.text.pdf.security.CertificateVerification;
80import com.itextpdf.text.pdf.security.DigestAlgorithms;
81import com.itextpdf.text.pdf.security.ExternalDigest;
82import com.itextpdf.text.pdf.security.PdfPKCS7;
83import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
84import com.itextpdf.text.pdf.security.SignaturePermissions;
85import com.itextpdf.text.pdf.security.VerificationException;
86
87import ee.sk.digidoc.CertValue;
88import ee.sk.digidoc.DigiDocException;
89import ee.sk.digidoc.SignedDoc;
90import ee.sk.digidoc.factory.DigiDocGenFactory;
91
92import javax.servlet.http.HttpServletRequest;
93import javax.servlet.http.HttpServletResponse;
94import javax.servlet.http.HttpSession;
95
96import org.digidoc4j.Configuration;
97import org.digidoc4j.Container;
98import org.digidoc4j.Container.DocumentType;
99import org.digidoc4j.DataFile;
100import org.digidoc4j.Signature;
101import org.digidoc4j.SignatureParameters;
102import org.digidoc4j.SignatureProductionPlace;
103import org.digidoc4j.SignedInfo;
104import org.digidoc4j.ValidationResult;
105import org.digidoc4j.Container.SignatureProfile;
106import org.digidoc4j.X509Cert;
107import org.digidoc4j.exceptions.DigiDoc4JException;
108import org.digidoc4j.exceptions.SignatureNotFoundException;
109import org.digidoc4j.impl.DDocContainer;
110import org.digidoc4j.impl.DDocSignature;
111import org.digidoc4j.impl.ValidationResultForDDoc;
112import org.digidoc4j.signers.PKCS12Signer;
113
114import ve.gob.cenditel.murachi.MurachiException;
115
116import org.apache.log4j.Logger;
117
118@Path("/archivos")
119public class MurachiRESTWS {
120       
121        final static Logger logger = Logger.getLogger(MurachiRESTWS.class);
122       
123        private static final String API_VERSION = "0.1.0";
124       
125        private static final String SERVER_UPLOAD_LOCATION_FOLDER = "/tmp/";   
126       
127        private static final String SHA256_MESSAGE_DIGEST = "SHA256";
128       
129        private static final String RSA_DIGEST_ENCRYPTION_ALGORITHM = "RSA";
130       
131        // para reportes de advertencias de BDOC
132        private static boolean bdocWarnings = true;
133       
134        // para reportes en modo verbose de BDOC
135        private static boolean bdocVerboseMode = true;
136
137        /**
138         * Retorna la ruta absoluta de un archivo recurso
139         * @param resource cadena con el nombre del archivo
140         * @return ruta absoluta de un archivo recurso
141         */
142        String getAbsolutePathOfResource(String resource) {
143                ClassLoader classLoader = getClass().getClassLoader();
144                File file = new File(classLoader.getResource(resource).getFile());
145                logger.debug("archivo recurso solicitado: "+ resource +" path abosulto: " + file.getAbsolutePath());
146                return file.getAbsolutePath();         
147        }
148       
149       
150        /**
151         * Retorna la version del api del servicio
152         * @return version del api del servicio
153         * @throws URISyntaxException
154         */
155        @Path("/version")
156        @GET
157        @Produces(MediaType.TEXT_HTML)
158        public String returnVersion() {
159                logger.info("/version: Murachi Version: " + API_VERSION);               
160                return "<p>Murachi Version: " + API_VERSION + "</p>";
161        }
162               
163        /**
164         * Carga un archivo pasado a través de un formulario y retorna
165         * un json con el id del archivo en el servidor para futuras consultas
166         * de estado de firmas
167         * @param uploadedInputStream stream para obtener el archivo
168         * @param fileDetails datos del archivo
169         * @return
170         * @throws MurachiException
171         */     
172        @POST
173        @Path("/")
174        @Consumes(MediaType.MULTIPART_FORM_DATA)
175        @Produces(MediaType.APPLICATION_JSON)
176        public Response uploadFile(
177                        @FormDataParam("upload") InputStream uploadedInputStream,
178                        @FormDataParam("upload") FormDataContentDisposition fileDetails) throws MurachiException {
179               
180                logger.info("/: uploadFile");
181               
182                if (uploadedInputStream == null) {
183                        System.out.println("uploadedInputStream == null");
184                        logger.error("uploadedInputStream != null. datos recibidos del formulario son nulos.");
185                        throw new MurachiException("uploadedInputStream != null. datos recibidos del formulario son nulos.");
186                }
187               
188                if (fileDetails == null) {
189                        System.out.println("fileDetails == null");
190                        logger.error("fileDetails == null. datos recibidos del formulario son nulos.");
191                        throw new MurachiException("fileDetails == null. datos recibidos del formulario son nulos.");
192                }
193                               
194                String fileId = UUID.randomUUID().toString();
195                System.out.println(fileId);
196               
197                saveToDisk(uploadedInputStream, fileDetails, fileId);
198               
199                try {
200                        uploadedInputStream.close();
201                } catch (IOException e) {
202                        logger.error("Ocurrio una excepcion: ", e);
203                        e.printStackTrace();
204                        throw new MurachiException(e.getMessage());
205                }
206               
207                JSONObject jsonObject = new JSONObject();
208                jsonObject.put("fileId", fileId);
209               
210                System.out.println("File saved to server location : " + SERVER_UPLOAD_LOCATION_FOLDER + fileId);
211                String result = jsonObject.toString();
212                logger.info("/: " + result);
213               
214                return Response.status(200).entity(result).build();
215        }
216
217        /**
218         * Descarga un archivo existente en el servidor
219         * @param fileName nombre (identificador) del archivo que se desea descargar
220         * @return archivo existente en el servidor y pasado como argumento
221         */
222        @GET
223        @Path("/descargas/{filename}")
224        @Produces(MediaType.APPLICATION_OCTET_STREAM)
225        public Response downloadFilebyPath(@PathParam("filename")  String fileName) {
226                logger.info("/descargas/{"+fileName+"}");
227                return downloadFileFromServer(fileName);
228        }
229       
230        /**
231         * Descarga un archivo pasado como argumento del servidor
232         * @param fileName nombre o identificador del archivo que se desea descargar
233         * @return archivo pasado como argumento del servidor
234         */
235        private Response downloadFileFromServer(String fileName) {   
236            String fileLocation = SERVER_UPLOAD_LOCATION_FOLDER + fileName;
237            Response response = null;
238            NumberFormat myFormat = NumberFormat.getInstance();
239              myFormat.setGroupingUsed(true);
240             
241            // Retrieve the file
242            File file = new File(SERVER_UPLOAD_LOCATION_FOLDER + fileName);
243            if (file.exists()) {
244                ResponseBuilder builder = Response.ok(file);
245                builder.header("Content-Disposition", "attachment; filename=" + file.getName());
246                response = builder.build();
247               
248                long file_size = file.length();
249                logger.info(String.format("Inside downloadFile==> fileName: %s, fileSize: %s bytes",
250                                fileName, myFormat.format(file_size)));
251            } else {
252                logger.error(String.format("Inside downloadFile==> FILE NOT FOUND: fileName: %s",
253                                fileName));
254               
255                //response = Response.status(404).entity("{\"fileExist\": " + /*fileLocation*/ fileName + "}").
256                //              type("text/plain").build();
257               
258                response = Response.status(404).entity("{\"fileExist\": false}").
259                                type("text/plain").build();
260            }
261             
262            return response;
263          }
264       
265       
266        /**
267         * Carga un archivo pasado a través de un formulario y retorna
268         * un json con la informacion de la(s) firma(s) del archivo
269         * en caso de que este firmado
270         *
271         * @param uploadedInputStream stream para obtener el archivo
272         * @param fileDetails datos del archivo
273         * @return
274         * @throws MurachiException
275         */
276        @POST
277        @Path("/firmados")
278        @Consumes(MediaType.MULTIPART_FORM_DATA)
279        @Produces(MediaType.APPLICATION_JSON)
280        public Response uploadFileAndVerify(
281                        @FormDataParam("upload") InputStream uploadedInputStream,
282                        @FormDataParam("upload") FormDataContentDisposition fileDetails) throws MurachiException {
283               
284                logger.info("/firmados: uploadFileAndVerify");
285               
286                if (uploadedInputStream == null) {
287                        System.out.println("uploadedInputStream == null");
288                        logger.error("uploadedInputStream != null. datos recibidos del formulario son nulos.");
289                        throw new MurachiException("uploadedInputStream != null. datos recibidos del formulario son nulos.");
290                }
291               
292                if (fileDetails == null) {
293                        System.out.println("fileDetails == null");
294                        logger.error("fileDetails == null. datos recibidos del formulario son nulos.");
295                        throw new MurachiException("fileDetails == null. datos recibidos del formulario son nulos.");
296                }
297                               
298                String fileId = UUID.randomUUID().toString();
299                System.out.println(fileId);
300               
301                saveToDisk(uploadedInputStream, fileDetails, fileId);
302               
303                try {
304                        uploadedInputStream.close();
305                } catch (IOException e) {
306                        logger.error("Ocurrio una excepcion: ", e);
307                        e.printStackTrace();
308                        throw new MurachiException(e.getMessage());
309                }
310               
311                System.out.println("File saved to server location : " + SERVER_UPLOAD_LOCATION_FOLDER + fileId);
312               
313                JSONObject jsonObject = new JSONObject();
314                                       
315                jsonObject = verifyALocalFile(fileId);
316                logger.info("/firmados: " + jsonObject.toString());
317               
318                return Response.status(200).entity(jsonObject.toString()).build();
319        }
320       
321        /**
322         * Escribe un archivo en el sistema de archivos
323         * @param uploadedInputStream
324         * @param fileDetails
325         * @param fileId identificador unico del archivo de acuerdo a UUIDs
326         * @throws MurachiException
327         */
328        private void saveToDisk(InputStream uploadedInputStream, FormDataContentDisposition fileDetails, String fileId) throws MurachiException {
329               
330                String uploadedFileLocation = SERVER_UPLOAD_LOCATION_FOLDER + /*fileDetails.getFileName()*/ fileId;
331               
332                System.out.println("uploadedFileLocation: " + uploadedFileLocation);
333                logger.debug("uploadedFileLocation: " + uploadedFileLocation);
334               
335                try {
336                        OutputStream out = new FileOutputStream(new File(uploadedFileLocation));
337                        int read = 0;
338                        byte[] bytes = new byte[1024];
339                       
340                        out = new FileOutputStream(new File(uploadedFileLocation));
341                        while ((read = uploadedInputStream.read(bytes)) != -1) {
342                                out.write(bytes, 0, read);
343                               
344                        }
345                        out.flush();
346                        out.close();
347                }
348                catch(IOException e) {
349                        logger.error("saveToDisk: ocurrio una excepcion", e);
350                        e.printStackTrace();
351                        throw new MurachiException(e.getMessage());
352                }
353        }
354       
355       
356        /**
357         * Verifica si un archivo posee firmas electronicas y retorna informacion
358         * de las mismas en un json
359         * @param idFile identificador del archivo a verificar
360         * @return JSON con informacion de las firmas
361         * @throws MurachiException
362         */
363        @GET
364        @Path("/{idFile}")
365        @Produces("application/json")
366        public Response verifyAFile(@PathParam("idFile") String idFile) throws MurachiException {
367
368                System.out.println("/{idFile}");
369                logger.info("/{"+idFile+"}");
370               
371                String file = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
372               
373                File tmpFile = new File(file);
374               
375                JSONObject jsonObject = new JSONObject();
376               
377                if (!tmpFile.exists()) {
378                        System.out.println("File : " + file + " does not exists.");
379                        jsonObject.put("fileExist", "false");
380                        logger.debug("fileExist: false");
381                       
382                }else{
383                        System.out.println("File : " + file + " exists.");
384                        jsonObject.put("fileExist", "true");
385                       
386                        String mime = getMimeType(file);
387                        System.out.println("mimetype : " + mime);
388                       
389                        if (mime.equals("application/pdf")){
390                                System.out.println(" PDF ");
391                               
392                                jsonObject = verifySignaturesInPdf(file);
393                               
394                        //}else if (mime.equals("application/vnd.etsi.asic-e+zip")){
395                        }else if (mime.equals("application/zip") ){
396                                System.out.println("BDOC");                             
397                                //jsonObject.put("formato", "BDOC");
398                                //jsonObject.put("resultado", "NO IMPLEMENTADO");
399                               
400                                jsonObject = verifySignaturesInBdoc(file);
401                        }else{
402                                System.out.println("extension no reconocida");
403                                jsonObject.put("fileExist", "true");
404                                jsonObject.put("error", "extension not supported");
405                                logger.debug("error: extension not supported");
406                        }
407                }
408                String result = jsonObject.toString();
409                logger.info("/{"+idFile+"}: result");
410                return Response.status(200).entity(result).build();
411                               
412        }
413       
414        /**
415         * Verifica si un archivo local posee firmas electronicas y retorna informacion
416         * de las mismas en un json.
417         *
418         * @param idFile identificador del archivo a verificar
419         * @return JSONObject con informacion de las firmas
420         * @throws MurachiException
421         */
422        public JSONObject verifyALocalFile(String idFile) throws MurachiException {
423               
424                System.out.println("verifyALocalFile: " + idFile);
425                logger.debug("verifyALocalFile: " + idFile);
426               
427                String file = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
428               
429                File tmpFile = new File(file);
430               
431                JSONObject jsonObject = new JSONObject();
432               
433                if (!tmpFile.exists()) {
434                        System.out.println("File : " + file + " does not exists.");
435                        jsonObject.put("fileExist", "false");
436                        logger.debug("fileExist: false");
437                       
438                }else{
439                        System.out.println("File : " + file + " exists.");
440                        jsonObject.put("fileExist", "true");
441                       
442                        String mime = getMimeType(file);
443                        System.out.println("mimetype : " + mime);
444                       
445                        if (mime.equals("application/pdf")){
446                                System.out.println(" PDF ");
447                               
448                                jsonObject = verifySignaturesInPdf(file);
449                               
450                        //}else if (mime.equals("application/vnd.etsi.asic-e+zip")){
451                        }else if (mime.equals("application/zip") ){
452                                System.out.println("BDOC");                             
453                                //jsonObject.put("formato", "BDOC");
454                                //jsonObject.put("resultado", "NO IMPLEMENTADO");
455                               
456                                jsonObject = verifySignaturesInBdoc(file);
457                        }else{
458                                System.out.println("extension no reconocida");
459                                jsonObject.put("fileExist", "true");
460                                jsonObject.put("error", "extension not supported");     
461                                logger.debug("error: extension not supported");
462                        }
463                }
464                return jsonObject;
465        }
466       
467       
468        /**
469         * Retorna un JSON con informacion de las firmas del documento PDF
470         * @param pdfFile archivo pdf a verificar
471         * @return JSON con informacion de las firmas del documento PDF
472         * @throws MurachiException
473         */
474        private JSONObject verifySignaturesInPdf(String pdfFile) throws MurachiException {
475               
476                logger.debug("verifySignaturesInPdf: "+ pdfFile);
477               
478                JSONObject jsonSignatures = new JSONObject();
479                JSONArray jsonArray = new JSONArray();
480               
481                try {
482                       
483                        Security.addProvider(new BouncyCastleProvider());
484                       
485                        PdfReader reader = new PdfReader(pdfFile);
486                        AcroFields af = reader.getAcroFields();
487                        ArrayList<String> names = af.getSignatureNames();
488                        if (names.size() <= 0) {
489                                jsonSignatures.put("signatureNumber", "0");
490                        }else{
491                               
492                                jsonSignatures.put("fileExist", "true");
493                                jsonSignatures.put("numberOfSignatures", names.size());
494                                                               
495                                HashMap<String, String> signatureInformation;
496                               
497                                // inicializar el keystore para verificacion
498                                KeyStore ks = setupKeyStore();
499                               
500                                for (String name : names) {
501                                        System.out.println("===== " + name + " =====");
502                                        signatureInformation = verifySignature(af, name, ks);
503                                        System.out.println("signatureInformation.size " + signatureInformation.size());
504                                       
505                                        JSONObject jo = getJSONFromASignature(signatureInformation);
506                                        System.out.println("jo:  " + jo.toString());
507                                        jsonArray.put(jo);
508                                }       
509                                jsonSignatures.put("signatures", jsonArray);
510                                System.out.println("jsonSignatures :  " + jsonSignatures.toString());
511                               
512                        }
513                       
514                } catch (IOException e) {
515                        logger.error("verifySignaturesInPdf ocurrio una excepcion", e);
516                        e.printStackTrace();
517                        throw new MurachiException(e.getMessage());
518                } catch (GeneralSecurityException e) {
519                        logger.error("verifySignaturesInPdf ocurrio una excepcion", e);
520                        e.printStackTrace();
521                        throw new MurachiException(e.getMessage());
522                }
523                               
524                return jsonSignatures;         
525        }
526       
527        /**
528         * Chequea la integridad de una revision basada en una firma electronica
529         * @param fields Campos
530         * @param name nombre de la firma
531         * @return HashMap con campos de informacion de la firma electronica
532         * @throws GeneralSecurityException falla en
533         * @throws IOException cuando ca
534         * @throws MurachiException
535         */
536        public HashMap<String, String> verifySignature(AcroFields fields, String name, KeyStore ks) 
537                        throws GeneralSecurityException, IOException, MurachiException {
538                       
539                logger.debug("verifySignature()");
540                HashMap<String, String> integrityMap = new HashMap<String, String>();
541               
542                System.out.println("Signature covers whole document: " + fields.signatureCoversWholeDocument(name));
543               
544                integrityMap.put("signatureCoversWholeDocument", Boolean.toString(fields.signatureCoversWholeDocument(name)));
545               
546                int revision = fields.getRevision(name);
547                System.out.println("Document revision: " + fields.getRevision(name) + " of " + fields.getTotalRevisions());             
548                integrityMap.put("documentRevision", Integer.toString(fields.getRevision(name)));
549               
550                System.out.println("Total Document revisions: " + fields.getTotalRevisions());
551                integrityMap.put("totalDocumentRevisions",  Integer.toString(fields.getTotalRevisions()));
552                               
553                PdfPKCS7 pkcs7 = fields.verifySignature(name);
554        System.out.println("Integrity check OK? " + pkcs7.verify());
555        integrityMap.put("integrityCheck", Boolean.toString(pkcs7.verify()));
556       
557        System.out.println("Digest Algorithm: " + pkcs7.getHashAlgorithm());
558        integrityMap.put("digestAlgorithm", pkcs7.getHashAlgorithm());
559       
560        System.out.println("Encryption Algorithm: " + pkcs7.getEncryptionAlgorithm());
561        integrityMap.put("encryptionAlgorithm", pkcs7.getEncryptionAlgorithm());
562       
563        System.out.println("Filter subtype: " + pkcs7.getFilterSubtype());
564        integrityMap.put("filterSubtype", pkcs7.getFilterSubtype().toString());
565       
566        X509Certificate cert = (X509Certificate) pkcs7.getSigningCertificate();
567                System.out.println("Name of the signer: " + CertificateInfo.getSubjectFields(cert).getField("CN"));
568                integrityMap.put("nameOfTheSigner", CertificateInfo.getSubjectFields(cert).getField("CN"));
569       
570                if (pkcs7.getSignName() != null){
571                        System.out.println("Alternative name of the signer: " + pkcs7.getSignName());
572                        integrityMap.put("alternativeNameOfTheSigner", pkcs7.getSignName());                   
573                }else{
574                        System.out.println("Alternative name of the signer: " + "null");
575                        integrityMap.put("alternativeNameOfTheSigner", "");
576                }
577               
578                SimpleDateFormat date_format = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss.SS");
579                System.out.println("Signed on: " + date_format.format(pkcs7.getSignDate().getTime()));
580                integrityMap.put("signedOn", date_format.format(pkcs7.getSignDate().getTime()).toString());
581               
582                if (pkcs7.getTimeStampDate() != null) {
583                        System.out.println("TimeStamp: " + date_format.format(pkcs7.getTimeStampDate().getTime()));
584                        integrityMap.put("timeStamp", date_format.format(pkcs7.getTimeStampDate().getTime()).toString());
585                        TimeStampToken ts = pkcs7.getTimeStampToken();
586                        System.out.println("TimeStamp service: " + ts.getTimeStampInfo().getTsa());
587                        integrityMap.put("timeStampService", ts.getTimeStampInfo().getTsa().toString());
588                        System.out.println("Timestamp verified? " + pkcs7.verifyTimestampImprint());
589                        integrityMap.put("timeStampVerified", Boolean.toString(pkcs7.verifyTimestampImprint()));
590                }else{
591                        System.out.println("TimeStamp: " + "null");
592                        integrityMap.put("timeStamp", "null");
593                       
594                        System.out.println("TimeStamp service: " + "null");
595                        integrityMap.put("timeStampService", "null");
596                       
597                        System.out.println("Timestamp verified?: " + "null");
598                        integrityMap.put("timeStampVerified", "null");
599                }
600               
601                System.out.println("Location: " + pkcs7.getLocation());
602                integrityMap.put("location", pkcs7.getLocation());             
603               
604                System.out.println("Reason: " + pkcs7.getReason());
605                integrityMap.put("reason", pkcs7.getReason());
606               
607                PdfDictionary sigDict = fields.getSignatureDictionary(name);
608                PdfString contact = sigDict.getAsString(PdfName.CONTACTINFO);
609                if (contact != null){
610                        System.out.println("Contact info: " + contact);
611                        integrityMap.put("contactInfo", contact.toString());                   
612                }else{
613                        System.out.println("Contact info: " + "null");
614                        integrityMap.put("contactInfo", "null");
615                }
616                       
617                SignaturePermissions perms = null;
618                perms = new SignaturePermissions(sigDict, perms);
619                System.out.println("Signature type: " + (perms.isCertification() ? "certification" : "approval"));
620                integrityMap.put("signatureType", (perms.isCertification() ? "certification" : "approval"));
621               
622               
623                //KeyStore ks = setupKeyStore();
624               
625                Certificate[] certs = pkcs7.getSignCertificateChain();
626                Calendar cal = pkcs7.getSignDate();
627                List<VerificationException> errors = CertificateVerification.verifyCertificates(certs, ks, cal);
628                if (errors.size() == 0){               
629                        System.out.println("Certificates verified against the KeyStore");
630                        integrityMap.put("certificatesVerifiedAgainstTheKeyStore", "true");
631                }
632                else{
633                        System.out.println(errors);
634                        integrityMap.put("certificatesVerifiedAgainstTheKeyStore", "false");
635                }
636               
637               
638                X509Certificate certificateTmp = (X509Certificate) certs[0];
639                System.out.println("=== Certificate " + Integer.toString(revision) + " ===");
640
641                HashMap<String, String> signerCertificateMap = getSignerCertificateInfo(certificateTmp, cal.getTime());
642                for (Entry<String, String> entry : signerCertificateMap.entrySet()) {
643                        integrityMap.put(entry.getKey(), entry.getValue());
644                }
645               
646                return integrityMap;
647        }
648       
649        /**
650         * Construye un objeto JSON a partir del HashMap pasado como argumento
651         * @param hashMap HashMap que contiene los elementos para construir el JSON
652         * @return objeto JSON a partir del HashMap pasado como argumento
653         */
654        public JSONObject getJSONFromASignature(HashMap<String, String> hashMap) {
655               
656                logger.debug("getJSONFromASignature()");
657                JSONObject jsonSignature = new JSONObject();
658               
659                for (Entry<String, String> entry : hashMap.entrySet()) {
660                    System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
661                    jsonSignature.put(entry.getKey(), entry.getValue());
662                }               
663                return jsonSignature;           
664        }
665       
666        /**
667         * Carga el KeyStore con certificados confiables para la verificacion de certificados
668         * de firmas
669         * @return KeyStore con certificados confiables
670         * @throws MurachiException
671         */
672        private KeyStore setupKeyStore() throws MurachiException {
673                logger.debug("setupKeyStore()");
674                KeyStore ks = null;
675                try {
676                        ks = KeyStore.getInstance(KeyStore.getDefaultType());
677                       
678                        ks.load(null, null);
679                        CertificateFactory cf = CertificateFactory.getInstance("X.509");
680                        ks.setCertificateEntry("acraiz",
681                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("CERTIFICADO-RAIZ-SHA384.crt"))));
682                        ks.setCertificateEntry("pscfii", 
683                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("PSCFII-SHA256.crt"))));                   
684                        ks.setCertificateEntry("procert", 
685                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("PSC-PROCERT-SHA256.crt"))));                     
686                        ks.setCertificateEntry("altosfuncionarios", 
687                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("ACALTOS-FUNCIONARIOS-SHA256.crt"))));                     
688                        ks.setCertificateEntry("acsubordinadafundayacucho", 
689                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("ACSUBORDINADA-FUNDAYACUCHO.crt"))));                     
690                        ks.setCertificateEntry("gidsi", 
691                                        cf.generateCertificate(new FileInputStream(getAbsolutePathOfResource("GIDSI.crt"))));
692                                               
693                } catch (KeyStoreException e) { 
694                        logger.error("setupKeyStore() ocurrio una excepcion", e);
695                        e.printStackTrace();
696                        throw new MurachiException(e.getMessage());
697                } catch (NoSuchAlgorithmException e) {
698                        logger.error("setupKeyStore() ocurrio una excepcion", e);
699                        e.printStackTrace();
700                        throw new MurachiException(e.getMessage());
701                } catch (CertificateException e) {
702                        logger.error("setupKeyStore() ocurrio una excepcion", e);
703                        e.printStackTrace();
704                        throw new MurachiException(e.getMessage());
705                } catch (IOException e) {
706                        logger.error("setupKeyStore() ocurrio una excepcion", e);
707                        e.printStackTrace();
708                        throw new MurachiException(e.getMessage());
709                }               
710                return ks;
711        }
712       
713        /**
714         * Obtiene informacion del certificado firmante de una revision
715         * @param cert certificado firmante
716         * @param signDate fecha en que se realizo la firma
717         * @return informacion del certificado firmante de una revision en forma de HashMap
718         * @throws MurachiException
719         */
720        public HashMap<String, String> getSignerCertificateInfo(X509Certificate cert, Date signDate) throws MurachiException {
721                logger.debug("getSignerCertificateInfo()");
722                HashMap<String, String> signerCertificateMap = new HashMap<String, String>();
723               
724                System.out.println("Issuer: " + cert.getIssuerDN());
725                signerCertificateMap.put("signerCertificateIssuer", cert.getIssuerDN().toString());
726               
727               
728                System.out.println("Subject: " + cert.getSubjectDN());
729                signerCertificateMap.put("signerCertificateSubject", cert.getSubjectDN().toString());
730               
731                SimpleDateFormat date_format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS");
732                System.out.println("Valid from: " + date_format.format(cert.getNotBefore()));
733                signerCertificateMap.put("signerCertificateValidFrom", date_format.format(cert.getNotBefore()).toString());
734               
735                System.out.println("Valid to: " + date_format.format(cert.getNotAfter()));
736                signerCertificateMap.put("signerCertificateValidTo", date_format.format(cert.getNotAfter()).toString());
737               
738                try {
739                        cert.checkValidity(signDate);
740                        System.out
741                                        .println("The certificate was valid at the time of signing.");
742                        signerCertificateMap.put("signerCertificateValidAtTimeOfSigning", "true");
743                } catch (CertificateExpiredException e) {
744                        System.out
745                                        .println("The certificate was expired at the time of signing.");
746                       
747                        signerCertificateMap.put("signerCertificateValidAtTimeOfSigning", "false");
748                       
749                        signerCertificateMap.put("signerCertificateExpiredAtTimeOfSigning", "true");
750                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate was expired at the time of signing");
751                        //throw new MurachiException(e.getMessage());
752                } catch (CertificateNotYetValidException e) {
753                        System.out
754                                        .println("The certificate wasn't valid yet at the time of signing.");
755                       
756                        signerCertificateMap.put("signerCertificateValidAtTimeOfSigning", "false");
757                       
758                        signerCertificateMap.put("signerCertificateNotValidYetAtTimeOfSigning", "true");
759                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate wasn't valid yet at the time of signing");
760                        //throw new MurachiException(e.getMessage());
761                }
762                try {
763                        cert.checkValidity();
764                        System.out.println("The certificate is still valid.");
765                        signerCertificateMap.put("signerCertificateStillValid", "true");
766                } catch (CertificateExpiredException e) {
767                        System.out.println("The certificate has expired.");
768                       
769                        signerCertificateMap.put("signerCertificateStillValid", "false");
770                       
771                        signerCertificateMap.put("signerCertificateHasExpired", "true");
772                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate has expired");
773                        //throw new MurachiException(e.getMessage());
774                } catch (CertificateNotYetValidException e) {
775                        System.out.println("The certificate isn't valid yet.");
776                       
777                        signerCertificateMap.put("signerCertificateStillValid", "false");
778                       
779                        signerCertificateMap.put("signerCertificateNotValidYet", "true");
780                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate isn't valid yet");
781                        //throw new MurachiException(e.getMessage());
782                }
783                return signerCertificateMap;
784        }
785       
786       
787        /**
788         * Ejecuta el proceso de presign o preparacion de firma de documento pdf.
789         *
790         * Estructura del JSON que recibe la funcion:
791         *
792         *      {"fileId":"file_id",                           
793         *      "certificate":"hex_cert_value",
794         *  "reason":"reason",
795         *  "location":"location",
796         *  "contact":"contact"
797         *  }
798         *
799         *
800         * @param presignPar JSON con los parametros de preparacion: Id del archivo y certificado
801         * firmante
802         * @param req objeto request para crear una sesion y mantener elementos del
803         * pdf en la misma.
804         * @throws MurachiException
805         *
806         */
807        @POST
808        @Path("/pdfs")
809        @Consumes(MediaType.APPLICATION_JSON)
810        @Produces(MediaType.APPLICATION_JSON)
811        //public PresignHash presignPdf(PresignParameters presignPar, @Context HttpServletRequest req) {
812        public Response presignPdf(PresignParameters presignPar, @Context HttpServletRequest req) throws MurachiException {
813               
814                logger.info("/pdfs");
815               
816                PresignHash presignHash = new PresignHash();
817
818                // obtener el id del archivo
819                String fileId = presignPar.getFileId();
820               
821                // cadena con el certificado
822                String certHex = presignPar.getCertificate();
823                System.out.println("certificado en Hex: " + certHex);
824
825                String reason = presignPar.getReason();
826               
827                String location = presignPar.getLocation();
828               
829                String contact = presignPar.getContact();
830               
831               
832                String pdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId;
833                System.out.println("archivo a firmar: " + pdf);
834                logger.debug("archivo a firmar: " + pdf);
835               
836                String mime = getMimeType(pdf);
837               
838                if (!mime.equals("application/pdf")){
839                        presignHash.setError("El archivo que desea firmar no es un PDF.");
840                        presignHash.setHash("");
841                        //return presignHash;
842                                                                       
843                        //result = presignHash.toString();
844                        logger.info("El archivo que desea firmar no es un PDF.");
845                        return Response.status(400).entity(presignHash).build();
846                       
847                }
848                       
849                               
850                try {
851                        CertificateFactory factory = CertificateFactory.getInstance("X.509");
852                        Certificate[] chain = new Certificate[1];
853                       
854                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
855                        chain[0] = factory.generateCertificate(in);
856                       
857                        if (chain[0] == null) {
858                                System.out.println("error chain[0] == null");
859                                logger.error("presignPdf: error en carga de certificado de firmante");
860                                throw new MurachiException("presignPdf: error en carga de certificado de firmante");
861                        }else {
862                               
863                                System.out.println("se cargo el certificado correctamente");
864                                System.out.println(chain[0].toString());
865                                logger.debug("se cargo el certificado correctamente");
866                                logger.debug(chain[0].toString());
867                        }                       
868                       
869                        PdfReader reader = new PdfReader(pdf);                 
870                       
871                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
872                       
873                        //PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
874                        PdfStamper stamper = null;
875                       
876                       
877                        if (pdfAlreadySigned(reader)){
878                                stamper = PdfStamper.createSignature(reader, baos, '\0', null, true);
879                        }else{
880                                stamper = PdfStamper.createSignature(reader, baos, '\0');
881                        }
882
883                        // crear la apariencia de la firma
884                PdfSignatureAppearance sap = stamper.getSignatureAppearance();
885                               
886                sap.setReason(reason);
887                sap.setLocation(location);
888                sap.setContact(contact);
889               
890                //sap.setVisibleSignature(new Rectangle(36, 748, 144,780),1, "sig");
891               
892                if (!pdfAlreadySigned(reader)){
893                        sap.setVisibleSignature(new Rectangle(36, 748, 144, 780),1, "sig1");
894                        }else{
895                                int idSig = numberOfSignatures(reader)+1;
896                                //sap.setVisibleSignature(new Rectangle(36, 700, 144, 732),1, "sig"+Integer.toString(idSig));
897                                sap.setVisibleSignature(
898                                                new Rectangle(36, (748-(numberOfSignatures(reader)*38)), 144, (780-(numberOfSignatures(reader)*38))),
899                                                        1, "sig"+Integer.toString(idSig));
900                        }
901               
902                sap.setCertificate(chain[0]);
903               
904                // crear la estructura de la firma
905                PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
906               
907               
908                dic.setReason(sap.getReason());
909                dic.setLocation(sap.getLocation());
910                dic.setContact(sap.getContact());
911                dic.setDate(new PdfDate(sap.getSignDate()));
912               
913                sap.setCryptoDictionary(dic);
914               
915                HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer> ();
916                exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
917                sap.preClose(exc);
918               
919                ExternalDigest externalDigest = new ExternalDigest() {
920                        public MessageDigest getMessageDigest(String hashAlgorithm)
921                        throws GeneralSecurityException {
922                                return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
923                        }
924                };
925                       
926                       
927                PdfPKCS7 sgn = new PdfPKCS7(null, chain, SHA256_MESSAGE_DIGEST, null, externalDigest, false);
928               
929                InputStream data = sap.getRangeStream();
930               
931                byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest(SHA256_MESSAGE_DIGEST));
932               
933                Calendar cal = Calendar.getInstance();
934                byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
935               
936                sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest(SHA256_MESSAGE_DIGEST));
937               
938                System.out.println("sh length: "+ sh.length);
939                logger.debug("sh length: "+ sh.length);
940                       
941                String hashToSign = byteArrayToHexString(sh);
942                logger.debug("hashToSign: "+ hashToSign);
943                logger.debug("length: " +hashToSign.length());
944                System.out.println("***************************************************************");
945                System.out.println("HASH EN HEXADECIMAL:");
946                System.out.println(hashToSign);
947                System.out.println("length: " +hashToSign.length());   
948                System.out.println("***************************************************************");
949                       
950                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
951                        Date date = new Date();
952                        System.out.println(dateFormat.format(date));
953                        //String d = dateFormat.format(date);
954                       
955                       
956                        // almacenar los objetos necesarios para realizar el postsign en una sesion
957                        HttpSession session = req.getSession(true);
958                        session.setAttribute("hashToSign", hashToSign);
959                       
960                        session.setAttribute("stamper", stamper);
961                        session.setAttribute("sgn", sgn);
962                        session.setAttribute("hash", hash);
963                        session.setAttribute("cal", cal);
964                        session.setAttribute("sap", sap);
965                        session.setAttribute("baos", baos);
966                        session.setAttribute("fileId", fileId);
967                       
968                        presignHash.setHash(hashToSign);
969                        presignHash.setError("");
970                               
971                       
972                } catch (CertificateException e1) {
973                        logger.error("presignPdf ocurrio una excepcion ", e1);
974                        e1.printStackTrace();
975                        throw new MurachiException(e1.getMessage());
976                } catch (InvalidPdfException e) {
977                        logger.error("presignPdf ocurrio una excepcion ", e);
978                        e.printStackTrace();
979                        presignHash.setError("No se pudo leer el archivo PDF en el servidor");
980                        throw new MurachiException(e.getMessage());
981                } catch (IOException e) {
982                        logger.error("presignPdf ocurrio una excepcion ", e);
983                        e.printStackTrace();
984                        throw new MurachiException(e.getMessage());
985                } catch (DocumentException e) {
986                        logger.error("presignPdf ocurrio una excepcion ", e);
987                        e.printStackTrace();
988                        throw new MurachiException(e.getMessage());
989                } catch (InvalidKeyException e) {
990                        logger.error("presignPdf ocurrio una excepcion ", e);
991                        e.printStackTrace();
992                        throw new MurachiException(e.getMessage());
993                } catch (NoSuchProviderException e) {
994                        logger.error("presignPdf ocurrio una excepcion ", e);
995                        e.printStackTrace();
996                        throw new MurachiException(e.getMessage());
997                } catch (NoSuchAlgorithmException e) {
998                        logger.error("presignPdf ocurrio una excepcion ", e);
999                        e.printStackTrace();
1000                        throw new MurachiException(e.getMessage());
1001                } catch (GeneralSecurityException e) {
1002                        logger.error("presignPdf ocurrio una excepcion ", e);
1003                        e.printStackTrace();
1004                        throw new MurachiException(e.getMessage());
1005                } 
1006               
1007                logger.debug("presignPdf: "+ presignHash.toString());
1008                return Response.status(200).entity(presignHash).build();
1009                //return presignHash;
1010                       
1011        }
1012       
1013        /**
1014         * Retorna verdadero si el archivo pdf pasado como argumento ya esta firmado.
1015         *
1016         * @param pdfReader objeto PdfReader asociado al documento pdf
1017         * @return si el archivo pdf pasado como argumento ya esta firmado.
1018         * @throws IOException
1019         */
1020        private Boolean pdfAlreadySigned(PdfReader pdfReader) throws IOException {
1021               
1022                logger.debug("pdfAlreadySigned()");
1023                Security.addProvider(new BouncyCastleProvider());
1024               
1025                AcroFields af = pdfReader.getAcroFields();
1026                ArrayList<String> names = af.getSignatureNames();
1027                if (names.size() <= 0) {
1028                        return false;
1029                }else{
1030                        return true;
1031                }
1032        }
1033       
1034        /**
1035         * Retorna el número de firmas del documento
1036         * @param pdfReader objeto PdfReader asociado al documento pdf
1037         * @return número de firmas del documento
1038         */
1039        private int numberOfSignatures(PdfReader pdfReader) {
1040                logger.debug("numberOfSignatures()");
1041                Security.addProvider(new BouncyCastleProvider());
1042               
1043                AcroFields af = pdfReader.getAcroFields();
1044                ArrayList<String> names = af.getSignatureNames();
1045                return names.size();           
1046        }
1047       
1048       
1049        /**
1050         * Ejecuta el proceso de postsign o completacion de firma de documento pdf
1051         * @param postsignPar JSON con los parametros de postsign: signature realizada a partir
1052         * del hardware criptografico en el navegador.
1053         * @param req objeto request para crear una sesion y mantener elementos del
1054         * pdf en la misma.
1055         * @throws IOException
1056         * @throws MurachiException
1057         */
1058        @POST
1059        @Path("/pdfs/resenas")
1060        @Consumes(MediaType.APPLICATION_JSON)
1061        @Produces(MediaType.APPLICATION_JSON)   
1062        public Response postsignPdf(PostsignParameters postsignPar, @Context HttpServletRequest req) throws IOException, MurachiException {
1063               
1064                logger.info("/pdfs/resenas");
1065                // cadena con la firma
1066                String signature = postsignPar.getSignature();
1067                System.out.println("firma en Hex: " + signature);
1068               
1069                HttpSession session = req.getSession(false);
1070               
1071                String fileId = (String) session.getAttribute("fileId");
1072                System.out.println("fileId: " + fileId);
1073                logger.debug("fileId: " + fileId);
1074               
1075                PdfStamper stamper = (PdfStamper) session.getAttribute("stamper");
1076               
1077                PdfPKCS7 sgn = (PdfPKCS7) session.getAttribute("sgn");
1078               
1079                byte[] hash = (byte[]) session.getAttribute("hash");
1080               
1081                Calendar cal = (Calendar) session.getAttribute("cal");
1082               
1083                PdfSignatureAppearance sap = (PdfSignatureAppearance) session.getAttribute("sap");
1084               
1085                ByteArrayOutputStream os = (ByteArrayOutputStream) session.getAttribute("baos");
1086               
1087                if (sgn == null) {
1088                        System.out.println("sgn == null");
1089                        logger.error("Error en completacion de firma: estructura PdfPKCS7 nula");
1090                        throw new MurachiException("Error en completacion de firma: estructura PdfPKCS7 nula");
1091                }
1092                if (hash == null) {
1093                        System.out.println("hash == null");
1094                        logger.error("Error en completacion de firma: hash nulo");
1095                        throw new MurachiException("Error en completacion de firma: hash nulo");
1096                }
1097                if (cal == null) {
1098                        System.out.println("cal == null");
1099                        logger.error("Error en completacion de firma: estructura de fecha nula");
1100                        throw new MurachiException("Error en completacion de firma: estructura de fecha nula");
1101                }
1102                if (sap == null) {
1103                        System.out.println("sap == null");
1104                        logger.error("Error en completacion de firma: estructura de apariencia de firma pdf nula");
1105                        throw new MurachiException("Error en completacion de firma: estructura de apariencia de firma pdf nula");
1106                }
1107                if (os == null) {
1108                        System.out.println("os == null");
1109                        logger.error("Error en completacion de firma: bytes de archivo nulos");
1110                        throw new MurachiException("Error en completacion de firma: bytes de archivo nulos");
1111                }
1112
1113                System.out.println("antes de  hexStringToByteArray(signature)");
1114                // convertir signature en bytes         
1115                byte[] signatureInBytes = hexStringToByteArray(signature);
1116                               
1117                // completar el proceso de firma
1118                sgn.setExternalDigest(signatureInBytes, null, "RSA");
1119                byte[] encodeSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
1120                byte[] paddedSig = new byte[8192];
1121                System.arraycopy(encodeSig, 0, paddedSig, 0, encodeSig.length);
1122                PdfDictionary dic2 = new PdfDictionary();
1123                dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
1124               
1125                try {
1126                        sap.close(dic2);                       
1127                        stamper.close();
1128                        System.out.println("stamper.close");
1129                       
1130                }catch(DocumentException e) {
1131                        System.out.println("throw new IOException");
1132                        logger.error("postsignPdf: ocurrio una excepcion", e);
1133                        throw new MurachiException(e.getMessage());
1134                       
1135                } catch (IOException e) {
1136                        System.out.println("IOException e");
1137                        logger.error("postsignPdf: ocurrio una excepcion", e);
1138                        e.printStackTrace();
1139                        throw new MurachiException(e.getMessage());
1140                       
1141                }
1142               
1143                String signedPdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-signed.pdf";
1144               
1145                FileOutputStream signedFile = new FileOutputStream(signedPdf);
1146               
1147                os.writeTo(signedFile);
1148                os.flush();
1149                               
1150                // en este punto el archivo pdf debe estar disponible en la ruta
1151                // SERVER_UPLOAD_LOCATION_FOLDER + fileId;             
1152                System.out.println("Archivo firmado correctamente");
1153                logger.debug("Archivo firmado correctamente");
1154                       
1155                PostsignMessage message = new PostsignMessage();
1156                //message.setMessage(SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-signed.pdf");
1157                message.setMessage("{\"signedFile\":"+fileId + "-signed.pdf}");
1158                //return Response.status(200).entity(message).build();
1159               
1160                JSONObject jsonFinalResult = new JSONObject();
1161                jsonFinalResult.put("signedFileId",fileId + "-signed.pdf");
1162               
1163                logger.info(jsonFinalResult.toString());
1164                return Response.status(200).entity(jsonFinalResult.toString()).build();
1165        }
1166       
1167        /**
1168         * Descarga el archivo pdf pasado como argumento.
1169         * @param idFile nombre del archivo pdf a descargar
1170         * @return archivo pdf pasado como argumento.
1171         */
1172        @GET
1173        @Path("/pdfs/{idFile}")
1174        public Response getPdfSigned(@PathParam("idFile") String idFile) {
1175                logger.info("/pdfs/{idFile}");
1176                File file = null;
1177               
1178                file = new File(SERVER_UPLOAD_LOCATION_FOLDER + idFile);
1179                /*
1180                if (!file.exists()){
1181                       
1182                }
1183                */
1184                         
1185                ResponseBuilder response = Response.ok((Object) file);
1186                response.header("Content-Disposition", "attachment; filename=" + file.getName());
1187                return response.build();
1188        }
1189       
1190       
1191        // ******* BDOC ***********************************************************
1192       
1193        /**
1194         * Retorna un JSON con informacion de las firmas del documento BDOC
1195         * @param bdocFile archivo BDOC a verificar
1196         * @return JSON con informacion de las firmas del documento BDOC
1197         */
1198        private JSONObject verifySignaturesInBdoc(String bdocFile) {
1199       
1200                JSONObject jsonSignatures = new JSONObject();
1201
1202                JSONArray jsonSignaturesArray = new JSONArray();
1203                JSONArray jsonContainerValidationExceptionArray = new JSONArray();
1204               
1205                Security.addProvider(new BouncyCastleProvider());
1206                Container container;
1207                container = Container.open(bdocFile);
1208               
1209                int numberOfSignatures = container.getSignatures().size();
1210                if (numberOfSignatures == 0){
1211                        jsonSignatures.put("signatureNumber", "0");
1212                }else{
1213                        jsonSignatures.put("fileExist", "true");
1214                       
1215                        // informacion de archivos dentro del contenedor
1216                        if (container.getDataFiles().size() > 0){
1217                                jsonSignatures.put("numberOfDataFiles", container.getDataFiles().size()); 
1218                                jsonSignatures.put("dataFiles", getJSONFromBDOCDataFiles(container.getDataFiles()));
1219                                System.out.println(" dataFiles:  " + getJSONFromBDOCDataFiles(container.getDataFiles()).toString());
1220                        }else{
1221                                System.out.println(" dataFiles:  == 0");
1222                        }
1223               
1224                        jsonSignatures.put("numberOfSignatures", numberOfSignatures);
1225                       
1226                        ValidationResult validationResult = container.validate();
1227                        List<DigiDoc4JException> exceptions = validationResult.getContainerErrors();
1228                       
1229                        boolean isDDoc = container.getDocumentType() == DocumentType.DDOC;
1230                       
1231                        if (exceptions.size() > 0){
1232                                jsonSignatures.put("containerValidation", false);
1233                               
1234                                for (DigiDoc4JException exception : exceptions) {
1235                                        JSONObject containerException = new JSONObject();
1236                                       
1237                                        if (isDDoc && isWarning(((DDocContainer) container).getFormat(), exception)){
1238                                                System.out.println("    Warning: " + exception.toString());
1239                                               
1240                                    }
1241                                    else{
1242                                        System.out.println((isDDoc ? "  " : "   Error_: ") + exception.toString());
1243                                       
1244                                    }
1245                                        containerException.put("containerValidationException", exception.toString());
1246                                    jsonContainerValidationExceptionArray.put(containerException);
1247                                }
1248                            if (isDDoc && (((ValidationResultForDDoc) validationResult).hasFatalErrors())) {
1249                                jsonSignatures.put("validationResultForDDocHasFatalErrors", true);
1250                                return jsonSignatures; 
1251                            }
1252                            jsonSignatures.put("containerValidationExceptions", jsonContainerValidationExceptionArray);
1253                               
1254                               
1255                        }else{
1256                                jsonSignatures.put("containerValidation", true);
1257                               
1258                                HashMap<String, String> signatureInformation;
1259                                for (int i=0; i< numberOfSignatures; i++) {
1260                                        System.out.println("===== firma " + i + " =====");
1261                                        signatureInformation = verifyBDOCSignature(container.getSignature(i), container.getDocumentType());
1262                                        System.out.println("signatureInformation.size " + signatureInformation.size());
1263                                       
1264                                        JSONObject jo = getJSONFromASignature(signatureInformation);
1265                                        //System.out.println("jo:  " + jo.toString());
1266                                        jsonSignaturesArray.put(jo);                                   
1267                                }
1268                                                               
1269                                jsonSignatures.put("signatures", jsonSignaturesArray);                                                         
1270                                System.out.println(jsonSignatures.toString());                         
1271                        }                       
1272                }
1273                //verifyBdocContainer(container);               
1274                jsonSignatures.put("validation", "executed");                           
1275                return jsonSignatures;
1276        }
1277       
1278        /**
1279         * Retorna un JSON con informacion de los DataFiles incluidos en el contenedor
1280         * @param dataFilesList lista de DataFile incluidos en el contenedor
1281         * @return JSON con informacion de los DataFiles incluidos en el contenedor
1282         */
1283        private JSONArray getJSONFromBDOCDataFiles(List<DataFile> dataFilesList) {
1284                JSONArray jsonDataFileArray = new JSONArray();
1285               
1286                for (int i = 0; i < dataFilesList.size(); i++){
1287                       
1288                        JSONObject tmpJsonDataFile = new JSONObject();
1289                        DataFile df = dataFilesList.get(i);
1290                        tmpJsonDataFile.put("dataFileSize", Long.toString(df.getFileSize()));
1291                        tmpJsonDataFile.put("filename", df.getId());
1292                        tmpJsonDataFile.put("mediaType", df.getMediaType());
1293                        tmpJsonDataFile.put("name", df.getName());
1294                        jsonDataFileArray.put(tmpJsonDataFile);
1295                }
1296               
1297                //JSONObject jsonDataFile = new JSONObject();
1298                //jsonDataFile.put("dataFiles", jsonDataFileArray);
1299               
1300                //return jsonDataFile;
1301                return jsonDataFileArray;
1302        }
1303
1304        /**
1305         * Retorna Hashmap con la informacion de una firma electronica que se verifica
1306         * @param signature firma para verificar
1307         * @param documentType tipo de documento
1308         * @return Hashmap con la informacion de una firma electronica que se verifica
1309         */
1310        private static HashMap<String, String> verifyBDOCSignature(Signature signature, DocumentType documentType) {
1311               
1312                HashMap<String, String> signatureMap = new HashMap<String, String>();
1313               
1314                boolean isDDoc = documentType == DocumentType.DDOC;
1315               
1316                List<DigiDoc4JException> signatureValidationResult = signature.validate();
1317               
1318                if (signatureValidationResult.size() > 0) {
1319                        System.out.println("Signature " + signature.getId() + " is not valid");
1320                signatureMap.put("isValid", Boolean.toString(false));
1321                int counter = 1;
1322               
1323                //JSONArray jsonValidationExceptionArray = new JSONArray();
1324                //JSONObject tmpValidationException = new JSONObject();
1325               
1326                for (DigiDoc4JException exception : signatureValidationResult) {
1327                  System.out.println((isDDoc ? "        " : "   Error: ") + exception.toString());
1328                  signatureMap.put("signature"+signature.getId()+"ValidationException"+counter, exception.toString());
1329                 
1330                  //tmpValidationException.put("ValidationException", exception.toString());             
1331                  //jsonValidationExceptionArray.put(tmpValidationException);
1332                }
1333                //signatureMap.put("validationException", jsonValidationExceptionArray);
1334             
1335              if (isDDoc && isDDocTestSignature(signature)) {
1336                System.out.println("Signature " + signature.getId() + " is a test signature");
1337                signatureMap.put("isDDocTestSignature", Boolean.toString(true));
1338              }
1339                }
1340                else{
1341                       
1342                        System.out.println("Signature " + signature.getId() + " is valid");
1343                signatureMap.put("isValid", Boolean.toString(true));
1344                }
1345                signatureMap.put("signatureId", signature.getId());
1346        signatureMap.put("signatureProfile", signature.getProfile().toString());
1347        signatureMap.put("signatureMethod", signature.getSignatureMethod());
1348        /*
1349        if (signature.getSignerRoles().size() > 0){             
1350                signatureMap.put("signerRole1", signature.getSignerRoles().get(0));
1351                if (signature.getSignerRoles().size() == 2){
1352                        signatureMap.put("signerRole2", signature.getSignerRoles().get(1));
1353                }
1354        }
1355        */
1356        signatureMap.put("signatureCity", signature.getCity());
1357        signatureMap.put("signatureState", signature.getStateOrProvince());
1358        signatureMap.put("signaturePostalCode", signature.getPostalCode());
1359        signatureMap.put("signatureCountry", signature.getCountryName());
1360        signatureMap.put("signatureSigningTime", signature.getSigningTime().toString());
1361        //signatureMap.put("signaturePolicy", signature.getPolicy());
1362        //signatureMap.put("signatureOCSPProducedAtTimestamp", signature.getProducedAt().toString());
1363        //signatureMap.put("signaturePolicyURI", signature.getSignaturePolicyURI().toString());
1364        //signatureMap.put("signatureTimestampGenerationTime", signature.getTimeStampCreationTime().toString());
1365               
1366       
1367        X509Cert signerCertificate = signature.getSigningCertificate();
1368        signatureMap.put("signerCertificateSerial", signerCertificate.getSerial());
1369        signatureMap.put("signerCertificateSubjectName", signerCertificate.getSubjectName());
1370        signatureMap.put("signerCertificateIssuer", signerCertificate.issuerName());
1371        if (signerCertificate.isValid()){
1372                signatureMap.put("signerCertificateIsValid", Boolean.toString(true));
1373        }else{
1374                signatureMap.put("signerCertificateIsValid", Boolean.toString(false));
1375        }
1376       
1377       
1378       
1379                return signatureMap;
1380        }
1381       
1382       
1383        private static void verifyBdocContainer(Container container) {
1384            ValidationResult validationResult = container.validate();
1385
1386            List<DigiDoc4JException> exceptions = validationResult.getContainerErrors();
1387            boolean isDDoc = container.getDocumentType() == DocumentType.DDOC;
1388            for (DigiDoc4JException exception : exceptions) {
1389              if (isDDoc && isWarning(((DDocContainer) container).getFormat(), exception))
1390                System.out.println("    Warning: " + exception.toString());
1391              else
1392                System.out.println((isDDoc ? "  " : "   Error_: ") + exception.toString());
1393            }
1394
1395            if (isDDoc && (((ValidationResultForDDoc) validationResult).hasFatalErrors())) {
1396              return;
1397            }
1398
1399            List<Signature> signatures = container.getSignatures();
1400            if (signatures == null) {
1401              throw new SignatureNotFoundException();
1402            }
1403
1404            for (Signature signature : signatures) {
1405              List<DigiDoc4JException> signatureValidationResult = signature.validate();
1406              if (signatureValidationResult.size() == 0) {
1407                System.out.println("Signature " + signature.getId() + " is valid");
1408              } else {
1409                System.out.println("Signature " + signature.getId() + " is not valid");
1410                for (DigiDoc4JException exception : signatureValidationResult) {
1411                  System.out.println((isDDoc ? "        " : "   Error: ")
1412                      + exception.toString());
1413                }
1414              }
1415              if (isDDoc && isDDocTestSignature(signature)) {
1416                System.out.println("Signature " + signature.getId() + " is a test signature");
1417              }
1418            }
1419
1420            showWarnings(validationResult);
1421            verboseMessage(validationResult.getReport());
1422         }
1423
1424         private static void showWarnings(ValidationResult validationResult) {
1425                 if (bdocWarnings) {
1426                         for (DigiDoc4JException warning : validationResult.getWarnings()) {
1427                                 System.out.println("Warning: " + warning.toString());
1428                     }
1429                 }
1430         }
1431         
1432         /**
1433           * Checks is DigiDoc4JException predefined as warning for DDOC
1434           *
1435           * @param documentFormat format SignedDoc
1436           * @param exception      error to check
1437           * @return is this exception warning for DDOC utility program
1438           * @see SignedDoc
1439           */
1440          public static boolean isWarning(String documentFormat, DigiDoc4JException exception) {
1441            int errorCode = exception.getErrorCode();
1442            return (errorCode == DigiDocException.ERR_DF_INV_HASH_GOOD_ALT_HASH
1443                || errorCode == DigiDocException.ERR_OLD_VER
1444                || errorCode == DigiDocException.ERR_TEST_SIGNATURE
1445                || errorCode == DigiDocException.WARN_WEAK_DIGEST
1446                || (errorCode == DigiDocException.ERR_ISSUER_XMLNS && !documentFormat.equals(SignedDoc.FORMAT_SK_XML)));
1447          }
1448
1449          private static boolean isDDocTestSignature(Signature signature) {
1450                  CertValue certValue = ((DDocSignature) signature).getCertValueOfType(CertValue.CERTVAL_TYPE_SIGNER);
1451                  if (certValue != null) {
1452                          if (DigiDocGenFactory.isTestCard(certValue.getCert())) return true;
1453                  }
1454                  return false;
1455          }
1456         
1457          private static void verboseMessage(String message) {
1458                    if (bdocVerboseMode)
1459                      System.out.println(message);
1460          }
1461
1462       
1463       
1464        /**
1465         * Verifica si un archivo posee firmas electronicas y retorna informacion
1466         * de las mismas en un json
1467         * @param idFile
1468         * @return
1469         */
1470        @GET
1471        @Path("/verificar/{idFile}")
1472        //@Produces("application/json")
1473        @Produces("text/plain")
1474        public String verifyFile(@PathParam("idFile") String idFile) {
1475               
1476                String file = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
1477       
1478                //return getMimeType(file);
1479               
1480                               
1481                File tmpFile = new File(file);
1482                String result = "";
1483
1484               
1485               
1486               
1487                if (tmpFile.exists()) {
1488                        result = "El archivo existe.";
1489                       
1490                        try {
1491                                PdfReader reader = new PdfReader(file);
1492                                AcroFields af = reader.getAcroFields();
1493                                ArrayList<String> names = af.getSignatureNames();
1494                                if (names.size() > 0) {
1495                                        result = "el archivo PDF posee "+ names.size() +" firma(s).\n";
1496                                       
1497                                        // sin esto explota: se debe agregar una implementacion del provider en tiempo de ejecucion
1498                                        //http://www.cs.berkeley.edu/~jonah/bc/org/bouncycastle/jce/provider/BouncyCastleProvider.html
1499                                        Security.addProvider(new BouncyCastleProvider());
1500                                       
1501                                        for (String name: names) {
1502                                                result = result +"Nombre de la firma: "+ name + "\n";
1503                                                System.out.println("Nombre de la firma: "+ name);
1504                                               
1505                                                PdfPKCS7 pk = af.verifySignature(name);
1506                                               
1507                                                Certificate[] pkc = pk.getCertificates();
1508                                               
1509                                                String tmpSignerName = pk.getSigningCertificate().getSubjectX500Principal().toString();
1510                                               
1511                                               
1512                                                result = result + "Sujeto del certificado firmante: " + tmpSignerName + "\n"; 
1513                                                //pk.getSigningCertificate().getSubjectX500Principal().getName() + "\n";
1514                                                System.out.println("Sujeto del certificado firmante: " + 
1515                                                                pk.getSigningCertificate().getSubjectX500Principal().toString());
1516                                                 
1517                                                Calendar cal = pk.getSignDate();
1518                                               
1519                                                SimpleDateFormat date_format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
1520                                               
1521                                                //result = result + "Fecha de la firma: " + cal.toString() + "\n";
1522                                                result = result + "Fecha de la firma: " + date_format.format(cal.getTime()) + "\n";
1523                                               
1524                                                /*
1525                                                System.out.println("año: "+ cal.get(Calendar.YEAR));
1526                                                System.out.println("mes: "+ (cal.get(Calendar.MONTH) + 1));
1527                                                System.out.println("día: "+ cal.get(Calendar.DAY_OF_MONTH));
1528                                                System.out.println("hora: "+ cal.get(Calendar.HOUR));
1529                                                System.out.println("minuto: "+ cal.get(Calendar.MINUTE));
1530                                                System.out.println("segundo: "+ cal.get(Calendar.SECOND));
1531                                                */
1532                                                //SimpleDateFormat date_format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
1533                                            System.out.println(date_format.format(cal.getTime()));
1534
1535                                        }
1536                                       
1537                                       
1538                                }else{
1539                                        result = "el archivo PDF no posee firmas";
1540                                }
1541                               
1542                               
1543                               
1544                        } catch (IOException e) {
1545                                // TODO Auto-generated catch block
1546                                e.printStackTrace();
1547                        }
1548                       
1549                       
1550                }else {
1551                        result = "El archivo NO existe.";
1552                }
1553               
1554               
1555                return result;
1556               
1557               
1558        }
1559       
1560        /**
1561         * Ejecuta el proceso de presign o preparacion de firma de documento pdf
1562         * @param presignPar
1563         * @param req objeto request para crear una sesion y mantener elementos del
1564         * pdf en la misma
1565         * @param resp
1566         */
1567        @POST
1568        @Path("/prepararfirmapdf")
1569        @Consumes(MediaType.APPLICATION_JSON)
1570        @Produces(MediaType.APPLICATION_JSON)
1571        //public Response presign(PresignParameters presignPar, @Context HttpServletRequest req) {
1572        public PresignHash presign(PresignParameters presignPar, @Context HttpServletRequest req) {
1573               
1574
1575                // cadena resultado de la funcion
1576                String result = "";
1577               
1578                PresignHash presignHash = new PresignHash();
1579               
1580               
1581                // cadena con el certificado
1582                String certHex = presignPar.getCertificate();
1583                System.out.println("certificado en Hex: " + certHex);
1584               
1585                // obtener el id del archivo
1586                String fileId = presignPar.getFileId();
1587                               
1588                try {
1589                        CertificateFactory factory = CertificateFactory.getInstance("X.509");
1590                        Certificate[] chain = new Certificate[1];
1591                       
1592                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
1593                        chain[0] = factory.generateCertificate(in);
1594                       
1595                        if (chain[0] == null) {
1596                                System.out.println("error chain[0] == null");
1597                        }else {
1598                               
1599                                System.out.println("se cargo el certificado correctamente");
1600                                System.out.println(chain[0].toString());
1601                        }
1602                       
1603                        //String pdf = SERVER_UPLOAD_LOCATION_FOLDER + "e27a6a90-f955-4191-8e54-580e316a999d";
1604                        String pdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId;
1605                        System.out.println("archivo a firmar: " + pdf);
1606                       
1607                        PdfReader reader = new PdfReader(pdf);
1608                       
1609                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1610                       
1611                        //FileOutputStream baos = new FileOutputStream(pdf+"-signed.pdf");
1612                       
1613                        PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
1614                       
1615                        // crear la apariencia de la firma
1616                PdfSignatureAppearance sap = stamper.getSignatureAppearance();
1617                sap.setReason("Prueba de firma en dos partes");
1618                sap.setLocation("Merida, Venezuela");
1619                sap.setVisibleSignature(new Rectangle(36, 748, 144,780),1, "sig");
1620                sap.setCertificate(chain[0]);
1621               
1622                // crear la estructura de la firma
1623                PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
1624                dic.setReason(sap.getReason());
1625                dic.setLocation(sap.getLocation());
1626                dic.setContact(sap.getContact());
1627                dic.setDate(new PdfDate(sap.getSignDate()));
1628               
1629                sap.setCryptoDictionary(dic);
1630               
1631                HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer> ();
1632                exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
1633                sap.preClose(exc);
1634               
1635                ExternalDigest externalDigest = new ExternalDigest() {
1636                        public MessageDigest getMessageDigest(String hashAlgorithm)
1637                        throws GeneralSecurityException {
1638                                return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
1639                        }
1640                };
1641                       
1642                       
1643                PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, externalDigest, false);
1644               
1645                InputStream data = sap.getRangeStream();
1646               
1647                byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));
1648               
1649                Calendar cal = Calendar.getInstance();
1650                byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
1651               
1652                sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest("SHA256"));
1653               
1654                System.out.println("sh length: "+ sh.length);
1655                       
1656                String hashToSign = byteArrayToHexString(sh);
1657                System.out.println("***************************************************************");
1658                System.out.println("HASH EN HEXADECIMAL:");
1659                System.out.println(hashToSign);
1660                System.out.println("length: " +hashToSign.length());   
1661                System.out.println("***************************************************************");
1662                       
1663                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
1664                        Date date = new Date();
1665                        System.out.println(dateFormat.format(date));
1666                        //String d = dateFormat.format(date);
1667                       
1668                       
1669                        // almacenar los objetos necesarios para realizar el postsign en una sesion
1670                        HttpSession session = req.getSession(true);
1671                        session.setAttribute("hashToSign", hashToSign);
1672                       
1673                        session.setAttribute("stamper", stamper);
1674                        session.setAttribute("sgn", sgn);
1675                        session.setAttribute("hash", hash);
1676                        session.setAttribute("cal", cal);
1677                        session.setAttribute("sap", sap);
1678                        session.setAttribute("baos", baos);
1679                        session.setAttribute("fileId", fileId);
1680                       
1681                        // creacion del json
1682                        JSONObject jsonHash = new JSONObject();
1683                        jsonHash.put("hashToSign", hashToSign);
1684                       
1685                        result = jsonHash.toString();
1686                       
1687                        presignHash.setHash(hashToSign);
1688                               
1689                       
1690                } catch (CertificateException e1) {
1691                        // TODO Auto-generated catch block
1692                        e1.printStackTrace();
1693                } catch (IOException e) {
1694                        // TODO Auto-generated catch block
1695                        e.printStackTrace();
1696                } catch (DocumentException e) {
1697                        // TODO Auto-generated catch block
1698                        e.printStackTrace();
1699                } catch (InvalidKeyException e) {
1700                        // TODO Auto-generated catch block
1701                        e.printStackTrace();
1702                } catch (NoSuchProviderException e) {
1703                        // TODO Auto-generated catch block
1704                        e.printStackTrace();
1705                } catch (NoSuchAlgorithmException e) {
1706                        // TODO Auto-generated catch block
1707                        e.printStackTrace();
1708                } catch (GeneralSecurityException e) {
1709                        // TODO Auto-generated catch block
1710                        e.printStackTrace();
1711                }
1712               
1713                //return Response.status(200).entity(result).build();
1714                return presignHash;
1715                       
1716        }
1717       
1718       
1719        /**
1720         * Ejecuta el proceso de postsign o completacion de firma de documento pdf
1721         * @param postsignPar
1722         * @param req objeto request para crear una sesion y mantener elementos del
1723         * pdf en la misma
1724         * @param resp
1725         * @throws IOException
1726         */
1727        @POST
1728        @Path("/completarfirmapdf")
1729        @Consumes(MediaType.APPLICATION_JSON)
1730        @Produces(MediaType.APPLICATION_JSON)
1731        public Response postsign(PostsignParameters postsignPar, @Context HttpServletRequest req) throws IOException {
1732               
1733               
1734                // cadena resultado de la funcion
1735                String result = "";
1736                               
1737                // cadena con la firma
1738                String signature = postsignPar.getSignature();
1739                System.out.println("firma en Hex: " + signature);
1740               
1741                HttpSession session = req.getSession(false);
1742               
1743                String fileId = (String) session.getAttribute("fileId");
1744                System.out.println("fileId: " + fileId);
1745               
1746                PdfStamper stamper = (PdfStamper) session.getAttribute("stamper");
1747               
1748                PdfPKCS7 sgn = (PdfPKCS7) session.getAttribute("sgn");
1749               
1750                byte[] hash = (byte[]) session.getAttribute("hash");
1751               
1752                Calendar cal = (Calendar) session.getAttribute("cal");
1753               
1754                PdfSignatureAppearance sap = (PdfSignatureAppearance) session.getAttribute("sap");
1755               
1756                ByteArrayOutputStream os = (ByteArrayOutputStream) session.getAttribute("baos");
1757               
1758                if (sgn == null) {
1759                        System.out.println("sgn == null");
1760                }
1761                if (hash == null) {
1762                        System.out.println("hash == null");
1763                }
1764                if (cal == null) {
1765                        System.out.println("cal == null");
1766                }
1767                if (sap == null) {
1768                        System.out.println("sap == null");
1769                }
1770                if (os == null) {
1771                        System.out.println("os == null");
1772                }
1773               
1774               
1775               
1776                // convertir signature en bytes         
1777                byte[] signatureInBytes = hexStringToByteArray(signature);
1778                               
1779                // completar el proceso de firma
1780                sgn.setExternalDigest(signatureInBytes, null, RSA_DIGEST_ENCRYPTION_ALGORITHM);
1781                byte[] encodeSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
1782                byte[] paddedSig = new byte[8192];
1783                System.arraycopy(encodeSig, 0, paddedSig, 0, encodeSig.length);
1784                PdfDictionary dic2 = new PdfDictionary();
1785                dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
1786                try {
1787                        sap.close(dic2);
1788                       
1789                        stamper.close();
1790                        System.out.println("stamper.close");
1791                       
1792                }catch(DocumentException e) {
1793                       
1794                        System.out.println("throw new IOException");
1795                        throw new IOException(e);
1796                       
1797                } catch (IOException e) {
1798                        // TODO Auto-generated catch block
1799                        System.out.println("IOException e");
1800                        e.printStackTrace();
1801                       
1802                }
1803               
1804                String signedPdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-signed.pdf";
1805               
1806                FileOutputStream signedFile = new FileOutputStream(signedPdf);
1807               
1808                os.writeTo(signedFile);
1809                os.flush();
1810               
1811               
1812               
1813                // en este punto el archivo pdf debe estar disponible en la ruta
1814                // SERVER_UPLOAD_LOCATION_FOLDER + fileId;
1815               
1816                // llamar a una funcion que permita descargar el archivo
1817               
1818                result = "Archivo firmado correctamente";
1819                System.out.println("Archivo firmado correctamente");
1820               
1821                return Response.status(200).entity(result).build();
1822        }
1823       
1824        /**
1825         * Ejecuta el proceso de presign o preparacion de firma de documento en formato BDOC
1826         *
1827         * @param presignPar
1828         * @param req
1829         * @return
1830         */
1831        @POST
1832        @Path("/bdoc/")
1833        @Consumes(MediaType.APPLICATION_JSON)
1834        @Produces(MediaType.APPLICATION_JSON)
1835        public PresignHash presignBdoc(PresignParameters presignPar, @Context HttpServletRequest req) {
1836               
1837                System.out.println("presignBdoc: ");
1838               
1839               
1840                String fileId;
1841                String certHex;
1842               
1843                CertificateFactory cf;
1844                X509Certificate signerCert;
1845               
1846                // cadena resultado de la funcion
1847                String result = "";
1848                               
1849                PresignHash presignHash = new PresignHash();
1850               
1851                SignedInfo signedInfo;
1852               
1853                fileId = presignPar.getFileId();
1854                String sourceFile = SERVER_UPLOAD_LOCATION_FOLDER + fileId;
1855               
1856                certHex = presignPar.getCertificate();
1857                System.out.println("certificado en Hex: " + certHex);
1858               
1859//              try {
1860                        /*             
1861                        Configuration configuration = new Configuration(Configuration.Mode.TEST);
1862                       
1863                        configuration.loadConfiguration("/home/aaraujo/desarrollo/2015/workspace-luna/JAXRS-Murachi/WebContent/WEB-INF/lib/digidoc4j.yaml");
1864                        configuration.setTslLocation("http://localhost/trusted-test-mp.xml");
1865                   
1866                        Container container = Container.create(configuration);
1867                    SignatureParameters signatureParameters = new SignatureParameters();
1868                    SignatureProductionPlace productionPlace = new SignatureProductionPlace();
1869                    productionPlace.setCity("Merida");
1870                    signatureParameters.setProductionPlace(productionPlace);
1871                    signatureParameters.setRoles(asList("Desarrollador"));
1872                    container.setSignatureParameters(signatureParameters);
1873                    container.setSignatureProfile(SignatureProfile.B_BES);
1874                    container.addDataFile("/tmp/215d6ef7-d639-4191-87a1-ef68a91b2b27", "text/plain");
1875                    container.sign(new PKCS12Signer("/tmp/JuanHilario.p12", "123456".toCharArray()));
1876//                  Container container = Container.open("util/faulty/bdoc21-bad-nonce-content.bdoc");
1877                    container.save("/tmp/signed.bdoc");
1878                    ValidationResult results = container.validate();
1879                    System.out.println(results.getReport());
1880                        */
1881
1882                       
1883                Security.addProvider(new BouncyCastleProvider());
1884                        System.setProperty("digidoc4j.mode", "TEST");
1885                       
1886                        Configuration configuration;
1887                        configuration = new Configuration(Configuration.Mode.TEST);
1888                        //configuration.loadConfiguration("/home/aaraujo/desarrollo/2015/workspace-luna/JAXRS-Murachi/WebContent/WEB-INF/lib/digidoc4j.yaml");
1889                       
1890                        //configuration.setTslLocation("https://tibisay.cenditel.gob.ve/murachi/raw-attachment/wiki/WikiStart/trusted-test-mp.xml");
1891                        configuration.setTslLocation("http://localhost/trusted-test-mp.xml");
1892                       
1893                        Container container;
1894                       
1895                        container = Container.create(Container.DocumentType.BDOC, configuration);
1896                       
1897                        SignatureParameters signatureParameters = new SignatureParameters();
1898                    SignatureProductionPlace productionPlace = new SignatureProductionPlace();
1899                    productionPlace.setCity("Merida");
1900                    signatureParameters.setProductionPlace(productionPlace);
1901                    signatureParameters.setRoles(asList("Desarrollador"));
1902                    container.setSignatureParameters(signatureParameters);
1903                    container.setSignatureProfile(SignatureProfile.B_BES);
1904                       
1905                        container.addDataFile(sourceFile, "text/plain");
1906                       
1907                        container.sign(new PKCS12Signer("/tmp/JuanHilario.p12", "123456".toCharArray()));
1908                    container.save("/tmp/signed.bdoc");
1909                    ValidationResult results = container.validate();
1910                    System.out.println(results.getReport());
1911                       
1912                        /*
1913                        cf = CertificateFactory.getInstance("X.509");
1914               
1915                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
1916                       
1917                        signerCert = (X509Certificate) cf.generateCertificate(in);
1918                       
1919                        signedInfo = container.prepareSigning(signerCert);
1920                       
1921                        String hashToSign = byteArrayToHexString(signedInfo.getDigest());
1922                        //System.out.println("presignBdoc - hash: " + byteArrayToHexString(signedInfo.getDigest()));
1923                        System.out.println("presignBdoc - hash: " + hashToSign);
1924                       
1925                       
1926                        //container.save("/tmp/containerTmp.bdoc");
1927                        serialize(container, "/tmp/containerSerialized");
1928                        */
1929                       
1930                        String hashToSign = "firma exitosa";
1931                       
1932                        // creacion del json
1933                        JSONObject jsonHash = new JSONObject();
1934                        jsonHash.put("hashToSign", hashToSign);
1935                                               
1936                        result = jsonHash.toString();
1937                                               
1938                        presignHash.setHash(hashToSign);
1939                       
1940                       
1941/*                     
1942                } catch (CertificateException e1) {
1943                        // TODO Auto-generated catch block
1944                        e1.printStackTrace();
1945                } catch (IOException e) {
1946                        // TODO Auto-generated catch block
1947                        e.printStackTrace();
1948                }
1949*/             
1950               
1951                return presignHash;
1952               
1953        }
1954       
1955       
1956        @GET
1957        @Path("/testbdoc/")
1958        public String testBdoc() {
1959               
1960                Security.addProvider(new BouncyCastleProvider());
1961               
1962                Configuration configuration = new Configuration(Configuration.Mode.TEST);
1963               
1964                configuration.loadConfiguration("/home/aaraujo/desarrollo/2015/workspace-luna/JAXRS-Murachi/WebContent/WEB-INF/lib/digidoc4j.yaml");
1965                configuration.setTslLocation("http://localhost/trusted-test-mp.xml");
1966               
1967            Container container = Container.create(configuration);
1968            SignatureParameters signatureParameters = new SignatureParameters();
1969            SignatureProductionPlace productionPlace = new SignatureProductionPlace();
1970            productionPlace.setCity("Merida");
1971            signatureParameters.setProductionPlace(productionPlace);
1972            signatureParameters.setRoles(asList("Desarrollador"));
1973            container.setSignatureParameters(signatureParameters);
1974            container.setSignatureProfile(SignatureProfile.B_BES);
1975            container.addDataFile("/tmp/01311213-5756-4707-a73d-6d42b09b26fd", "text/plain");
1976            container.sign(new PKCS12Signer("/tmp/JuanHilario.p12", "123456".toCharArray()));
1977//          Container container = Container.open("util/faulty/bdoc21-bad-nonce-content.bdoc");
1978            container.save("/tmp/signed.bdoc");
1979            ValidationResult result = container.validate();
1980            System.out.println(result.getReport());
1981               
1982                return "test";
1983        }
1984       
1985       
1986       
1987       
1988       
1989        /**
1990         * Prueba de ejecucion de programa desde consola. Incompleta
1991         * @return
1992         * @throws InterruptedException
1993         */
1994        @GET
1995        @Path("/ejecutar")
1996        @Produces("text/plain")
1997        public String executeProcess() throws InterruptedException {
1998               
1999               
2000                String line = "";
2001                OutputStream stdin = null;
2002                InputStream stderr = null;
2003                InputStream stdout = null;
2004               
2005                try {
2006                        System.out.print("...a crear el proceso");
2007                        Process process = Runtime.getRuntime().exec("/usr/java/jdk1.7.0_21/bin/java -jar /home/aaraujo/desarrollo/2015/servicioVerificacion/testsigningpdf/holamundopdf.jar /tmp/589750.pdf /tmp/simonDiaz.pem /tmp/firmadoconsola.pdf");
2008                        //Process process = Runtime.getRuntime().exec("ls -l");
2009                        stdin = process.getOutputStream();
2010                        stderr = process.getErrorStream();
2011                        stdout = process.getInputStream();
2012                       
2013                        InputStreamReader isr = new InputStreamReader(stdout);
2014                        BufferedReader buff = new BufferedReader (isr);
2015
2016                       
2017                        while((line = buff.readLine()) != null)
2018                                System.out.print(line+"\n");
2019                        int exitValue = process.waitFor();
2020                        if (exitValue != 0) {
2021                            System.out.println("Abnormal process termination");
2022                        }       
2023                       
2024                } catch (IOException e) {
2025                        // TODO Auto-generated catch block
2026                        e.printStackTrace();
2027                }
2028                System.out.print("...saliendo");
2029                return line;
2030        }
2031       
2032       
2033       
2034       
2035       
2036        /**
2037         *
2038         * @param certHex
2039         * @param httpHeaders
2040         * @param req
2041         * @param resp
2042         */
2043        @POST
2044        @Path("/presignOld")
2045        @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
2046        public void presignOld(
2047                        @FormParam("certHexInForm") String certHex,
2048                        @Context HttpHeaders httpHeaders,
2049                        @Context HttpServletRequest req,
2050                        @Context HttpServletResponse resp) {
2051               
2052
2053                String host = httpHeaders.getRequestHeader("host").get(0);
2054               
2055                String agent = httpHeaders.getRequestHeader("user-agent").get(0);
2056                String salida = "User agent :"+ agent +" from host : "+host;
2057                System.out.println(host);
2058                System.out.println(agent);
2059                System.out.println(salida);
2060               
2061                System.out.println("certificado en Hex: " + certHex);
2062               
2063                try {
2064                        CertificateFactory factory = CertificateFactory.getInstance("X.509");
2065                        Certificate[] chain = new Certificate[1];
2066                       
2067                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
2068                        chain[0] = factory.generateCertificate(in);
2069                       
2070                        if (chain[0] == null) {
2071                                System.out.println("error chain[0] == null");
2072                        }else {
2073                               
2074                                System.out.println("se cargo el certificado correctamente");
2075                                System.out.println(chain[0].toString());
2076                        }
2077                       
2078                        String pdf = SERVER_UPLOAD_LOCATION_FOLDER + "e27a6a90-f955-4191-8e54-580e316a999d";
2079                       
2080                        PdfReader reader = new PdfReader(pdf);
2081                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
2082                        PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
2083                       
2084                        // crear la apariencia de la firma
2085                PdfSignatureAppearance sap = stamper.getSignatureAppearance();
2086                sap.setReason("Prueba de firma en dos partes");
2087                sap.setLocation("Merida, Venezuela");
2088                sap.setVisibleSignature(new Rectangle(36, 748, 144,780),1, "sig");
2089                sap.setCertificate(chain[0]);
2090               
2091                // crear la estructura de la firma
2092                PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
2093                dic.setReason(sap.getReason());
2094                dic.setLocation(sap.getLocation());
2095                dic.setContact(sap.getContact());
2096                dic.setDate(new PdfDate(sap.getSignDate()));
2097               
2098                sap.setCryptoDictionary(dic);
2099               
2100                HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer> ();
2101                exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
2102                sap.preClose(exc);
2103               
2104                ExternalDigest externalDigest = new ExternalDigest() {
2105                        public MessageDigest getMessageDigest(String hashAlgorithm)
2106                        throws GeneralSecurityException {
2107                                return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
2108                        }
2109                };
2110                       
2111                       
2112                PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, externalDigest, false);
2113               
2114                InputStream data = sap.getRangeStream();
2115               
2116                byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));
2117               
2118                Calendar cal = Calendar.getInstance();
2119                byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
2120               
2121                sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest("SHA256"));
2122               
2123                System.out.println("sh length: "+ sh.length);
2124                       
2125                String hashToSign = byteArrayToHexString(sh);
2126                System.out.println("***************************************************************");
2127                System.out.println("HASH EN HEXADECIMAL:");
2128                System.out.println(hashToSign);
2129                System.out.println("length: " +hashToSign.length());   
2130                System.out.println("***************************************************************");
2131                       
2132                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
2133                        Date date = new Date();
2134                        System.out.println(dateFormat.format(date));
2135                        String d = dateFormat.format(date);
2136                       
2137                       
2138                        // almacenar los objetos necesarios para realizar el postsign en una sesion
2139                        HttpSession session = req.getSession(true);
2140                        session.setAttribute("hashToSign", hashToSign);
2141                       
2142                        session.setAttribute("sgn", sgn);
2143                        session.setAttribute("hash", hash);
2144                        session.setAttribute("cal", cal);
2145                        session.setAttribute("sap", sap);
2146                        session.setAttribute("baos", baos);
2147                       
2148               
2149                       
2150                        resp.sendRedirect("http://localhost/murachi2.html");
2151                       
2152                       
2153                } catch (CertificateException e1) {
2154                        // TODO Auto-generated catch block
2155                        e1.printStackTrace();
2156                } catch (IOException e) {
2157                        // TODO Auto-generated catch block
2158                        e.printStackTrace();
2159                } catch (DocumentException e) {
2160                        // TODO Auto-generated catch block
2161                        e.printStackTrace();
2162                } catch (InvalidKeyException e) {
2163                        // TODO Auto-generated catch block
2164                        e.printStackTrace();
2165                } catch (NoSuchProviderException e) {
2166                        // TODO Auto-generated catch block
2167                        e.printStackTrace();
2168                } catch (NoSuchAlgorithmException e) {
2169                        // TODO Auto-generated catch block
2170                        e.printStackTrace();
2171                } catch (GeneralSecurityException e) {
2172                        // TODO Auto-generated catch block
2173                        e.printStackTrace();
2174                }
2175               
2176               
2177       
2178        }
2179       
2180       
2181        @POST
2182        @Path("/postsign")
2183        public String postsignOld(@Context HttpServletRequest req,
2184                        @Context HttpServletResponse resp) {
2185               
2186                System.out.println("...postsign()...");
2187               
2188                HttpSession session = req.getSession(false);
2189                Object att = session.getAttribute("hashToSign");
2190                               
2191       
2192                String output = "atributo leido de la sesion: " + att.toString();
2193               
2194               
2195                return output;
2196                //return Response.status(200).entity(output).build();
2197        }
2198       
2199       
2200        @GET
2201        @Path("/retornajson")
2202        @Produces(MediaType.APPLICATION_JSON)
2203        public PresignHash retornajson(@Context HttpServletRequest req) {
2204               
2205               
2206               
2207                PresignHash h = new PresignHash();
2208                h.setHash("ESTO SERIA UN HASH");
2209               
2210                System.out.println("...retornajson..."+ h.getHash());
2211               
2212                return h;
2213               
2214        }
2215       
2216        @POST
2217        @Path("/enviarjson")
2218        @Consumes(MediaType.APPLICATION_JSON)
2219        @Produces(MediaType.APPLICATION_JSON)
2220        public PresignHash recibejson( PresignParameters par) {
2221               
2222                String fileId = par.getFileId();
2223                System.out.println("...fileId recibido..."+ fileId);
2224               
2225                String cert = par.getCertificate();
2226                System.out.println("...certificate recibido..."+ cert);
2227               
2228                PresignHash h = new PresignHash();
2229                h.setHash("DEBES FIRMAR ESTO");
2230               
2231                System.out.println("...recibejson..."+ h.getHash());
2232               
2233                return h;
2234               
2235        }
2236       
2237       
2238       
2239       
2240        /**
2241         * Retorna el mimeType del archivo pasado como argumento
2242         * @param absolutFilePath ruta absoluta del archivo
2243         * @return mimeType del archivo pasado como argumento
2244         */
2245        public String getMimeType(String absolutFilePath) {
2246                               
2247                String result = "";             
2248                java.nio.file.Path source = Paths.get(absolutFilePath);
2249                try {
2250                        result = Files.probeContentType(source);                       
2251                        System.out.println(result);
2252                } catch (IOException e) {
2253                        // TODO Auto-generated catch block
2254                        e.printStackTrace();
2255                }               
2256                return result;           
2257        }
2258       
2259        /**
2260         * Convierte una cadena Hexadecimal en un arreglo de bytes
2261         * @param s cadena hexadecimal
2262         * @return arreglo de bytes resultantes de la conversion de la cadena hexadecimal
2263         */
2264        public static byte[] hexStringToByteArray(String s) {
2265            byte[] b = new byte[s.length() / 2];
2266            for (int i = 0; i < b.length; i++) {
2267              int index = i * 2;
2268              int v = Integer.parseInt(s.substring(index, index + 2), 16);
2269              b[i] = (byte) v;
2270            }
2271            return b;
2272          }
2273       
2274        /**
2275           * Converts a byte array into a hex string.
2276           * @param byteArray the byte array source
2277           * @return a hex string representing the byte array
2278           */
2279          public static String byteArrayToHexString(final byte[] byteArray) {
2280              if (byteArray == null) {
2281                  return "";
2282              }
2283              return byteArrayToHexString(byteArray, 0, byteArray.length);
2284          }
2285         
2286          public static String byteArrayToHexString(final byte[] byteArray, int startPos, int length) {
2287              if (byteArray == null) {
2288                  return "";
2289              }
2290              if(byteArray.length < startPos+length){
2291                  throw new IllegalArgumentException("startPos("+startPos+")+length("+length+") > byteArray.length("+byteArray.length+")");
2292              }
2293//            int readBytes = byteArray.length;
2294              StringBuilder hexData = new StringBuilder();
2295              int onebyte;
2296              for (int i = 0; i < length; i++) {
2297                  onebyte = ((0x000000ff & byteArray[startPos+i]) | 0xffffff00);
2298                  hexData.append(Integer.toHexString(onebyte).substring(6));
2299              }
2300              return hexData.toString();
2301          }
2302       
2303          /**
2304           * Serializa el contenedor BDOC pasado como argumento
2305           * @param container Contenedor que se desea serializar
2306           * @param filePath ruta absoluta al archivo serializado
2307           * @throws IOException
2308           */
2309          private static void serialize(Container container, String filePath) throws IOException {
2310                  FileOutputStream fileOut = new FileOutputStream(filePath+".bin");
2311                  ObjectOutputStream out = new ObjectOutputStream(fileOut);
2312                  out.writeObject(container);
2313                  out.flush();
2314                  out.close();
2315                  fileOut.close();
2316          }
2317         
2318          /**
2319           * Deserializa el contenedor BDOC pasado como argumento
2320           * @param filePath ruta absoluta al contenedor que se desea deserializar
2321           * @return contenedor deserializado
2322           * @throws IOException
2323           * @throws ClassNotFoundException
2324           */
2325          private static Container deserializer(String filePath) throws IOException, ClassNotFoundException {
2326                  //FileInputStream fileIn = new FileInputStream("container.bin");
2327                  FileInputStream fileIn = new FileInputStream(filePath);
2328                  ObjectInputStream in = new ObjectInputStream(fileIn);
2329                  Container container = (Container) in.readObject();
2330                  in.close();
2331                  fileIn.close();
2332                  return container;
2333          }
2334         
2335}
Note: See TracBrowser for help on using the repository browser.