Example usage for com.lowagie.text.pdf PdfReader getCertificationLevel

List of usage examples for com.lowagie.text.pdf PdfReader getCertificationLevel

Introduction

In this page you can find the example usage for com.lowagie.text.pdf PdfReader getCertificationLevel.

Prototype

public int getCertificationLevel() 

Source Link

Document

Gets the certification level for this document.

Usage

From source file:es.gob.afirma.signers.pades.PAdESSigner.java

License:Open Source License

@SuppressWarnings("boxing")
static byte[] signPDF(final PrivateKey key, final java.security.cert.Certificate[] certChain,
        final byte[] inPDF, final Properties extraParams, final String algorithm)
        throws IOException, AOException, DocumentException, NoSuchAlgorithmException, CertificateException {

    // *********************************************************************************************************************
    // **************** LECTURA PARAMETROS ADICIONALES *********************************************************************
    // *********************************************************************************************************************

    // Imagen de la rubrica
    final Image rubric = getRubricImage(extraParams.getProperty("signatureRubricImage")); //$NON-NLS-1$

    // Usar hora y fecha del sistema
    final boolean useSystemDateTime = Boolean
            .parseBoolean(extraParams.getProperty("applySystemDate", Boolean.TRUE.toString())); //$NON-NLS-1$

    // Motivo de la firma
    final String reason = extraParams.getProperty("signReason"); //$NON-NLS-1$

    // Nombre del campo de firma preexistente en el PDF a usar
    final String signatureField = extraParams.getProperty("signatureField"); //$NON-NLS-1$

    // Lugar de realizacion de la firma
    final String signatureProductionCity = extraParams.getProperty("signatureProductionCity"); //$NON-NLS-1$

    // Datos de contacto (correo electronico) del firmante
    final String signerContact = extraParams.getProperty("signerContact"); //$NON-NLS-1$

    // Pagina donde situar la firma visible
    int page = LAST_PAGE;
    try {/*from  w ww.j ava 2  s .co m*/
        page = Integer.parseInt(extraParams.getProperty("signaturePage")); //$NON-NLS-1$
    } catch (final Exception e) {
        /* Se deja la pagina tal y como esta */
    }

    // Nombre del subfiltro de firma en el diccionario PDF
    final String signatureSubFilter = extraParams.getProperty("signatureSubFilter"); //$NON-NLS-1$

    // ******************
    // ** Adjuntos ******

    // Contenido a adjuntar (en Base64)
    final String b64Attachment = extraParams.getProperty("attach"); //$NON-NLS-1$

    // Nombre que se pondra al fichero adjunto en el PDF
    final String attachmentFileName = extraParams.getProperty("attachFileName"); //$NON-NLS-1$

    // Descripcion del adjunto
    final String attachmentDescription = extraParams.getProperty("attachDescription"); //$NON-NLS-1$

    // ** Fin Adjuntos **
    // ******************

    // Nivel de certificacion del PDF
    int certificationLevel;
    try {
        certificationLevel = extraParams.getProperty("certificationLevel") != null ? //$NON-NLS-1$
                Integer.parseInt(extraParams.getProperty("certificationLevel")) : //$NON-NLS-1$
                -1;
    } catch (final Exception e) {
        certificationLevel = UNDEFINED;
    }

    // *****************************
    // **** Texto firma visible ****

    // Texto en capa 4
    final String layer4Text = extraParams.getProperty("layer4Text"); //$NON-NLS-1$

    // Texto en capa 2
    final String layer2Text = extraParams.getProperty("layer2Text"); //$NON-NLS-1$

    // Tipo de letra en capa 2
    int layer2FontFamily;
    try {
        layer2FontFamily = extraParams.getProperty("layer2FontFamily") != null ? //$NON-NLS-1$
                Integer.parseInt(extraParams.getProperty("layer2FontFamily")) : //$NON-NLS-1$
                -1;
    } catch (final Exception e) {
        layer2FontFamily = UNDEFINED;
    }

    // Tamano del tipo de letra en capa 2
    int layer2FontSize;
    try {
        layer2FontSize = extraParams.getProperty("layer2FontSize") != null ? //$NON-NLS-1$
                Integer.parseInt(extraParams.getProperty("layer2FontSize")) : //$NON-NLS-1$
                -1;
    } catch (final Exception e) {
        layer2FontSize = UNDEFINED;
    }

    // Estilo del tipo de letra en capa 2
    int layer2FontStyle;
    try {
        layer2FontStyle = extraParams.getProperty("layer2FontStyle") != null ? //$NON-NLS-1$
                Integer.parseInt(extraParams.getProperty("layer2FontStyle")) : //$NON-NLS-1$
                -1;
    } catch (final Exception e) {
        layer2FontStyle = UNDEFINED;
    }

    // Color del tipo de letra en capa 2
    final String layer2FontColor = extraParams.getProperty("layer2FontColor"); //$NON-NLS-1$

    // ** Fin texto firma visible **
    // *****************************

    // Contrasena del propietario del PDF
    String ownerPassword = extraParams.getProperty("ownerPassword"); //$NON-NLS-1$

    // Contrasena del usuario del PDF
    final String userPassword = extraParams.getProperty("userPassword"); //$NON-NLS-1$

    // *********************************************************************************************************************
    // **************** FIN LECTURA PARAMETROS ADICIONALES *****************************************************************
    // *********************************************************************************************************************

    PdfReader pdfReader;
    try {
        if (ownerPassword != null) {
            pdfReader = new PdfReader(inPDF, ownerPassword.getBytes());
        } else if (userPassword != null) {
            pdfReader = new PdfReader(inPDF, userPassword.getBytes());
        } else {
            pdfReader = new PdfReader(inPDF);
        }
    } catch (final BadPasswordException e) {
        // Comprobamos que el signer esta en modo interactivo, y si no lo
        // esta no pedimos contrasena por dialogo, principalmente para no interrumpir un firmado por lotes
        // desatendido
        if (Boolean.TRUE.toString().equalsIgnoreCase(extraParams.getProperty("headLess"))) { //$NON-NLS-1$
            throw new BadPdfPasswordException(e);
        }
        // La contrasena que nos han proporcionada no es buena o no nos
        // proporcionaron ninguna
        ownerPassword = new String(AOUIFactory.getPassword(
                ownerPassword == null ? PDFMessages.getString("AOPDFSigner.0") //$NON-NLS-1$
                        : PDFMessages.getString("AOPDFSigner.1"), //$NON-NLS-1$
                null));
        try {
            pdfReader = new PdfReader(inPDF, ownerPassword.getBytes());
        } catch (final BadPasswordException e2) {
            throw new BadPdfPasswordException(e2);
        }
    } catch (final IOException e) {
        throw new InvalidPdfException(e);
    }

    if (pdfReader.getCertificationLevel() == PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED
            && !Boolean.parseBoolean(extraParams.getProperty("allowSigningCertifiedPdfs"))) { //$NON-NLS-1$
        // Si no permitimos dialogos graficos o directamente hemos indicado que no permitimos firmar PDF certificados lanzamos
        // una excepcion
        if (Boolean.parseBoolean(extraParams.getProperty("headLess")) //$NON-NLS-1$
                || "false".equalsIgnoreCase(extraParams.getProperty("allowSigningCertifiedPdfs"))) { //$NON-NLS-1$ //$NON-NLS-2$
            throw new PdfIsCertifiedException();
        }
        // En otro caso, perguntamos al usuario
        if (AOUIFactory.NO_OPTION == AOUIFactory.showConfirmDialog(null, PDFMessages.getString("AOPDFSigner.8"), //$NON-NLS-1$
                PDFMessages.getString("AOPDFSigner.9"), //$NON-NLS-1$
                AOUIFactory.YES_NO_OPTION, AOUIFactory.WARNING_MESSAGE)) {
            throw new AOCancelledOperationException(
                    "El usuario no ha permitido la firma de un PDF certificado"); //$NON-NLS-1$
        }
    }

    // Los derechos van firmados por Adobe, y como desde iText se invalidan
    // es mejor quitarlos
    pdfReader.removeUsageRights();

    final ByteArrayOutputStream baos = new ByteArrayOutputStream();

    // Activar el atributo de "agregar firma" (cuarto parametro del metodo
    // "PdfStamper.createSignature") hace que se cree una nueva revision del
    // documento y evita que las firmas previas queden invalidadas. Sin embargo, este
    // exige que el PDF no incorpore ningun error, asi que lo mantendremos desactivado
    // para la primera firma y activado para las subsiguientes. Un error incorporado
    // en un PDF erroneo puede quedar subsanado en su version firmada, haciendo
    // posible incorporar nuevas firmas agregando revisiones del documento.
    final PdfStamper stp;
    try {
        stp = PdfStamper.createSignature(pdfReader, // PDF de entrada
                baos, // Salida
                '\0', // Mantener version
                null, // No crear temporal
                pdfReader.getAcroFields().getSignatureNames().size() > 0 // Si hay mas firmas, creo una revision
        );
    } catch (final BadPasswordException e) {
        throw new PdfIsPasswordProtectedException(e);
    }

    // Aplicamos todos los atributos de firma
    final PdfSignatureAppearance sap = stp.getSignatureAppearance();
    stp.setFullCompression();
    sap.setAcro6Layers(true);

    // PAdES parte 3 seccion 4.7 - Habilitacion para LTV
    stp.getWriter().addDeveloperExtension(new PdfDeveloperExtension(new PdfName("ESIC"), //$NON-NLS-1$
            PdfWriter.PDF_VERSION_1_7, 1));

    // Adjuntos
    if (b64Attachment != null && attachmentFileName != null) {
        byte[] attachment = null;
        try {
            attachment = Base64.decode(b64Attachment);
        } catch (final IOException e) {
            LOGGER.warning("Se ha indicado un adjunto, pero no estaba en formato Base64, se ignorara : " + e); //$NON-NLS-1$
        }
        if (attachment != null) {
            stp.getWriter().addFileAttachment(attachmentDescription, attachment, null, attachmentFileName);
        }
    }

    // iText antiguo
    sap.setRender(PdfSignatureAppearance.SignatureRenderDescription);
    // En iText nuevo seria "sap.setRenderingMode(PdfSignatureAppearance.RenderingMode.NAME_AND_DESCRIPTION);"

    // Razon de firma
    if (reason != null) {
        sap.setReason(reason);
    }

    // Establecer fecha local del equipo
    if (useSystemDateTime) {
        sap.setSignDate(new GregorianCalendar());
    }

    // Gestion de los cifrados
    if (pdfReader.isEncrypted() && (ownerPassword != null || userPassword != null)) {
        if (Boolean.TRUE.toString().equalsIgnoreCase(extraParams.getProperty("avoidEncryptingSignedPdfs"))) { //$NON-NLS-1$
            LOGGER.info(
                    "Aunque el PDF original estaba encriptado no se encriptara el PDF firmado (se establecio el indicativo 'avoidEncryptingSignedPdfs')" //$NON-NLS-1$
            );
        } else {
            LOGGER.info("El PDF original estaba encriptado, se intentara encriptar tambien el PDF firmado" //$NON-NLS-1$
            );
            try {
                stp.setEncryption(ownerPassword != null ? ownerPassword.getBytes() : null,
                        userPassword != null ? userPassword.getBytes() : null, pdfReader.getPermissions(),
                        pdfReader.getCryptoMode());
            } catch (final DocumentException de) {
                LOGGER.warning("No se ha podido cifrar el PDF destino, se escribira sin contrasena: " + de //$NON-NLS-1$
                );
            }
        }
    }

    // Pagina en donde se imprime la firma
    if (page == LAST_PAGE) {
        page = pdfReader.getNumberOfPages();
    }

    // Posicion de la firma
    final Rectangle signaturePositionOnPage = getSignaturePositionOnPage(extraParams);
    if (signaturePositionOnPage != null && signatureField == null) {
        sap.setVisibleSignature(signaturePositionOnPage, page, null);
    } else if (signatureField != null) {
        sap.setVisibleSignature(signatureField);
    }

    // Localizacion en donde se produce la firma
    if (signatureProductionCity != null) {
        sap.setLocation(signatureProductionCity);
    }

    // Contacto del firmante
    if (signerContact != null) {
        sap.setContact(signerContact);
    }

    // Rubrica de la firma
    if (rubric != null) {
        sap.setImage(rubric);
        sap.setLayer2Text(""); //$NON-NLS-1$
        sap.setLayer4Text(""); //$NON-NLS-1$
    }

    // **************************
    // ** Texto en las capas ****
    // **************************

    // Capa 2
    if (layer2Text != null) {

        sap.setLayer2Text(layer2Text);

        final int layer2FontColorR;
        final int layer2FontColorG;
        final int layer2FontColorB;
        if ("black".equalsIgnoreCase(layer2FontColor)) { //$NON-NLS-1$
            layer2FontColorR = 0;
            layer2FontColorG = 0;
            layer2FontColorB = 0;
        } else if ("white".equalsIgnoreCase(layer2FontColor)) { //$NON-NLS-1$
            layer2FontColorR = 255;
            layer2FontColorG = 255;
            layer2FontColorB = 255;
        } else if ("lightGray".equalsIgnoreCase(layer2FontColor)) { //$NON-NLS-1$
            layer2FontColorR = 192;
            layer2FontColorG = 192;
            layer2FontColorB = 192;
        } else if ("gray".equalsIgnoreCase(layer2FontColor)) { //$NON-NLS-1$
            layer2FontColorR = 128;
            layer2FontColorG = 128;
            layer2FontColorB = 128;
        } else if ("darkGray".equalsIgnoreCase(layer2FontColor)) { //$NON-NLS-1$
            layer2FontColorR = 64;
            layer2FontColorG = 64;
            layer2FontColorB = 64;
        } else if ("red".equalsIgnoreCase(layer2FontColor)) { //$NON-NLS-1$
            layer2FontColorR = 255;
            layer2FontColorG = 0;
            layer2FontColorB = 0;
        } else if ("pink".equalsIgnoreCase(layer2FontColor)) { //$NON-NLS-1$
            layer2FontColorR = 255;
            layer2FontColorG = 175;
            layer2FontColorB = 175;
        } else if (layer2FontColor == null) {
            layer2FontColorR = 0;
            layer2FontColorG = 0;
            layer2FontColorB = 0;
        } else {
            LOGGER.warning("No se soporta el color '" + layer2FontColor //$NON-NLS-1$
                    + "' para el texto de la capa 4, se usara negro"); //$NON-NLS-1$
            layer2FontColorR = 0;
            layer2FontColorG = 0;
            layer2FontColorB = 0;
        }

        com.lowagie.text.Font font;
        try {
            Class<?> colorClass;
            if (Platform.getOS() == OS.ANDROID) {
                colorClass = Class.forName("harmony.java.awt.Color"); //$NON-NLS-1$
            } else {
                colorClass = Class.forName("java.awt.Color"); //$NON-NLS-1$
            }
            final Object color = colorClass.getConstructor(Integer.TYPE, Integer.TYPE, Integer.TYPE)
                    .newInstance(layer2FontColorR, layer2FontColorG, layer2FontColorB);

            font = com.lowagie.text.Font.class
                    .getConstructor(Integer.TYPE, Integer.TYPE, Integer.TYPE, colorClass).newInstance(
                            // Family (COURIER = 0, HELVETICA = 1, TIMES_ROMAN = 2, SYMBOL = 3, ZAPFDINGBATS = 4)
                            layer2FontFamily == UNDEFINED ? COURIER : layer2FontFamily,
                            // Size (DEFAULTSIZE = 12)
                            layer2FontSize == UNDEFINED ? DEFAULT_LAYER_2_FONT_SIZE : layer2FontSize,
                            // Style (NORMAL = 0, BOLD = 1, ITALIC = 2, BOLDITALIC = 3, UNDERLINE = 4, STRIKETHRU = 8)
                            layer2FontStyle == UNDEFINED ? com.lowagie.text.Font.NORMAL : layer2FontStyle,
                            // Color
                            color);

        } catch (Exception e) {
            font = new com.lowagie.text.Font(
                    // Family (COURIER = 0, HELVETICA = 1, TIMES_ROMAN = 2, SYMBOL = 3, ZAPFDINGBATS = 4)
                    layer2FontFamily == UNDEFINED ? COURIER : layer2FontFamily,
                    // Size (DEFAULTSIZE = 12)
                    layer2FontSize == UNDEFINED ? DEFAULT_LAYER_2_FONT_SIZE : layer2FontSize,
                    // Style (NORMAL = 0, BOLD = 1, ITALIC = 2, BOLDITALIC = 3, UNDERLINE = 4, STRIKETHRU = 8)
                    layer2FontStyle == UNDEFINED ? com.lowagie.text.Font.NORMAL : layer2FontStyle,
                    // Color
                    null);
        }
        sap.setLayer2Font(font);
    }

    // Capa 4
    if (layer4Text != null) {
        sap.setLayer4Text(layer4Text);
    }

    // ***************************
    // ** Fin texto en las capas *
    // ***************************

    sap.setCrypto(null, certChain, null, null);

    final PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE,
            signatureSubFilter != null && !"".equals(signatureSubFilter) ? new PdfName(signatureSubFilter) //$NON-NLS-1$
                    : PdfName.ADBE_PKCS7_DETACHED);

    // Fecha de firma
    if (sap.getSignDate() != null) {
        dic.setDate(new PdfDate(sap.getSignDate()));
    }

    dic.setName(PdfPKCS7.getSubjectFields((X509Certificate) certChain[0]).getField("CN")); //$NON-NLS-1$
    if (sap.getReason() != null) {
        dic.setReason(sap.getReason());
    }

    // Lugar de la firma
    if (sap.getLocation() != null) {
        dic.setLocation(sap.getLocation());
    }

    // Contacto del firmante
    if (sap.getContact() != null) {
        dic.setContact(sap.getContact());
    }

    sap.setCryptoDictionary(dic);

    // Certificacion del PDF (NOT_CERTIFIED = 0, CERTIFIED_NO_CHANGES_ALLOWED = 1,
    // CERTIFIED_FORM_FILLING = 2, CERTIFIED_FORM_FILLING_AND_ANNOTATIONS = 3)
    if (certificationLevel != -1) {
        sap.setCertificationLevel(certificationLevel);
    }

    // Reservamos el espacio necesario en el PDF para insertar la firma
    final HashMap<PdfName, Integer> exc = new HashMap<PdfName, Integer>();
    exc.put(PdfName.CONTENTS, Integer.valueOf(CSIZE * 2 + 2));

    sap.preClose(exc);

    // ********************************************************************************
    // **************** CALCULO DEL SIGNED DATA ***************************************
    // ********************************************************************************

    // La norma PAdES establece que si el algoritmo de huella digital es SHA1 debe usarse SigningCertificateV2, y en cualquier
    // otro caso deberia usarse SigningCertificateV2
    boolean signingCertificateV2;
    if (extraParams.containsKey("signingCertificateV2")) { //$NON-NLS-1$
        signingCertificateV2 = Boolean.parseBoolean(extraParams.getProperty("signingCertificateV2")); //$NON-NLS-1$
    } else {
        signingCertificateV2 = !"SHA1".equals(AOSignConstants.getDigestAlgorithmName(algorithm)); //$NON-NLS-1$
    }

    byte[] completeCAdESSignature = GenCAdESEPESSignedData.generateSignedData(
            new P7ContentSignerParameters(inPDF, algorithm), true, // omitContent
            new AdESPolicy(extraParams), signingCertificateV2, key, certChain,
            MessageDigest.getInstance(AOSignConstants.getDigestAlgorithmName(algorithm))
                    .digest(AOUtil.getDataFromInputStream(sap.getRangeStream())),
            AOSignConstants.getDigestAlgorithmName(algorithm), true, // Modo PAdES
            PDF_OID,
            extraParams.getProperty("contentDescription") != null //$NON-NLS-1$
                    ? extraParams.getProperty("contentDescription") //$NON-NLS-1$
                    : PDF_DESC);

    //***************** SELLO DE TIEMPO ****************
    final String tsa = extraParams.getProperty("tsaURL"); //$NON-NLS-1$
    URI tsaURL;
    if (tsa != null) {
        try {
            tsaURL = new URI(tsa);
        } catch (final Exception e) {
            LOGGER.warning("Se ha indicado una URL de TSA invalida (" + tsa //$NON-NLS-1$
                    + "), no se anadira sello de tiempo: " + e); //$NON-NLS-1$
            tsaURL = null;
        }
        if (tsaURL != null) {
            final String tsaPolicy = extraParams.getProperty("tsaPolicy"); //$NON-NLS-1$
            if (tsaPolicy == null) {
                LOGGER.warning(
                        "Se ha indicado una URL de TSA pero no una politica, no se anadira sello de tiempo"); //$NON-NLS-1$
            } else {
                final String tsaHashAlgorithm = extraParams.getProperty("tsaHashAlgorithm"); //$NON-NLS-1$
                completeCAdESSignature = new CMSTimestamper(
                        !Boolean.FALSE.toString().equalsIgnoreCase(extraParams.getProperty("tsaRequireCert")), //$NON-NLS-1$
                        tsaPolicy, tsaURL, extraParams.getProperty("tsaUsr"), //$NON-NLS-1$
                        extraParams.getProperty("tsaPwd"), //$NON-NLS-1$
                        extraParams.getProperty("tsaExtensionOid") != null //$NON-NLS-1$
                                && extraParams.getProperty("tsaExtensionValueBase64") != null ? //$NON-NLS-1$
                                        new TsaRequestExtension[] { new TsaRequestExtension(
                                                extraParams.getProperty("tsaExtensionOid"), //$NON-NLS-1$
                                                Boolean.getBoolean(extraParams
                                                        .getProperty("tsaExtensionCritical", "false")), //$NON-NLS-1$ //$NON-NLS-2$
                                                Base64.decode(
                                                        extraParams.getProperty("tsaExtensionValueBase64")) //$NON-NLS-1$
                                        ) } : null).addTimestamp(completeCAdESSignature,
                                                AOAlgorithmID.getOID(AOSignConstants.getDigestAlgorithmName(
                                                        tsaHashAlgorithm != null ? tsaHashAlgorithm : "SHA1"))); //$NON-NLS-1$
            }
        }

    }
    //************** FIN SELLO DE TIEMPO ****************

    // ********************************************************************************
    // *************** FIN CALCULO DEL SIGNED DATA ************************************
    // ********************************************************************************

    final byte[] outc = new byte[CSIZE];
    if (outc.length < completeCAdESSignature.length) {
        throw new AOException("La firma generada tiene un tamano (" + completeCAdESSignature.length //$NON-NLS-1$
                + ") mayor que el permitido (" + outc.length + ")" //$NON-NLS-1$ //$NON-NLS-2$
        );
    }
    final PdfDictionary dic2 = new PdfDictionary();
    System.arraycopy(completeCAdESSignature, 0, outc, 0, completeCAdESSignature.length);
    dic2.put(PdfName.CONTENTS, new PdfString(outc).setHexWriting(true));

    sap.close(dic2);

    return baos.toByteArray();
}

From source file:net.sf.jsignpdf.verify.VerifierLogic.java

License:Mozilla Public License

/**
 * Verifies signature(s) in PDF document.
 * //from   w ww  . jav a2  s . co m
 * @param tmpReader
 *            PdfReader for given PDF
 * @return
 */
@SuppressWarnings("unchecked")
private VerificationResult verify(final PdfReader tmpReader) {
    final VerificationResult tmpResult = new VerificationResult();
    try {
        final AcroFields tmpAcroFields = tmpReader.getAcroFields();
        final List<String> tmpNames = tmpAcroFields.getSignatureNames();
        tmpResult.setTotalRevisions(tmpAcroFields.getTotalRevisions());

        final int lastSignatureIdx = tmpNames.size() - 1;
        if (lastSignatureIdx < 0) {
            // there is no signature
            tmpResult.setWithoutSignature();
        }
        for (int i = lastSignatureIdx; i >= 0; i--) {
            final String name = tmpNames.get(i);
            final SignatureVerification tmpVerif = new SignatureVerification(name);
            tmpVerif.setLastSignature(i == lastSignatureIdx);
            tmpVerif.setWholeDocument(tmpAcroFields.signatureCoversWholeDocument(name));
            tmpVerif.setRevision(tmpAcroFields.getRevision(name));
            final PdfPKCS7 pk = tmpAcroFields.verifySignature(name);
            final TimeStampToken tst = pk.getTimeStampToken();
            tmpVerif.setTsTokenPresent(tst != null);
            tmpVerif.setTsTokenValidationResult(validateTimeStampToken(tst));
            tmpVerif.setDate(pk.getTimeStampDate() != null ? pk.getTimeStampDate() : pk.getSignDate());
            tmpVerif.setLocation(pk.getLocation());
            tmpVerif.setReason(pk.getReason());
            tmpVerif.setSignName(pk.getSignName());
            final Certificate pkc[] = pk.getCertificates();
            final X509Name tmpX509Name = PdfPKCS7.getSubjectFields(pk.getSigningCertificate());
            tmpVerif.setSubject(tmpX509Name.toString());
            tmpVerif.setModified(!pk.verify());
            tmpVerif.setOcspPresent(pk.getOcsp() != null);
            tmpVerif.setOcspValid(pk.isRevocationValid());
            tmpVerif.setCrlPresent(pk.getCRLs() != null && pk.getCRLs().size() > 0);
            tmpVerif.setFails(PdfPKCS7.verifyCertificates(pkc, kall, pk.getCRLs(), tmpVerif.getDate()));
            tmpVerif.setSigningCertificate(pk.getSigningCertificate());

            // generate CertPath
            List<Certificate> certList = Arrays.asList(pkc);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            CertPath cp = cf.generateCertPath(certList);
            tmpVerif.setCertPath(cp);

            // to save time - check OCSP in certificate only if document's OCSP is not present and valid
            if (!tmpVerif.isOcspValid()) {
                // try to get OCSP url from signing certificate 
                String url = PdfPKCS7.getOCSPURL((X509Certificate) pk.getSigningCertificate());
                tmpVerif.setOcspInCertPresent(url != null);

                if (url != null) {
                    // OCSP url is found in signing certificate - verify certificate with that url
                    tmpVerif.setOcspInCertValid(validateCertificateOCSP(pk.getSignCertificateChain(), url));
                }
            }

            String certificateAlias = kall.getCertificateAlias(pk.getSigningCertificate());
            if (certificateAlias != null) {
                // this means that signing certificate is directly trusted

                String verifyCertificate = PdfPKCS7.verifyCertificate(pk.getSigningCertificate(), pk.getCRLs(),
                        tmpVerif.getDate());
                if (verifyCertificate == null) {
                    // this means that signing certificate is valid
                    tmpVerif.setSignCertTrustedAndValid(true);
                }
            }

            final InputStream revision = tmpAcroFields.extractRevision(name);
            try {
                final PdfReader revisionReader = new PdfReader(revision);
                tmpVerif.setCertLevelCode(revisionReader.getCertificationLevel());
            } finally {
                if (revision != null) {
                    revision.close();
                }
            }
            tmpResult.addVerification(tmpVerif);
            if (failFast && tmpVerif.containsError()) {
                return tmpResult;
            }
        }
    } catch (Exception e) {
        tmpResult.setException(e);
    }
    return tmpResult;
}

From source file:org.signserver.module.pdfsigner.PDFSigner.java

License:Open Source License

protected byte[] addSignatureToPDFDocument(final ICryptoInstance crypto, PDFSignerParameters params,
        byte[] pdfbytes, byte[] password, int contentEstimated, final ProcessRequest request,
        final RequestContext context) throws IOException, DocumentException, CryptoTokenOfflineException,
        SignServerException, IllegalRequestException {
    // when given a content length (i.e. non-zero), it means we are running a second try
    boolean secondTry = contentEstimated != 0;

    // get signing cert certificate chain and private key
    final List<Certificate> certs = getSigningCertificateChain(crypto);
    if (certs == null) {
        throw new SignServerException("Null certificate chain. This signer needs a certificate.");
    }//from w w w .j  a va2 s. c om
    final List<Certificate> includedCerts = includedCertificates(certs);
    Certificate[] certChain = includedCerts.toArray(new Certificate[includedCerts.size()]);
    PrivateKey privKey = crypto.getPrivateKey();

    // need to check digest algorithms for DSA private key at signing
    // time since we can't be sure what key a configured alias selector gives back
    if (privKey instanceof DSAPrivateKey) {
        if (!"SHA1".equals(digestAlgorithm)) {
            throw new IllegalRequestException(
                    "Only SHA1 is permitted as digest algorithm for DSA private keys");
        }
    }

    PdfReader reader = new PdfReader(pdfbytes, password);
    boolean appendMode = true; // TODO: This could be good to have as a property in the future

    int pdfVersion;

    try {
        pdfVersion = Integer.parseInt(Character.toString(reader.getPdfVersion()));
    } catch (NumberFormatException e) {
        pdfVersion = 0;
    }

    if (LOG.isDebugEnabled()) {
        LOG.debug("PDF version: " + pdfVersion);
    }

    // Don't certify already certified documents
    if (reader.getCertificationLevel() != PdfSignatureAppearance.NOT_CERTIFIED
            && params.getCertification_level() != PdfSignatureAppearance.NOT_CERTIFIED) {
        throw new IllegalRequestException("Will not certify an already certified document");
    }

    // Don't sign documents where the certification does not allow it
    if (reader.getCertificationLevel() == PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED
            || reader.getCertificationLevel() == PdfSignatureAppearance.CERTIFIED_FORM_FILLING) {
        throw new IllegalRequestException("Will not sign a certified document where signing is not allowed");
    }

    Permissions currentPermissions = Permissions.fromInt(reader.getPermissions());

    if (params.getSetPermissions() != null && params.getRemovePermissions() != null) {
        throw new SignServerException("Signer " + workerId + " missconfigured. Only one of " + SET_PERMISSIONS
                + " and " + REMOVE_PERMISSIONS + " should be specified.");
    }

    Permissions newPermissions;
    if (params.getSetPermissions() != null) {
        newPermissions = params.getSetPermissions();
    } else if (params.getRemovePermissions() != null) {
        newPermissions = currentPermissions.withRemoved(params.getRemovePermissions());
    } else {
        newPermissions = null;
    }

    Permissions rejectPermissions = Permissions.fromSet(params.getRejectPermissions());
    byte[] userPassword = reader.computeUserPassword();
    int cryptoMode = reader.getCryptoMode();
    if (LOG.isDebugEnabled()) {
        StringBuilder buff = new StringBuilder();
        buff.append("Current permissions: ").append(currentPermissions).append("\n")
                .append("Remove permissions: ").append(params.getRemovePermissions()).append("\n")
                .append("Reject permissions: ").append(rejectPermissions).append("\n")
                .append("New permissions: ").append(newPermissions).append("\n").append("userPassword: ")
                .append(userPassword == null ? "null" : "yes").append("\n").append("ownerPassword: ")
                .append(password == null ? "no" : (isUserPassword(reader, password) ? "no" : "yes"))
                .append("\n").append("setOwnerPassword: ")
                .append(params.getSetOwnerPassword() == null ? "no" : "yes").append("\n").append("cryptoMode: ")
                .append(cryptoMode);
        LOG.debug(buff.toString());
    }

    if (appendMode && (newPermissions != null || params.getSetOwnerPassword() != null)) {
        appendMode = false;
        if (LOG.isDebugEnabled()) {
            LOG.debug("Changing appendMode to false to be able to change permissions");
        }
    }

    ByteArrayOutputStream fout = new ByteArrayOutputStream();

    // increase PDF version if needed by digest algorithm
    final char updatedPdfVersion;
    if (minimumPdfVersion > pdfVersion) {
        updatedPdfVersion = Character.forDigit(minimumPdfVersion, 10);
        if (LOG.isDebugEnabled()) {
            LOG.debug("Need to upgrade PDF to version 1." + updatedPdfVersion);
        }

        // check that the document isn't already signed 
        // when trying to upgrade version
        final AcroFields af = reader.getAcroFields();
        final List<String> sigNames = af.getSignatureNames();

        if (!sigNames.isEmpty()) {
            // TODO: in the future we might want to support
            // a fallback option in this case to allow re-signing using the same version (using append)
            throw new IllegalRequestException(
                    "Can not upgrade an already signed PDF and a higher version is required to support the configured digest algorithm");
        }

        appendMode = false;
    } else {
        updatedPdfVersion = '\0';
    }

    PdfStamper stp = PdfStamper.createSignature(reader, fout, updatedPdfVersion, null, appendMode);
    PdfSignatureAppearance sap = stp.getSignatureAppearance();

    // Set the new permissions
    if (newPermissions != null || params.getSetOwnerPassword() != null) {
        if (cryptoMode < 0) {
            cryptoMode = PdfWriter.STANDARD_ENCRYPTION_128;
            if (LOG.isDebugEnabled()) {
                LOG.debug("Setting default encryption algorithm");
            }
        }
        if (newPermissions == null) {
            newPermissions = currentPermissions;
        }
        if (params.getSetOwnerPassword() != null) {
            password = params.getSetOwnerPassword().getBytes("ISO-8859-1");
        } else if (isUserPassword(reader, password)) {
            // We do not have an owner password so lets use a random one
            password = new byte[16];
            random.nextBytes(password);
            if (LOG.isDebugEnabled()) {
                LOG.debug("Setting random owner password");
            }
        }
        stp.setEncryption(userPassword, password, newPermissions.asInt(), cryptoMode);
        currentPermissions = newPermissions;
    }

    // Reject if any permissions are rejected and the document does not use a permission password
    // or if it contains any of the rejected permissions
    if (rejectPermissions.asInt() != 0) {
        if (cryptoMode < 0 || currentPermissions.containsAnyOf(rejectPermissions)) {
            throw new IllegalRequestException("Document contains permissions not allowed by this signer");
        }
    }

    // include signer certificate crl inside cms package if requested
    CRL[] crlList = null;
    if (params.isEmbed_crl()) {
        crlList = getCrlsForChain(certs);
    }
    sap.setCrypto(null, certChain, crlList, PdfSignatureAppearance.SELF_SIGNED);

    // add visible signature if requested
    if (params.isAdd_visible_signature()) {
        int signaturePage = getPageNumberForSignature(reader, params);
        sap.setVisibleSignature(new com.lowagie.text.Rectangle(params.getVisible_sig_rectangle_llx(),
                params.getVisible_sig_rectangle_lly(), params.getVisible_sig_rectangle_urx(),
                params.getVisible_sig_rectangle_ury()), signaturePage, null);

        // set custom image if requested
        if (params.isUse_custom_image()) {
            sap.setAcro6Layers(true);
            PdfTemplate n2 = sap.getLayer(2);
            params.getCustom_image().setAbsolutePosition(0, 0);
            n2.addImage(params.getCustom_image());
        }
    }

    // Certification level
    sap.setCertificationLevel(params.getCertification_level());

    PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE, new PdfName("adbe.pkcs7.detached"));
    dic.setReason(params.getReason());
    dic.setLocation(params.getLocation());
    dic.setDate(new PdfDate(Calendar.getInstance()));

    sap.setCryptoDictionary(dic);

    // add timestamp to signature if requested
    TSAClient tsc = null;
    if (params.isUse_timestamp()) {
        final String tsaUrl = params.getTsa_url();

        if (tsaUrl != null) {
            tsc = getTimeStampClient(params.getTsa_url(), params.getTsa_username(), params.getTsa_password());
        } else {
            tsc = new InternalTSAClient(getWorkerSession(), params.getTsa_worker(), params.getTsa_username(),
                    params.getTsa_password());
        }
    }

    // embed ocsp response in cms package if requested
    // for ocsp request to be formed there needs to be issuer certificate in
    // chain
    byte[] ocsp = null;
    if (params.isEmbed_ocsp_response() && certChain.length >= 2) {
        String url;
        try {
            url = PdfPKCS7.getOCSPURL((X509Certificate) certChain[0]);
            if (url != null && url.length() > 0) {
                ocsp = new OcspClientBouncyCastle((X509Certificate) certChain[0],
                        (X509Certificate) certChain[1], url).getEncoded();
            }
        } catch (CertificateParsingException e) {
            throw new SignServerException("Error getting OCSP URL from certificate", e);
        }

    }

    PdfPKCS7 sgn;
    try {
        sgn = new PdfPKCS7(privKey, certChain, crlList, digestAlgorithm, null, false);
    } catch (InvalidKeyException e) {
        throw new SignServerException("Error constructing PKCS7 package", e);
    } catch (NoSuchProviderException e) {
        throw new SignServerException("Error constructing PKCS7 package", e);
    } catch (NoSuchAlgorithmException e) {
        throw new SignServerException("Error constructing PKCS7 package", e);
    }

    MessageDigest messageDigest;
    try {
        messageDigest = MessageDigest.getInstance(digestAlgorithm);
    } catch (NoSuchAlgorithmException e) {
        throw new SignServerException("Error creating " + digestAlgorithm + " digest", e);
    }

    Calendar cal = Calendar.getInstance();

    // calculate signature size
    if (contentEstimated == 0) {
        contentEstimated = calculateEstimatedSignatureSize(certChain, tsc, ocsp, crlList);
    }

    byte[] encodedSig = calculateSignature(sgn, contentEstimated, messageDigest, cal, params, certChain, tsc,
            ocsp, sap);

    if (LOG.isDebugEnabled()) {
        LOG.debug("Estimated size: " + contentEstimated);
        LOG.debug("Encoded length: " + encodedSig.length);
    }

    if (contentEstimated + 2 < encodedSig.length) {
        if (!secondTry) {
            int contentExact = encodedSig.length;
            LOG.warn(
                    "Estimated signature size too small, usinging accurate calculation (resulting in an extra signature computation).");

            if (LOG.isDebugEnabled()) {
                LOG.debug("Estimated size: " + contentEstimated + ", actual size: " + contentExact);
            }

            // try signing again
            return addSignatureToPDFDocument(crypto, params, pdfbytes, password, contentExact, request,
                    context);
        } else {
            // if we fail to get an accurate signature size on the second attempt, bail out (this shouldn't happen)
            throw new SignServerException("Failed to calculate signature size");
        }
    }

    byte[] paddedSig = new byte[contentEstimated];
    System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length);

    PdfDictionary dic2 = new PdfDictionary();
    dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
    sap.close(dic2);
    reader.close();

    fout.close();
    return fout.toByteArray();
}