source: murachi/murachi/src/main/java/ve/gob/cenditel/murachi/MurachiRESTWS.java @ 4a9505e

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

Agregados nuevos certificados de la infraestructura nacional de certificación electrónica para la verificación de archivos firmados.

  • Property mode set to 100644
File size: 80.2 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                        signerCertificateMap.put("signerCertificateExpiredAtTimeOfSigning", "true");
747                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate was expired at the time of signing");
748                        throw new MurachiException(e.getMessage());
749                } catch (CertificateNotYetValidException e) {
750                        System.out
751                                        .println("The certificate wasn't valid yet at the time of signing.");
752                        signerCertificateMap.put("signerCertificateNotValidYetAtTimeOfSigning", "true");
753                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate wasn't valid yet at the time of signing");
754                        throw new MurachiException(e.getMessage());
755                }
756                try {
757                        cert.checkValidity();
758                        System.out.println("The certificate is still valid.");
759                        signerCertificateMap.put("signerCertificateStillValid", "true");
760                } catch (CertificateExpiredException e) {
761                        System.out.println("The certificate has expired.");
762                        signerCertificateMap.put("signerCertificateHasExpired", "true");
763                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate has expired");
764                        throw new MurachiException(e.getMessage());
765                } catch (CertificateNotYetValidException e) {
766                        System.out.println("The certificate isn't valid yet.");
767                        signerCertificateMap.put("signerCertificateNotValidYet", "true");
768                        logger.error("getSignerCertificateInfo() ocurrio una excepcion: The certificate isn't valid yet");
769                        throw new MurachiException(e.getMessage());
770                }
771                return signerCertificateMap;
772        }
773       
774       
775        /**
776         * Ejecuta el proceso de presign o preparacion de firma de documento pdf.
777         *
778         * Estructura del JSON que recibe la funcion:
779         *
780         *      {"fileId":"file_id",                           
781         *      "certificate":"hex_cert_value",
782         *  "reason":"reason",
783         *  "location":"location",
784         *  "contact":"contact"
785         *  }
786         *
787         *
788         * @param presignPar JSON con los parametros de preparacion: Id del archivo y certificado
789         * firmante
790         * @param req objeto request para crear una sesion y mantener elementos del
791         * pdf en la misma.
792         * @throws MurachiException
793         *
794         */
795        @POST
796        @Path("/pdfs")
797        @Consumes(MediaType.APPLICATION_JSON)
798        @Produces(MediaType.APPLICATION_JSON)
799        //public PresignHash presignPdf(PresignParameters presignPar, @Context HttpServletRequest req) {
800        public Response presignPdf(PresignParameters presignPar, @Context HttpServletRequest req) throws MurachiException {
801               
802                logger.info("/pdfs");
803               
804                PresignHash presignHash = new PresignHash();
805
806                // obtener el id del archivo
807                String fileId = presignPar.getFileId();
808               
809                // cadena con el certificado
810                String certHex = presignPar.getCertificate();
811                System.out.println("certificado en Hex: " + certHex);
812
813                String reason = presignPar.getReason();
814               
815                String location = presignPar.getLocation();
816               
817                String contact = presignPar.getContact();
818               
819               
820                String pdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId;
821                System.out.println("archivo a firmar: " + pdf);
822                logger.debug("archivo a firmar: " + pdf);
823               
824                String mime = getMimeType(pdf);
825               
826                if (!mime.equals("application/pdf")){
827                        presignHash.setError("El archivo que desea firmar no es un PDF.");
828                        presignHash.setHash("");
829                        //return presignHash;
830                                                                       
831                        //result = presignHash.toString();
832                        logger.info("El archivo que desea firmar no es un PDF.");
833                        return Response.status(400).entity(presignHash).build();
834                       
835                }
836                       
837                               
838                try {
839                        CertificateFactory factory = CertificateFactory.getInstance("X.509");
840                        Certificate[] chain = new Certificate[1];
841                       
842                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
843                        chain[0] = factory.generateCertificate(in);
844                       
845                        if (chain[0] == null) {
846                                System.out.println("error chain[0] == null");
847                                logger.error("presignPdf: error en carga de certificado de firmante");
848                                throw new MurachiException("presignPdf: error en carga de certificado de firmante");
849                        }else {
850                               
851                                System.out.println("se cargo el certificado correctamente");
852                                System.out.println(chain[0].toString());
853                                logger.debug("se cargo el certificado correctamente");
854                                logger.debug(chain[0].toString());
855                        }                       
856                       
857                        PdfReader reader = new PdfReader(pdf);                 
858                       
859                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
860                       
861                        //PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
862                        PdfStamper stamper = null;
863                       
864                       
865                        if (pdfAlreadySigned(reader)){
866                                stamper = PdfStamper.createSignature(reader, baos, '\0', null, true);
867                        }else{
868                                stamper = PdfStamper.createSignature(reader, baos, '\0');
869                        }
870
871                        // crear la apariencia de la firma
872                PdfSignatureAppearance sap = stamper.getSignatureAppearance();
873                               
874                sap.setReason(reason);
875                sap.setLocation(location);
876                sap.setContact(contact);
877               
878                //sap.setVisibleSignature(new Rectangle(36, 748, 144,780),1, "sig");
879               
880                if (!pdfAlreadySigned(reader)){
881                        sap.setVisibleSignature(new Rectangle(36, 748, 144, 780),1, "sig1");
882                        }else{
883                                int idSig = numberOfSignatures(reader)+1;
884                                //sap.setVisibleSignature(new Rectangle(36, 700, 144, 732),1, "sig"+Integer.toString(idSig));
885                                sap.setVisibleSignature(
886                                                new Rectangle(36, (748-(numberOfSignatures(reader)*38)), 144, (780-(numberOfSignatures(reader)*38))),
887                                                        1, "sig"+Integer.toString(idSig));
888                        }
889               
890                sap.setCertificate(chain[0]);
891               
892                // crear la estructura de la firma
893                PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
894               
895               
896                dic.setReason(sap.getReason());
897                dic.setLocation(sap.getLocation());
898                dic.setContact(sap.getContact());
899                dic.setDate(new PdfDate(sap.getSignDate()));
900               
901                sap.setCryptoDictionary(dic);
902               
903                HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer> ();
904                exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
905                sap.preClose(exc);
906               
907                ExternalDigest externalDigest = new ExternalDigest() {
908                        public MessageDigest getMessageDigest(String hashAlgorithm)
909                        throws GeneralSecurityException {
910                                return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
911                        }
912                };
913                       
914                       
915                PdfPKCS7 sgn = new PdfPKCS7(null, chain, SHA256_MESSAGE_DIGEST, null, externalDigest, false);
916               
917                InputStream data = sap.getRangeStream();
918               
919                byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest(SHA256_MESSAGE_DIGEST));
920               
921                Calendar cal = Calendar.getInstance();
922                byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
923               
924                sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest(SHA256_MESSAGE_DIGEST));
925               
926                System.out.println("sh length: "+ sh.length);
927                logger.debug("sh length: "+ sh.length);
928                       
929                String hashToSign = byteArrayToHexString(sh);
930                logger.debug("hashToSign: "+ hashToSign);
931                logger.debug("length: " +hashToSign.length());
932                System.out.println("***************************************************************");
933                System.out.println("HASH EN HEXADECIMAL:");
934                System.out.println(hashToSign);
935                System.out.println("length: " +hashToSign.length());   
936                System.out.println("***************************************************************");
937                       
938                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
939                        Date date = new Date();
940                        System.out.println(dateFormat.format(date));
941                        //String d = dateFormat.format(date);
942                       
943                       
944                        // almacenar los objetos necesarios para realizar el postsign en una sesion
945                        HttpSession session = req.getSession(true);
946                        session.setAttribute("hashToSign", hashToSign);
947                       
948                        session.setAttribute("stamper", stamper);
949                        session.setAttribute("sgn", sgn);
950                        session.setAttribute("hash", hash);
951                        session.setAttribute("cal", cal);
952                        session.setAttribute("sap", sap);
953                        session.setAttribute("baos", baos);
954                        session.setAttribute("fileId", fileId);
955                       
956                        presignHash.setHash(hashToSign);
957                        presignHash.setError("");
958                               
959                       
960                } catch (CertificateException e1) {
961                        logger.error("presignPdf ocurrio una excepcion ", e1);
962                        e1.printStackTrace();
963                        throw new MurachiException(e1.getMessage());
964                } catch (InvalidPdfException e) {
965                        logger.error("presignPdf ocurrio una excepcion ", e);
966                        e.printStackTrace();
967                        presignHash.setError("No se pudo leer el archivo PDF en el servidor");
968                        throw new MurachiException(e.getMessage());
969                } catch (IOException e) {
970                        logger.error("presignPdf ocurrio una excepcion ", e);
971                        e.printStackTrace();
972                        throw new MurachiException(e.getMessage());
973                } catch (DocumentException e) {
974                        logger.error("presignPdf ocurrio una excepcion ", e);
975                        e.printStackTrace();
976                        throw new MurachiException(e.getMessage());
977                } catch (InvalidKeyException e) {
978                        logger.error("presignPdf ocurrio una excepcion ", e);
979                        e.printStackTrace();
980                        throw new MurachiException(e.getMessage());
981                } catch (NoSuchProviderException e) {
982                        logger.error("presignPdf ocurrio una excepcion ", e);
983                        e.printStackTrace();
984                        throw new MurachiException(e.getMessage());
985                } catch (NoSuchAlgorithmException e) {
986                        logger.error("presignPdf ocurrio una excepcion ", e);
987                        e.printStackTrace();
988                        throw new MurachiException(e.getMessage());
989                } catch (GeneralSecurityException e) {
990                        logger.error("presignPdf ocurrio una excepcion ", e);
991                        e.printStackTrace();
992                        throw new MurachiException(e.getMessage());
993                } 
994               
995                logger.debug("presignPdf: "+ presignHash.toString());
996                return Response.status(200).entity(presignHash).build();
997                //return presignHash;
998                       
999        }
1000       
1001        /**
1002         * Retorna verdadero si el archivo pdf pasado como argumento ya esta firmado.
1003         *
1004         * @param pdfReader objeto PdfReader asociado al documento pdf
1005         * @return si el archivo pdf pasado como argumento ya esta firmado.
1006         * @throws IOException
1007         */
1008        private Boolean pdfAlreadySigned(PdfReader pdfReader) throws IOException {
1009               
1010                logger.debug("pdfAlreadySigned()");
1011                Security.addProvider(new BouncyCastleProvider());
1012               
1013                AcroFields af = pdfReader.getAcroFields();
1014                ArrayList<String> names = af.getSignatureNames();
1015                if (names.size() <= 0) {
1016                        return false;
1017                }else{
1018                        return true;
1019                }
1020        }
1021       
1022        /**
1023         * Retorna el número de firmas del documento
1024         * @param pdfReader objeto PdfReader asociado al documento pdf
1025         * @return número de firmas del documento
1026         */
1027        private int numberOfSignatures(PdfReader pdfReader) {
1028                logger.debug("numberOfSignatures()");
1029                Security.addProvider(new BouncyCastleProvider());
1030               
1031                AcroFields af = pdfReader.getAcroFields();
1032                ArrayList<String> names = af.getSignatureNames();
1033                return names.size();           
1034        }
1035       
1036       
1037        /**
1038         * Ejecuta el proceso de postsign o completacion de firma de documento pdf
1039         * @param postsignPar JSON con los parametros de postsign: signature realizada a partir
1040         * del hardware criptografico en el navegador.
1041         * @param req objeto request para crear una sesion y mantener elementos del
1042         * pdf en la misma.
1043         * @throws IOException
1044         * @throws MurachiException
1045         */
1046        @POST
1047        @Path("/pdfs/resenas")
1048        @Consumes(MediaType.APPLICATION_JSON)
1049        @Produces(MediaType.APPLICATION_JSON)   
1050        public Response postsignPdf(PostsignParameters postsignPar, @Context HttpServletRequest req) throws IOException, MurachiException {
1051               
1052                logger.info("/pdfs/resenas");
1053                // cadena con la firma
1054                String signature = postsignPar.getSignature();
1055                System.out.println("firma en Hex: " + signature);
1056               
1057                HttpSession session = req.getSession(false);
1058               
1059                String fileId = (String) session.getAttribute("fileId");
1060                System.out.println("fileId: " + fileId);
1061                logger.debug("fileId: " + fileId);
1062               
1063                PdfStamper stamper = (PdfStamper) session.getAttribute("stamper");
1064               
1065                PdfPKCS7 sgn = (PdfPKCS7) session.getAttribute("sgn");
1066               
1067                byte[] hash = (byte[]) session.getAttribute("hash");
1068               
1069                Calendar cal = (Calendar) session.getAttribute("cal");
1070               
1071                PdfSignatureAppearance sap = (PdfSignatureAppearance) session.getAttribute("sap");
1072               
1073                ByteArrayOutputStream os = (ByteArrayOutputStream) session.getAttribute("baos");
1074               
1075                if (sgn == null) {
1076                        System.out.println("sgn == null");
1077                        logger.error("Error en completacion de firma: estructura PdfPKCS7 nula");
1078                        throw new MurachiException("Error en completacion de firma: estructura PdfPKCS7 nula");
1079                }
1080                if (hash == null) {
1081                        System.out.println("hash == null");
1082                        logger.error("Error en completacion de firma: hash nulo");
1083                        throw new MurachiException("Error en completacion de firma: hash nulo");
1084                }
1085                if (cal == null) {
1086                        System.out.println("cal == null");
1087                        logger.error("Error en completacion de firma: estructura de fecha nula");
1088                        throw new MurachiException("Error en completacion de firma: estructura de fecha nula");
1089                }
1090                if (sap == null) {
1091                        System.out.println("sap == null");
1092                        logger.error("Error en completacion de firma: estructura de apariencia de firma pdf nula");
1093                        throw new MurachiException("Error en completacion de firma: estructura de apariencia de firma pdf nula");
1094                }
1095                if (os == null) {
1096                        System.out.println("os == null");
1097                        logger.error("Error en completacion de firma: bytes de archivo nulos");
1098                        throw new MurachiException("Error en completacion de firma: bytes de archivo nulos");
1099                }
1100
1101                System.out.println("antes de  hexStringToByteArray(signature)");
1102                // convertir signature en bytes         
1103                byte[] signatureInBytes = hexStringToByteArray(signature);
1104                               
1105                // completar el proceso de firma
1106                sgn.setExternalDigest(signatureInBytes, null, "RSA");
1107                byte[] encodeSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
1108                byte[] paddedSig = new byte[8192];
1109                System.arraycopy(encodeSig, 0, paddedSig, 0, encodeSig.length);
1110                PdfDictionary dic2 = new PdfDictionary();
1111                dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
1112               
1113                try {
1114                        sap.close(dic2);                       
1115                        stamper.close();
1116                        System.out.println("stamper.close");
1117                       
1118                }catch(DocumentException e) {
1119                        System.out.println("throw new IOException");
1120                        logger.error("postsignPdf: ocurrio una excepcion", e);
1121                        throw new MurachiException(e.getMessage());
1122                       
1123                } catch (IOException e) {
1124                        System.out.println("IOException e");
1125                        logger.error("postsignPdf: ocurrio una excepcion", e);
1126                        e.printStackTrace();
1127                        throw new MurachiException(e.getMessage());
1128                       
1129                }
1130               
1131                String signedPdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-signed.pdf";
1132               
1133                FileOutputStream signedFile = new FileOutputStream(signedPdf);
1134               
1135                os.writeTo(signedFile);
1136                os.flush();
1137                               
1138                // en este punto el archivo pdf debe estar disponible en la ruta
1139                // SERVER_UPLOAD_LOCATION_FOLDER + fileId;             
1140                System.out.println("Archivo firmado correctamente");
1141                logger.debug("Archivo firmado correctamente");
1142                       
1143                PostsignMessage message = new PostsignMessage();
1144                //message.setMessage(SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-signed.pdf");
1145                message.setMessage("{\"signedFile\":"+fileId + "-signed.pdf}");
1146                //return Response.status(200).entity(message).build();
1147               
1148                JSONObject jsonFinalResult = new JSONObject();
1149                jsonFinalResult.put("signedFileId",fileId + "-signed.pdf");
1150               
1151                logger.info(jsonFinalResult.toString());
1152                return Response.status(200).entity(jsonFinalResult.toString()).build();
1153        }
1154       
1155        /**
1156         * Descarga el archivo pdf pasado como argumento.
1157         * @param idFile nombre del archivo pdf a descargar
1158         * @return archivo pdf pasado como argumento.
1159         */
1160        @GET
1161        @Path("/pdfs/{idFile}")
1162        public Response getPdfSigned(@PathParam("idFile") String idFile) {
1163                logger.info("/pdfs/{idFile}");
1164                File file = null;
1165               
1166                file = new File(SERVER_UPLOAD_LOCATION_FOLDER + idFile);
1167                /*
1168                if (!file.exists()){
1169                       
1170                }
1171                */
1172                         
1173                ResponseBuilder response = Response.ok((Object) file);
1174                response.header("Content-Disposition", "attachment; filename=" + file.getName());
1175                return response.build();
1176        }
1177       
1178       
1179        // ******* BDOC ***********************************************************
1180       
1181        /**
1182         * Retorna un JSON con informacion de las firmas del documento BDOC
1183         * @param bdocFile archivo BDOC a verificar
1184         * @return JSON con informacion de las firmas del documento BDOC
1185         */
1186        private JSONObject verifySignaturesInBdoc(String bdocFile) {
1187       
1188                JSONObject jsonSignatures = new JSONObject();
1189
1190                JSONArray jsonSignaturesArray = new JSONArray();
1191                JSONArray jsonContainerValidationExceptionArray = new JSONArray();
1192               
1193                Security.addProvider(new BouncyCastleProvider());
1194                Container container;
1195                container = Container.open(bdocFile);
1196               
1197                int numberOfSignatures = container.getSignatures().size();
1198                if (numberOfSignatures == 0){
1199                        jsonSignatures.put("signatureNumber", "0");
1200                }else{
1201                        jsonSignatures.put("fileExist", "true");
1202                       
1203                        // informacion de archivos dentro del contenedor
1204                        if (container.getDataFiles().size() > 0){
1205                                jsonSignatures.put("numberOfDataFiles", container.getDataFiles().size()); 
1206                                jsonSignatures.put("dataFiles", getJSONFromBDOCDataFiles(container.getDataFiles()));
1207                                System.out.println(" dataFiles:  " + getJSONFromBDOCDataFiles(container.getDataFiles()).toString());
1208                        }else{
1209                                System.out.println(" dataFiles:  == 0");
1210                        }
1211               
1212                        jsonSignatures.put("numberOfSignatures", numberOfSignatures);
1213                       
1214                        ValidationResult validationResult = container.validate();
1215                        List<DigiDoc4JException> exceptions = validationResult.getContainerErrors();
1216                       
1217                        boolean isDDoc = container.getDocumentType() == DocumentType.DDOC;
1218                       
1219                        if (exceptions.size() > 0){
1220                                jsonSignatures.put("containerValidation", false);
1221                               
1222                                for (DigiDoc4JException exception : exceptions) {
1223                                        JSONObject containerException = new JSONObject();
1224                                       
1225                                        if (isDDoc && isWarning(((DDocContainer) container).getFormat(), exception)){
1226                                                System.out.println("    Warning: " + exception.toString());
1227                                               
1228                                    }
1229                                    else{
1230                                        System.out.println((isDDoc ? "  " : "   Error_: ") + exception.toString());
1231                                       
1232                                    }
1233                                        containerException.put("containerValidationException", exception.toString());
1234                                    jsonContainerValidationExceptionArray.put(containerException);
1235                                }
1236                            if (isDDoc && (((ValidationResultForDDoc) validationResult).hasFatalErrors())) {
1237                                jsonSignatures.put("validationResultForDDocHasFatalErrors", true);
1238                                return jsonSignatures; 
1239                            }
1240                            jsonSignatures.put("containerValidationExceptions", jsonContainerValidationExceptionArray);
1241                               
1242                               
1243                        }else{
1244                                jsonSignatures.put("containerValidation", true);
1245                               
1246                                HashMap<String, String> signatureInformation;
1247                                for (int i=0; i< numberOfSignatures; i++) {
1248                                        System.out.println("===== firma " + i + " =====");
1249                                        signatureInformation = verifyBDOCSignature(container.getSignature(i), container.getDocumentType());
1250                                        System.out.println("signatureInformation.size " + signatureInformation.size());
1251                                       
1252                                        JSONObject jo = getJSONFromASignature(signatureInformation);
1253                                        //System.out.println("jo:  " + jo.toString());
1254                                        jsonSignaturesArray.put(jo);                                   
1255                                }
1256                                                               
1257                                jsonSignatures.put("signatures", jsonSignaturesArray);                                                         
1258                                System.out.println(jsonSignatures.toString());                         
1259                        }                       
1260                }
1261                //verifyBdocContainer(container);               
1262                jsonSignatures.put("validation", "executed");                           
1263                return jsonSignatures;
1264        }
1265       
1266        /**
1267         * Retorna un JSON con informacion de los DataFiles incluidos en el contenedor
1268         * @param dataFilesList lista de DataFile incluidos en el contenedor
1269         * @return JSON con informacion de los DataFiles incluidos en el contenedor
1270         */
1271        private JSONArray getJSONFromBDOCDataFiles(List<DataFile> dataFilesList) {
1272                JSONArray jsonDataFileArray = new JSONArray();
1273               
1274                for (int i = 0; i < dataFilesList.size(); i++){
1275                       
1276                        JSONObject tmpJsonDataFile = new JSONObject();
1277                        DataFile df = dataFilesList.get(i);
1278                        tmpJsonDataFile.put("dataFileSize", Long.toString(df.getFileSize()));
1279                        tmpJsonDataFile.put("filename", df.getId());
1280                        tmpJsonDataFile.put("mediaType", df.getMediaType());
1281                        tmpJsonDataFile.put("name", df.getName());
1282                        jsonDataFileArray.put(tmpJsonDataFile);
1283                }
1284               
1285                //JSONObject jsonDataFile = new JSONObject();
1286                //jsonDataFile.put("dataFiles", jsonDataFileArray);
1287               
1288                //return jsonDataFile;
1289                return jsonDataFileArray;
1290        }
1291
1292        /**
1293         * Retorna Hashmap con la informacion de una firma electronica que se verifica
1294         * @param signature firma para verificar
1295         * @param documentType tipo de documento
1296         * @return Hashmap con la informacion de una firma electronica que se verifica
1297         */
1298        private static HashMap<String, String> verifyBDOCSignature(Signature signature, DocumentType documentType) {
1299               
1300                HashMap<String, String> signatureMap = new HashMap<String, String>();
1301               
1302                boolean isDDoc = documentType == DocumentType.DDOC;
1303               
1304                List<DigiDoc4JException> signatureValidationResult = signature.validate();
1305               
1306                if (signatureValidationResult.size() > 0) {
1307                        System.out.println("Signature " + signature.getId() + " is not valid");
1308                signatureMap.put("isValid", Boolean.toString(false));
1309                int counter = 1;
1310               
1311                //JSONArray jsonValidationExceptionArray = new JSONArray();
1312                //JSONObject tmpValidationException = new JSONObject();
1313               
1314                for (DigiDoc4JException exception : signatureValidationResult) {
1315                  System.out.println((isDDoc ? "        " : "   Error: ") + exception.toString());
1316                  signatureMap.put("signature"+signature.getId()+"ValidationException"+counter, exception.toString());
1317                 
1318                  //tmpValidationException.put("ValidationException", exception.toString());             
1319                  //jsonValidationExceptionArray.put(tmpValidationException);
1320                }
1321                //signatureMap.put("validationException", jsonValidationExceptionArray);
1322             
1323              if (isDDoc && isDDocTestSignature(signature)) {
1324                System.out.println("Signature " + signature.getId() + " is a test signature");
1325                signatureMap.put("isDDocTestSignature", Boolean.toString(true));
1326              }
1327                }
1328                else{
1329                       
1330                        System.out.println("Signature " + signature.getId() + " is valid");
1331                signatureMap.put("isValid", Boolean.toString(true));
1332                }
1333                signatureMap.put("signatureId", signature.getId());
1334        signatureMap.put("signatureProfile", signature.getProfile().toString());
1335        signatureMap.put("signatureMethod", signature.getSignatureMethod());
1336        /*
1337        if (signature.getSignerRoles().size() > 0){             
1338                signatureMap.put("signerRole1", signature.getSignerRoles().get(0));
1339                if (signature.getSignerRoles().size() == 2){
1340                        signatureMap.put("signerRole2", signature.getSignerRoles().get(1));
1341                }
1342        }
1343        */
1344        signatureMap.put("signatureCity", signature.getCity());
1345        signatureMap.put("signatureState", signature.getStateOrProvince());
1346        signatureMap.put("signaturePostalCode", signature.getPostalCode());
1347        signatureMap.put("signatureCountry", signature.getCountryName());
1348        signatureMap.put("signatureSigningTime", signature.getSigningTime().toString());
1349        //signatureMap.put("signaturePolicy", signature.getPolicy());
1350        //signatureMap.put("signatureOCSPProducedAtTimestamp", signature.getProducedAt().toString());
1351        //signatureMap.put("signaturePolicyURI", signature.getSignaturePolicyURI().toString());
1352        //signatureMap.put("signatureTimestampGenerationTime", signature.getTimeStampCreationTime().toString());
1353               
1354       
1355        X509Cert signerCertificate = signature.getSigningCertificate();
1356        signatureMap.put("signerCertificateSerial", signerCertificate.getSerial());
1357        signatureMap.put("signerCertificateSubjectName", signerCertificate.getSubjectName());
1358        signatureMap.put("signerCertificateIssuer", signerCertificate.issuerName());
1359        if (signerCertificate.isValid()){
1360                signatureMap.put("signerCertificateIsValid", Boolean.toString(true));
1361        }else{
1362                signatureMap.put("signerCertificateIsValid", Boolean.toString(false));
1363        }
1364       
1365       
1366       
1367                return signatureMap;
1368        }
1369       
1370       
1371        private static void verifyBdocContainer(Container container) {
1372            ValidationResult validationResult = container.validate();
1373
1374            List<DigiDoc4JException> exceptions = validationResult.getContainerErrors();
1375            boolean isDDoc = container.getDocumentType() == DocumentType.DDOC;
1376            for (DigiDoc4JException exception : exceptions) {
1377              if (isDDoc && isWarning(((DDocContainer) container).getFormat(), exception))
1378                System.out.println("    Warning: " + exception.toString());
1379              else
1380                System.out.println((isDDoc ? "  " : "   Error_: ") + exception.toString());
1381            }
1382
1383            if (isDDoc && (((ValidationResultForDDoc) validationResult).hasFatalErrors())) {
1384              return;
1385            }
1386
1387            List<Signature> signatures = container.getSignatures();
1388            if (signatures == null) {
1389              throw new SignatureNotFoundException();
1390            }
1391
1392            for (Signature signature : signatures) {
1393              List<DigiDoc4JException> signatureValidationResult = signature.validate();
1394              if (signatureValidationResult.size() == 0) {
1395                System.out.println("Signature " + signature.getId() + " is valid");
1396              } else {
1397                System.out.println("Signature " + signature.getId() + " is not valid");
1398                for (DigiDoc4JException exception : signatureValidationResult) {
1399                  System.out.println((isDDoc ? "        " : "   Error: ")
1400                      + exception.toString());
1401                }
1402              }
1403              if (isDDoc && isDDocTestSignature(signature)) {
1404                System.out.println("Signature " + signature.getId() + " is a test signature");
1405              }
1406            }
1407
1408            showWarnings(validationResult);
1409            verboseMessage(validationResult.getReport());
1410         }
1411
1412         private static void showWarnings(ValidationResult validationResult) {
1413                 if (bdocWarnings) {
1414                         for (DigiDoc4JException warning : validationResult.getWarnings()) {
1415                                 System.out.println("Warning: " + warning.toString());
1416                     }
1417                 }
1418         }
1419         
1420         /**
1421           * Checks is DigiDoc4JException predefined as warning for DDOC
1422           *
1423           * @param documentFormat format SignedDoc
1424           * @param exception      error to check
1425           * @return is this exception warning for DDOC utility program
1426           * @see SignedDoc
1427           */
1428          public static boolean isWarning(String documentFormat, DigiDoc4JException exception) {
1429            int errorCode = exception.getErrorCode();
1430            return (errorCode == DigiDocException.ERR_DF_INV_HASH_GOOD_ALT_HASH
1431                || errorCode == DigiDocException.ERR_OLD_VER
1432                || errorCode == DigiDocException.ERR_TEST_SIGNATURE
1433                || errorCode == DigiDocException.WARN_WEAK_DIGEST
1434                || (errorCode == DigiDocException.ERR_ISSUER_XMLNS && !documentFormat.equals(SignedDoc.FORMAT_SK_XML)));
1435          }
1436
1437          private static boolean isDDocTestSignature(Signature signature) {
1438                  CertValue certValue = ((DDocSignature) signature).getCertValueOfType(CertValue.CERTVAL_TYPE_SIGNER);
1439                  if (certValue != null) {
1440                          if (DigiDocGenFactory.isTestCard(certValue.getCert())) return true;
1441                  }
1442                  return false;
1443          }
1444         
1445          private static void verboseMessage(String message) {
1446                    if (bdocVerboseMode)
1447                      System.out.println(message);
1448          }
1449
1450       
1451       
1452        /**
1453         * Verifica si un archivo posee firmas electronicas y retorna informacion
1454         * de las mismas en un json
1455         * @param idFile
1456         * @return
1457         */
1458        @GET
1459        @Path("/verificar/{idFile}")
1460        //@Produces("application/json")
1461        @Produces("text/plain")
1462        public String verifyFile(@PathParam("idFile") String idFile) {
1463               
1464                String file = SERVER_UPLOAD_LOCATION_FOLDER + idFile;
1465       
1466                //return getMimeType(file);
1467               
1468                               
1469                File tmpFile = new File(file);
1470                String result = "";
1471
1472               
1473               
1474               
1475                if (tmpFile.exists()) {
1476                        result = "El archivo existe.";
1477                       
1478                        try {
1479                                PdfReader reader = new PdfReader(file);
1480                                AcroFields af = reader.getAcroFields();
1481                                ArrayList<String> names = af.getSignatureNames();
1482                                if (names.size() > 0) {
1483                                        result = "el archivo PDF posee "+ names.size() +" firma(s).\n";
1484                                       
1485                                        // sin esto explota: se debe agregar una implementacion del provider en tiempo de ejecucion
1486                                        //http://www.cs.berkeley.edu/~jonah/bc/org/bouncycastle/jce/provider/BouncyCastleProvider.html
1487                                        Security.addProvider(new BouncyCastleProvider());
1488                                       
1489                                        for (String name: names) {
1490                                                result = result +"Nombre de la firma: "+ name + "\n";
1491                                                System.out.println("Nombre de la firma: "+ name);
1492                                               
1493                                                PdfPKCS7 pk = af.verifySignature(name);
1494                                               
1495                                                Certificate[] pkc = pk.getCertificates();
1496                                               
1497                                                String tmpSignerName = pk.getSigningCertificate().getSubjectX500Principal().toString();
1498                                               
1499                                               
1500                                                result = result + "Sujeto del certificado firmante: " + tmpSignerName + "\n"; 
1501                                                //pk.getSigningCertificate().getSubjectX500Principal().getName() + "\n";
1502                                                System.out.println("Sujeto del certificado firmante: " + 
1503                                                                pk.getSigningCertificate().getSubjectX500Principal().toString());
1504                                                 
1505                                                Calendar cal = pk.getSignDate();
1506                                               
1507                                                SimpleDateFormat date_format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
1508                                               
1509                                                //result = result + "Fecha de la firma: " + cal.toString() + "\n";
1510                                                result = result + "Fecha de la firma: " + date_format.format(cal.getTime()) + "\n";
1511                                               
1512                                                /*
1513                                                System.out.println("año: "+ cal.get(Calendar.YEAR));
1514                                                System.out.println("mes: "+ (cal.get(Calendar.MONTH) + 1));
1515                                                System.out.println("día: "+ cal.get(Calendar.DAY_OF_MONTH));
1516                                                System.out.println("hora: "+ cal.get(Calendar.HOUR));
1517                                                System.out.println("minuto: "+ cal.get(Calendar.MINUTE));
1518                                                System.out.println("segundo: "+ cal.get(Calendar.SECOND));
1519                                                */
1520                                                //SimpleDateFormat date_format = new SimpleDateFormat("dd/MM/yyyy hh:mm:ss");
1521                                            System.out.println(date_format.format(cal.getTime()));
1522
1523                                        }
1524                                       
1525                                       
1526                                }else{
1527                                        result = "el archivo PDF no posee firmas";
1528                                }
1529                               
1530                               
1531                               
1532                        } catch (IOException e) {
1533                                // TODO Auto-generated catch block
1534                                e.printStackTrace();
1535                        }
1536                       
1537                       
1538                }else {
1539                        result = "El archivo NO existe.";
1540                }
1541               
1542               
1543                return result;
1544               
1545               
1546        }
1547       
1548        /**
1549         * Ejecuta el proceso de presign o preparacion de firma de documento pdf
1550         * @param presignPar
1551         * @param req objeto request para crear una sesion y mantener elementos del
1552         * pdf en la misma
1553         * @param resp
1554         */
1555        @POST
1556        @Path("/prepararfirmapdf")
1557        @Consumes(MediaType.APPLICATION_JSON)
1558        @Produces(MediaType.APPLICATION_JSON)
1559        //public Response presign(PresignParameters presignPar, @Context HttpServletRequest req) {
1560        public PresignHash presign(PresignParameters presignPar, @Context HttpServletRequest req) {
1561               
1562
1563                // cadena resultado de la funcion
1564                String result = "";
1565               
1566                PresignHash presignHash = new PresignHash();
1567               
1568               
1569                // cadena con el certificado
1570                String certHex = presignPar.getCertificate();
1571                System.out.println("certificado en Hex: " + certHex);
1572               
1573                // obtener el id del archivo
1574                String fileId = presignPar.getFileId();
1575                               
1576                try {
1577                        CertificateFactory factory = CertificateFactory.getInstance("X.509");
1578                        Certificate[] chain = new Certificate[1];
1579                       
1580                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
1581                        chain[0] = factory.generateCertificate(in);
1582                       
1583                        if (chain[0] == null) {
1584                                System.out.println("error chain[0] == null");
1585                        }else {
1586                               
1587                                System.out.println("se cargo el certificado correctamente");
1588                                System.out.println(chain[0].toString());
1589                        }
1590                       
1591                        //String pdf = SERVER_UPLOAD_LOCATION_FOLDER + "e27a6a90-f955-4191-8e54-580e316a999d";
1592                        String pdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId;
1593                        System.out.println("archivo a firmar: " + pdf);
1594                       
1595                        PdfReader reader = new PdfReader(pdf);
1596                       
1597                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1598                       
1599                        //FileOutputStream baos = new FileOutputStream(pdf+"-signed.pdf");
1600                       
1601                        PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
1602                       
1603                        // crear la apariencia de la firma
1604                PdfSignatureAppearance sap = stamper.getSignatureAppearance();
1605                sap.setReason("Prueba de firma en dos partes");
1606                sap.setLocation("Merida, Venezuela");
1607                sap.setVisibleSignature(new Rectangle(36, 748, 144,780),1, "sig");
1608                sap.setCertificate(chain[0]);
1609               
1610                // crear la estructura de la firma
1611                PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
1612                dic.setReason(sap.getReason());
1613                dic.setLocation(sap.getLocation());
1614                dic.setContact(sap.getContact());
1615                dic.setDate(new PdfDate(sap.getSignDate()));
1616               
1617                sap.setCryptoDictionary(dic);
1618               
1619                HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer> ();
1620                exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
1621                sap.preClose(exc);
1622               
1623                ExternalDigest externalDigest = new ExternalDigest() {
1624                        public MessageDigest getMessageDigest(String hashAlgorithm)
1625                        throws GeneralSecurityException {
1626                                return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
1627                        }
1628                };
1629                       
1630                       
1631                PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, externalDigest, false);
1632               
1633                InputStream data = sap.getRangeStream();
1634               
1635                byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));
1636               
1637                Calendar cal = Calendar.getInstance();
1638                byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
1639               
1640                sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest("SHA256"));
1641               
1642                System.out.println("sh length: "+ sh.length);
1643                       
1644                String hashToSign = byteArrayToHexString(sh);
1645                System.out.println("***************************************************************");
1646                System.out.println("HASH EN HEXADECIMAL:");
1647                System.out.println(hashToSign);
1648                System.out.println("length: " +hashToSign.length());   
1649                System.out.println("***************************************************************");
1650                       
1651                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
1652                        Date date = new Date();
1653                        System.out.println(dateFormat.format(date));
1654                        //String d = dateFormat.format(date);
1655                       
1656                       
1657                        // almacenar los objetos necesarios para realizar el postsign en una sesion
1658                        HttpSession session = req.getSession(true);
1659                        session.setAttribute("hashToSign", hashToSign);
1660                       
1661                        session.setAttribute("stamper", stamper);
1662                        session.setAttribute("sgn", sgn);
1663                        session.setAttribute("hash", hash);
1664                        session.setAttribute("cal", cal);
1665                        session.setAttribute("sap", sap);
1666                        session.setAttribute("baos", baos);
1667                        session.setAttribute("fileId", fileId);
1668                       
1669                        // creacion del json
1670                        JSONObject jsonHash = new JSONObject();
1671                        jsonHash.put("hashToSign", hashToSign);
1672                       
1673                        result = jsonHash.toString();
1674                       
1675                        presignHash.setHash(hashToSign);
1676                               
1677                       
1678                } catch (CertificateException e1) {
1679                        // TODO Auto-generated catch block
1680                        e1.printStackTrace();
1681                } catch (IOException e) {
1682                        // TODO Auto-generated catch block
1683                        e.printStackTrace();
1684                } catch (DocumentException e) {
1685                        // TODO Auto-generated catch block
1686                        e.printStackTrace();
1687                } catch (InvalidKeyException e) {
1688                        // TODO Auto-generated catch block
1689                        e.printStackTrace();
1690                } catch (NoSuchProviderException e) {
1691                        // TODO Auto-generated catch block
1692                        e.printStackTrace();
1693                } catch (NoSuchAlgorithmException e) {
1694                        // TODO Auto-generated catch block
1695                        e.printStackTrace();
1696                } catch (GeneralSecurityException e) {
1697                        // TODO Auto-generated catch block
1698                        e.printStackTrace();
1699                }
1700               
1701                //return Response.status(200).entity(result).build();
1702                return presignHash;
1703                       
1704        }
1705       
1706       
1707        /**
1708         * Ejecuta el proceso de postsign o completacion de firma de documento pdf
1709         * @param postsignPar
1710         * @param req objeto request para crear una sesion y mantener elementos del
1711         * pdf en la misma
1712         * @param resp
1713         * @throws IOException
1714         */
1715        @POST
1716        @Path("/completarfirmapdf")
1717        @Consumes(MediaType.APPLICATION_JSON)
1718        @Produces(MediaType.APPLICATION_JSON)
1719        public Response postsign(PostsignParameters postsignPar, @Context HttpServletRequest req) throws IOException {
1720               
1721               
1722                // cadena resultado de la funcion
1723                String result = "";
1724                               
1725                // cadena con la firma
1726                String signature = postsignPar.getSignature();
1727                System.out.println("firma en Hex: " + signature);
1728               
1729                HttpSession session = req.getSession(false);
1730               
1731                String fileId = (String) session.getAttribute("fileId");
1732                System.out.println("fileId: " + fileId);
1733               
1734                PdfStamper stamper = (PdfStamper) session.getAttribute("stamper");
1735               
1736                PdfPKCS7 sgn = (PdfPKCS7) session.getAttribute("sgn");
1737               
1738                byte[] hash = (byte[]) session.getAttribute("hash");
1739               
1740                Calendar cal = (Calendar) session.getAttribute("cal");
1741               
1742                PdfSignatureAppearance sap = (PdfSignatureAppearance) session.getAttribute("sap");
1743               
1744                ByteArrayOutputStream os = (ByteArrayOutputStream) session.getAttribute("baos");
1745               
1746                if (sgn == null) {
1747                        System.out.println("sgn == null");
1748                }
1749                if (hash == null) {
1750                        System.out.println("hash == null");
1751                }
1752                if (cal == null) {
1753                        System.out.println("cal == null");
1754                }
1755                if (sap == null) {
1756                        System.out.println("sap == null");
1757                }
1758                if (os == null) {
1759                        System.out.println("os == null");
1760                }
1761               
1762               
1763               
1764                // convertir signature en bytes         
1765                byte[] signatureInBytes = hexStringToByteArray(signature);
1766                               
1767                // completar el proceso de firma
1768                sgn.setExternalDigest(signatureInBytes, null, RSA_DIGEST_ENCRYPTION_ALGORITHM);
1769                byte[] encodeSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CMS);
1770                byte[] paddedSig = new byte[8192];
1771                System.arraycopy(encodeSig, 0, paddedSig, 0, encodeSig.length);
1772                PdfDictionary dic2 = new PdfDictionary();
1773                dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
1774                try {
1775                        sap.close(dic2);
1776                       
1777                        stamper.close();
1778                        System.out.println("stamper.close");
1779                       
1780                }catch(DocumentException e) {
1781                       
1782                        System.out.println("throw new IOException");
1783                        throw new IOException(e);
1784                       
1785                } catch (IOException e) {
1786                        // TODO Auto-generated catch block
1787                        System.out.println("IOException e");
1788                        e.printStackTrace();
1789                       
1790                }
1791               
1792                String signedPdf = SERVER_UPLOAD_LOCATION_FOLDER + fileId + "-signed.pdf";
1793               
1794                FileOutputStream signedFile = new FileOutputStream(signedPdf);
1795               
1796                os.writeTo(signedFile);
1797                os.flush();
1798               
1799               
1800               
1801                // en este punto el archivo pdf debe estar disponible en la ruta
1802                // SERVER_UPLOAD_LOCATION_FOLDER + fileId;
1803               
1804                // llamar a una funcion que permita descargar el archivo
1805               
1806                result = "Archivo firmado correctamente";
1807                System.out.println("Archivo firmado correctamente");
1808               
1809                return Response.status(200).entity(result).build();
1810        }
1811       
1812        /**
1813         * Ejecuta el proceso de presign o preparacion de firma de documento en formato BDOC
1814         *
1815         * @param presignPar
1816         * @param req
1817         * @return
1818         */
1819        @POST
1820        @Path("/bdoc/")
1821        @Consumes(MediaType.APPLICATION_JSON)
1822        @Produces(MediaType.APPLICATION_JSON)
1823        public PresignHash presignBdoc(PresignParameters presignPar, @Context HttpServletRequest req) {
1824               
1825                System.out.println("presignBdoc: ");
1826               
1827               
1828                String fileId;
1829                String certHex;
1830               
1831                CertificateFactory cf;
1832                X509Certificate signerCert;
1833               
1834                // cadena resultado de la funcion
1835                String result = "";
1836                               
1837                PresignHash presignHash = new PresignHash();
1838               
1839                SignedInfo signedInfo;
1840               
1841                fileId = presignPar.getFileId();
1842                String sourceFile = SERVER_UPLOAD_LOCATION_FOLDER + fileId;
1843               
1844                certHex = presignPar.getCertificate();
1845                System.out.println("certificado en Hex: " + certHex);
1846               
1847//              try {
1848                        /*             
1849                        Configuration configuration = new Configuration(Configuration.Mode.TEST);
1850                       
1851                        configuration.loadConfiguration("/home/aaraujo/desarrollo/2015/workspace-luna/JAXRS-Murachi/WebContent/WEB-INF/lib/digidoc4j.yaml");
1852                        configuration.setTslLocation("http://localhost/trusted-test-mp.xml");
1853                   
1854                        Container container = Container.create(configuration);
1855                    SignatureParameters signatureParameters = new SignatureParameters();
1856                    SignatureProductionPlace productionPlace = new SignatureProductionPlace();
1857                    productionPlace.setCity("Merida");
1858                    signatureParameters.setProductionPlace(productionPlace);
1859                    signatureParameters.setRoles(asList("Desarrollador"));
1860                    container.setSignatureParameters(signatureParameters);
1861                    container.setSignatureProfile(SignatureProfile.B_BES);
1862                    container.addDataFile("/tmp/215d6ef7-d639-4191-87a1-ef68a91b2b27", "text/plain");
1863                    container.sign(new PKCS12Signer("/tmp/JuanHilario.p12", "123456".toCharArray()));
1864//                  Container container = Container.open("util/faulty/bdoc21-bad-nonce-content.bdoc");
1865                    container.save("/tmp/signed.bdoc");
1866                    ValidationResult results = container.validate();
1867                    System.out.println(results.getReport());
1868                        */
1869
1870                       
1871                Security.addProvider(new BouncyCastleProvider());
1872                        System.setProperty("digidoc4j.mode", "TEST");
1873                       
1874                        Configuration configuration;
1875                        configuration = new Configuration(Configuration.Mode.TEST);
1876                        //configuration.loadConfiguration("/home/aaraujo/desarrollo/2015/workspace-luna/JAXRS-Murachi/WebContent/WEB-INF/lib/digidoc4j.yaml");
1877                       
1878                        //configuration.setTslLocation("https://tibisay.cenditel.gob.ve/murachi/raw-attachment/wiki/WikiStart/trusted-test-mp.xml");
1879                        configuration.setTslLocation("http://localhost/trusted-test-mp.xml");
1880                       
1881                        Container container;
1882                       
1883                        container = Container.create(Container.DocumentType.BDOC, configuration);
1884                       
1885                        SignatureParameters signatureParameters = new SignatureParameters();
1886                    SignatureProductionPlace productionPlace = new SignatureProductionPlace();
1887                    productionPlace.setCity("Merida");
1888                    signatureParameters.setProductionPlace(productionPlace);
1889                    signatureParameters.setRoles(asList("Desarrollador"));
1890                    container.setSignatureParameters(signatureParameters);
1891                    container.setSignatureProfile(SignatureProfile.B_BES);
1892                       
1893                        container.addDataFile(sourceFile, "text/plain");
1894                       
1895                        container.sign(new PKCS12Signer("/tmp/JuanHilario.p12", "123456".toCharArray()));
1896                    container.save("/tmp/signed.bdoc");
1897                    ValidationResult results = container.validate();
1898                    System.out.println(results.getReport());
1899                       
1900                        /*
1901                        cf = CertificateFactory.getInstance("X.509");
1902               
1903                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
1904                       
1905                        signerCert = (X509Certificate) cf.generateCertificate(in);
1906                       
1907                        signedInfo = container.prepareSigning(signerCert);
1908                       
1909                        String hashToSign = byteArrayToHexString(signedInfo.getDigest());
1910                        //System.out.println("presignBdoc - hash: " + byteArrayToHexString(signedInfo.getDigest()));
1911                        System.out.println("presignBdoc - hash: " + hashToSign);
1912                       
1913                       
1914                        //container.save("/tmp/containerTmp.bdoc");
1915                        serialize(container, "/tmp/containerSerialized");
1916                        */
1917                       
1918                        String hashToSign = "firma exitosa";
1919                       
1920                        // creacion del json
1921                        JSONObject jsonHash = new JSONObject();
1922                        jsonHash.put("hashToSign", hashToSign);
1923                                               
1924                        result = jsonHash.toString();
1925                                               
1926                        presignHash.setHash(hashToSign);
1927                       
1928                       
1929/*                     
1930                } catch (CertificateException e1) {
1931                        // TODO Auto-generated catch block
1932                        e1.printStackTrace();
1933                } catch (IOException e) {
1934                        // TODO Auto-generated catch block
1935                        e.printStackTrace();
1936                }
1937*/             
1938               
1939                return presignHash;
1940               
1941        }
1942       
1943       
1944        @GET
1945        @Path("/testbdoc/")
1946        public String testBdoc() {
1947               
1948                Security.addProvider(new BouncyCastleProvider());
1949               
1950                Configuration configuration = new Configuration(Configuration.Mode.TEST);
1951               
1952                configuration.loadConfiguration("/home/aaraujo/desarrollo/2015/workspace-luna/JAXRS-Murachi/WebContent/WEB-INF/lib/digidoc4j.yaml");
1953                configuration.setTslLocation("http://localhost/trusted-test-mp.xml");
1954               
1955            Container container = Container.create(configuration);
1956            SignatureParameters signatureParameters = new SignatureParameters();
1957            SignatureProductionPlace productionPlace = new SignatureProductionPlace();
1958            productionPlace.setCity("Merida");
1959            signatureParameters.setProductionPlace(productionPlace);
1960            signatureParameters.setRoles(asList("Desarrollador"));
1961            container.setSignatureParameters(signatureParameters);
1962            container.setSignatureProfile(SignatureProfile.B_BES);
1963            container.addDataFile("/tmp/01311213-5756-4707-a73d-6d42b09b26fd", "text/plain");
1964            container.sign(new PKCS12Signer("/tmp/JuanHilario.p12", "123456".toCharArray()));
1965//          Container container = Container.open("util/faulty/bdoc21-bad-nonce-content.bdoc");
1966            container.save("/tmp/signed.bdoc");
1967            ValidationResult result = container.validate();
1968            System.out.println(result.getReport());
1969               
1970                return "test";
1971        }
1972       
1973       
1974       
1975       
1976       
1977        /**
1978         * Prueba de ejecucion de programa desde consola. Incompleta
1979         * @return
1980         * @throws InterruptedException
1981         */
1982        @GET
1983        @Path("/ejecutar")
1984        @Produces("text/plain")
1985        public String executeProcess() throws InterruptedException {
1986               
1987               
1988                String line = "";
1989                OutputStream stdin = null;
1990                InputStream stderr = null;
1991                InputStream stdout = null;
1992               
1993                try {
1994                        System.out.print("...a crear el proceso");
1995                        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");
1996                        //Process process = Runtime.getRuntime().exec("ls -l");
1997                        stdin = process.getOutputStream();
1998                        stderr = process.getErrorStream();
1999                        stdout = process.getInputStream();
2000                       
2001                        InputStreamReader isr = new InputStreamReader(stdout);
2002                        BufferedReader buff = new BufferedReader (isr);
2003
2004                       
2005                        while((line = buff.readLine()) != null)
2006                                System.out.print(line+"\n");
2007                        int exitValue = process.waitFor();
2008                        if (exitValue != 0) {
2009                            System.out.println("Abnormal process termination");
2010                        }       
2011                       
2012                } catch (IOException e) {
2013                        // TODO Auto-generated catch block
2014                        e.printStackTrace();
2015                }
2016                System.out.print("...saliendo");
2017                return line;
2018        }
2019       
2020       
2021       
2022       
2023       
2024        /**
2025         *
2026         * @param certHex
2027         * @param httpHeaders
2028         * @param req
2029         * @param resp
2030         */
2031        @POST
2032        @Path("/presignOld")
2033        @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
2034        public void presignOld(
2035                        @FormParam("certHexInForm") String certHex,
2036                        @Context HttpHeaders httpHeaders,
2037                        @Context HttpServletRequest req,
2038                        @Context HttpServletResponse resp) {
2039               
2040
2041                String host = httpHeaders.getRequestHeader("host").get(0);
2042               
2043                String agent = httpHeaders.getRequestHeader("user-agent").get(0);
2044                String salida = "User agent :"+ agent +" from host : "+host;
2045                System.out.println(host);
2046                System.out.println(agent);
2047                System.out.println(salida);
2048               
2049                System.out.println("certificado en Hex: " + certHex);
2050               
2051                try {
2052                        CertificateFactory factory = CertificateFactory.getInstance("X.509");
2053                        Certificate[] chain = new Certificate[1];
2054                       
2055                        InputStream in = new ByteArrayInputStream(hexStringToByteArray(certHex));
2056                        chain[0] = factory.generateCertificate(in);
2057                       
2058                        if (chain[0] == null) {
2059                                System.out.println("error chain[0] == null");
2060                        }else {
2061                               
2062                                System.out.println("se cargo el certificado correctamente");
2063                                System.out.println(chain[0].toString());
2064                        }
2065                       
2066                        String pdf = SERVER_UPLOAD_LOCATION_FOLDER + "e27a6a90-f955-4191-8e54-580e316a999d";
2067                       
2068                        PdfReader reader = new PdfReader(pdf);
2069                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
2070                        PdfStamper stamper = PdfStamper.createSignature(reader, baos, '\0');
2071                       
2072                        // crear la apariencia de la firma
2073                PdfSignatureAppearance sap = stamper.getSignatureAppearance();
2074                sap.setReason("Prueba de firma en dos partes");
2075                sap.setLocation("Merida, Venezuela");
2076                sap.setVisibleSignature(new Rectangle(36, 748, 144,780),1, "sig");
2077                sap.setCertificate(chain[0]);
2078               
2079                // crear la estructura de la firma
2080                PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, PdfName.ADBE_PKCS7_DETACHED);
2081                dic.setReason(sap.getReason());
2082                dic.setLocation(sap.getLocation());
2083                dic.setContact(sap.getContact());
2084                dic.setDate(new PdfDate(sap.getSignDate()));
2085               
2086                sap.setCryptoDictionary(dic);
2087               
2088                HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer> ();
2089                exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
2090                sap.preClose(exc);
2091               
2092                ExternalDigest externalDigest = new ExternalDigest() {
2093                        public MessageDigest getMessageDigest(String hashAlgorithm)
2094                        throws GeneralSecurityException {
2095                                return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
2096                        }
2097                };
2098                       
2099                       
2100                PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, externalDigest, false);
2101               
2102                InputStream data = sap.getRangeStream();
2103               
2104                byte hash[] = DigestAlgorithms.digest(data, externalDigest.getMessageDigest("SHA256"));
2105               
2106                Calendar cal = Calendar.getInstance();
2107                byte sh[] = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
2108               
2109                sh = DigestAlgorithms.digest(new ByteArrayInputStream(sh), externalDigest.getMessageDigest("SHA256"));
2110               
2111                System.out.println("sh length: "+ sh.length);
2112                       
2113                String hashToSign = byteArrayToHexString(sh);
2114                System.out.println("***************************************************************");
2115                System.out.println("HASH EN HEXADECIMAL:");
2116                System.out.println(hashToSign);
2117                System.out.println("length: " +hashToSign.length());   
2118                System.out.println("***************************************************************");
2119                       
2120                DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
2121                        Date date = new Date();
2122                        System.out.println(dateFormat.format(date));
2123                        String d = dateFormat.format(date);
2124                       
2125                       
2126                        // almacenar los objetos necesarios para realizar el postsign en una sesion
2127                        HttpSession session = req.getSession(true);
2128                        session.setAttribute("hashToSign", hashToSign);
2129                       
2130                        session.setAttribute("sgn", sgn);
2131                        session.setAttribute("hash", hash);
2132                        session.setAttribute("cal", cal);
2133                        session.setAttribute("sap", sap);
2134                        session.setAttribute("baos", baos);
2135                       
2136               
2137                       
2138                        resp.sendRedirect("http://localhost/murachi2.html");
2139                       
2140                       
2141                } catch (CertificateException e1) {
2142                        // TODO Auto-generated catch block
2143                        e1.printStackTrace();
2144                } catch (IOException e) {
2145                        // TODO Auto-generated catch block
2146                        e.printStackTrace();
2147                } catch (DocumentException e) {
2148                        // TODO Auto-generated catch block
2149                        e.printStackTrace();
2150                } catch (InvalidKeyException e) {
2151                        // TODO Auto-generated catch block
2152                        e.printStackTrace();
2153                } catch (NoSuchProviderException e) {
2154                        // TODO Auto-generated catch block
2155                        e.printStackTrace();
2156                } catch (NoSuchAlgorithmException e) {
2157                        // TODO Auto-generated catch block
2158                        e.printStackTrace();
2159                } catch (GeneralSecurityException e) {
2160                        // TODO Auto-generated catch block
2161                        e.printStackTrace();
2162                }
2163               
2164               
2165       
2166        }
2167       
2168       
2169        @POST
2170        @Path("/postsign")
2171        public String postsignOld(@Context HttpServletRequest req,
2172                        @Context HttpServletResponse resp) {
2173               
2174                System.out.println("...postsign()...");
2175               
2176                HttpSession session = req.getSession(false);
2177                Object att = session.getAttribute("hashToSign");
2178                               
2179       
2180                String output = "atributo leido de la sesion: " + att.toString();
2181               
2182               
2183                return output;
2184                //return Response.status(200).entity(output).build();
2185        }
2186       
2187       
2188        @GET
2189        @Path("/retornajson")
2190        @Produces(MediaType.APPLICATION_JSON)
2191        public PresignHash retornajson(@Context HttpServletRequest req) {
2192               
2193               
2194               
2195                PresignHash h = new PresignHash();
2196                h.setHash("ESTO SERIA UN HASH");
2197               
2198                System.out.println("...retornajson..."+ h.getHash());
2199               
2200                return h;
2201               
2202        }
2203       
2204        @POST
2205        @Path("/enviarjson")
2206        @Consumes(MediaType.APPLICATION_JSON)
2207        @Produces(MediaType.APPLICATION_JSON)
2208        public PresignHash recibejson( PresignParameters par) {
2209               
2210                String fileId = par.getFileId();
2211                System.out.println("...fileId recibido..."+ fileId);
2212               
2213                String cert = par.getCertificate();
2214                System.out.println("...certificate recibido..."+ cert);
2215               
2216                PresignHash h = new PresignHash();
2217                h.setHash("DEBES FIRMAR ESTO");
2218               
2219                System.out.println("...recibejson..."+ h.getHash());
2220               
2221                return h;
2222               
2223        }
2224       
2225       
2226       
2227       
2228        /**
2229         * Retorna el mimeType del archivo pasado como argumento
2230         * @param absolutFilePath ruta absoluta del archivo
2231         * @return mimeType del archivo pasado como argumento
2232         */
2233        public String getMimeType(String absolutFilePath) {
2234                               
2235                String result = "";             
2236                java.nio.file.Path source = Paths.get(absolutFilePath);
2237                try {
2238                        result = Files.probeContentType(source);                       
2239                        System.out.println(result);
2240                } catch (IOException e) {
2241                        // TODO Auto-generated catch block
2242                        e.printStackTrace();
2243                }               
2244                return result;           
2245        }
2246       
2247        /**
2248         * Convierte una cadena Hexadecimal en un arreglo de bytes
2249         * @param s cadena hexadecimal
2250         * @return arreglo de bytes resultantes de la conversion de la cadena hexadecimal
2251         */
2252        public static byte[] hexStringToByteArray(String s) {
2253            byte[] b = new byte[s.length() / 2];
2254            for (int i = 0; i < b.length; i++) {
2255              int index = i * 2;
2256              int v = Integer.parseInt(s.substring(index, index + 2), 16);
2257              b[i] = (byte) v;
2258            }
2259            return b;
2260          }
2261       
2262        /**
2263           * Converts a byte array into a hex string.
2264           * @param byteArray the byte array source
2265           * @return a hex string representing the byte array
2266           */
2267          public static String byteArrayToHexString(final byte[] byteArray) {
2268              if (byteArray == null) {
2269                  return "";
2270              }
2271              return byteArrayToHexString(byteArray, 0, byteArray.length);
2272          }
2273         
2274          public static String byteArrayToHexString(final byte[] byteArray, int startPos, int length) {
2275              if (byteArray == null) {
2276                  return "";
2277              }
2278              if(byteArray.length < startPos+length){
2279                  throw new IllegalArgumentException("startPos("+startPos+")+length("+length+") > byteArray.length("+byteArray.length+")");
2280              }
2281//            int readBytes = byteArray.length;
2282              StringBuilder hexData = new StringBuilder();
2283              int onebyte;
2284              for (int i = 0; i < length; i++) {
2285                  onebyte = ((0x000000ff & byteArray[startPos+i]) | 0xffffff00);
2286                  hexData.append(Integer.toHexString(onebyte).substring(6));
2287              }
2288              return hexData.toString();
2289          }
2290       
2291          /**
2292           * Serializa el contenedor BDOC pasado como argumento
2293           * @param container Contenedor que se desea serializar
2294           * @param filePath ruta absoluta al archivo serializado
2295           * @throws IOException
2296           */
2297          private static void serialize(Container container, String filePath) throws IOException {
2298                  FileOutputStream fileOut = new FileOutputStream(filePath+".bin");
2299                  ObjectOutputStream out = new ObjectOutputStream(fileOut);
2300                  out.writeObject(container);
2301                  out.flush();
2302                  out.close();
2303                  fileOut.close();
2304          }
2305         
2306          /**
2307           * Deserializa el contenedor BDOC pasado como argumento
2308           * @param filePath ruta absoluta al contenedor que se desea deserializar
2309           * @return contenedor deserializado
2310           * @throws IOException
2311           * @throws ClassNotFoundException
2312           */
2313          private static Container deserializer(String filePath) throws IOException, ClassNotFoundException {
2314                  //FileInputStream fileIn = new FileInputStream("container.bin");
2315                  FileInputStream fileIn = new FileInputStream(filePath);
2316                  ObjectInputStream in = new ObjectInputStream(fileIn);
2317                  Container container = (Container) in.readObject();
2318                  in.close();
2319                  fileIn.close();
2320                  return container;
2321          }
2322         
2323}
Note: See TracBrowser for help on using the repository browser.