Example usage for com.lowagie.text.pdf PdfSignatureAppearance NOT_CERTIFIED

List of usage examples for com.lowagie.text.pdf PdfSignatureAppearance NOT_CERTIFIED

Introduction

In this page you can find the example usage for com.lowagie.text.pdf PdfSignatureAppearance NOT_CERTIFIED.

Prototype

int NOT_CERTIFIED

To view the source code for com.lowagie.text.pdf PdfSignatureAppearance NOT_CERTIFIED.

Click Source Link

Usage

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

License:Mozilla Public License

/**
 * Gets validation code for this verification
 * /* w  w w  .j  a va 2s.  com*/
 * @return validation code defined in {@link SignatureVerification}
 */
public int getValidationCode() {
    int code = SignatureVerification.SIG_STAT_CODE_INFO_SIGNATURE_VALID;

    // TODO Handle case when OCRL checking fails
    // TODO Handle case when new content is added after signature with
    // certification level set
    if (isModified()) {
        // ERROR: signed revision is altered
        code = SignatureVerification.SIG_STAT_CODE_ERROR_REVISION_MODIFIED;
    } else if (!isLastSignature && getCertLevelCode() == PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED) {
        // ERROR: some signature has certification level set but document is
        // changed (at least with some additional signatures)
        code = SignatureVerification.SIG_STAT_CODE_ERROR_CERTIFICATION_BROKEN;
    } else if (isLastSignature && !isWholeDocument()
            && getCertLevelCode() != PdfSignatureAppearance.NOT_CERTIFIED) {
        // TODO What if e.g. annotations are added (which is allowed by cert
        // level)?
        // ERROR: last signature doesn't cover whole document (document is
        // changed) and certification level set
        code = SignatureVerification.SIG_STAT_CODE_ERROR_CERTIFICATION_BROKEN;
    } else if (isLastSignature && !isWholeDocument()) {
        // WARNING: last signature doesn't cover whole document - there is
        // some unsigned content in the document
        code = SignatureVerification.SIG_STAT_CODE_WARNING_UNSIGNED_CONTENT;
    } else if (!isSignCertTrustedAndValid() && getFails() != null) {
        // WARNING: there is some problem with certificate
        String errorMessage = String.valueOf(getFails()[1]).trim().toLowerCase();
        if (errorMessage.startsWith(CERT_PROBLEM_CANT_BE_VERIFIED.trim().toLowerCase())) {
            // WARNING: certificate is not trusted (can't be verified
            // against keystore)
            code = SignatureVerification.SIG_STAT_CODE_WARNING_CERTIFICATE_CANT_BE_VERIFIED;
        } else if (errorMessage.startsWith(CERT_PROBLEM_EXPIRED.trim().toLowerCase())) {
            // WARNING: certificate expired
            code = SignatureVerification.SIG_STAT_CODE_WARNING_CERTIFICATE_EXPIRED;
        } else if (errorMessage.startsWith(CERT_PROBLEM_NOT_YET_VALID.trim().toLowerCase())) {
            // WARNING: certificate not yet valid
            code = SignatureVerification.SIG_STAT_CODE_WARNING_CERTIFICATE_NOT_YET_VALID;
        } else if (errorMessage.startsWith(CERT_PROBLEM_REVOKED.trim().toLowerCase())) {
            // WARNING: certificate revoked
            code = SignatureVerification.SIG_STAT_CODE_WARNING_CERTIFICATE_REVOKED;
        } else if (errorMessage.startsWith(CERT_PROBLEM_UNSUPPORTED_CRITICAL_EXTENSION.trim().toLowerCase())) {
            // WARNING: certificate has unsupported critical extension
            code = SignatureVerification.SIG_STAT_CODE_WARNING_CERTIFICATE_UNSUPPORTED_CRITICAL_EXTENSION;
        } else if (errorMessage.startsWith(CERT_PROBLEM_INVALID_STATE.trim().toLowerCase())) {
            // WARNING: possible circular certificate chain
            code = SignatureVerification.SIG_STAT_CODE_WARNING_CERTIFICATE_INVALID_STATE;
        } else {
            // WARNING: some other certificate error
            code = SignatureVerification.SIG_STAT_CODE_WARNING_CERTIFICATE_PROBLEM;
        }
    } else if ((!isCrlPresent() || (isCrlPresent() && getFails() != null)) && !isSignCertTrustedAndValid()
            && (isOcspPresent() || isOcspInCertPresent()) && !isOcspValid() && !isOcspInCertValid()) {
        // If certificate is successfully validated against CRL - don't set
        // warning flag for OCSP (set OCSP error only if CRL doesn't exist
        // or there are some errors)
        // WARNING: OCSP validation fails
        code = SignatureVerification.SIG_STAT_CODE_WARNING_SIGNATURE_OCSP_INVALID;
    } else if (!isSignCertTrustedAndValid() && !isOcspPresent() && !isOcspInCertPresent() && !isCrlPresent()) {
        // WARNING: No revocation information (CRL or OCSP) found
        code = SignatureVerification.SIG_STAT_CODE_WARNING_NO_REVOCATION_INFO;
    } else if (!isTsTokenPresent()) {
        // WARNING: signature date/time are from the clock on the signer's
        // computer
        code = SignatureVerification.SIG_STAT_CODE_WARNING_NO_TIMESTAMP_TOKEN;
    } else if (isTsTokenPresent() && getTsTokenValidationResult() != null) {
        // WARNING: signature is timestamped but the timestamp could not be
        // verified
        code = SignatureVerification.SIG_STAT_CODE_WARNING_TIMESTAMP_INVALID;
    }
    return code;
}

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.");
    }//  w ww  .j a v  a2 s. c o m
    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();
}

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

License:Open Source License

private void extractAndProcessConfigurationProperties() throws IllegalRequestException, SignServerException {

    // The reason shown in the PDF signature
    if (config.getProperties().getProperty(PDFSigner.REASON) != null) {
        reason = config.getProperties().getProperty(PDFSigner.REASON);
    }/*from   www.  j  a  va 2  s. c  o  m*/
    LOG.debug("Using reason: " + reason);

    // The location shown in the PDF signature
    if (config.getProperties().getProperty(PDFSigner.LOCATION) != null) {
        location = config.getProperties().getProperty(PDFSigner.LOCATION);
    }
    LOG.debug("Using location: " + location);

    // are we adding visible or invisible signature
    // note : ParseBoolean returns false for everything but "True"
    if (config.getProperties().getProperty(PDFSigner.ADD_VISIBLE_SIGNATURE) != null) {
        add_visible_signature = Boolean
                .parseBoolean(config.getProperties().getProperty(PDFSigner.ADD_VISIBLE_SIGNATURE).trim());
    }
    LOG.debug("Using visible signature: " + add_visible_signature);

    // timestamp url
    if (config.getProperties().getProperty(PDFSigner.TSA_URL) != null) {
        tsa_url = config.getProperties().getProperty(PDFSigner.TSA_URL);
        use_timestamp = true;
        LOG.debug("Using tsa url : " + tsa_url);
    } else if (config.getProperties().getProperty(PDFSigner.TSA_WORKER) != null) {
        tsa_worker = config.getProperties().getProperty(PDFSigner.TSA_WORKER);
        use_timestamp = true;
    }

    if (use_timestamp && config.getProperties().getProperty(PDFSigner.TSA_USERNAME) != null
            && config.getProperties().getProperty(PDFSigner.TSA_PASSWORD) != null) {
        tsa_username = config.getProperties().getProperty(PDFSigner.TSA_USERNAME);
        tsa_password = config.getProperties().getProperty(PDFSigner.TSA_PASSWORD);
        use_timestamp_authorization = true;
    }

    // should we embed crl inside the cms package
    if (config.getProperties().getProperty(PDFSigner.EMBED_CRL) != null) {
        embed_crl = Boolean.parseBoolean(config.getProperties().getProperty(PDFSigner.EMBED_CRL).trim());
    }
    LOG.debug("Using embed crl inside cms package : " + isEmbed_crl());

    // should we embed ocsp response inside the cms package
    if (config.getProperties().getProperty(PDFSigner.EMBED_OCSP_RESPONSE) != null) {
        embed_ocsp_response = Boolean
                .parseBoolean(config.getProperties().getProperty(PDFSigner.EMBED_OCSP_RESPONSE).trim());
    }
    LOG.debug("Using embed ocsp inside cms package : " + isEmbed_ocsp_response());

    // should we refuse PDF documents that contains multiple
    // indirect objects with the same name
    if (config.getProperties().getProperty(PDFSigner.REFUSE_DOUBLE_INDIRECT_OBJECTS) != null) {
        refuseDoubleIndirectObjects = Boolean
                .parseBoolean(config.getProperties().getProperty(PDFSigner.REFUSE_DOUBLE_INDIRECT_OBJECTS));
    }

    // Reject permissions
    String rejectPermissionsValue = config.getProperties().getProperty(PDFSigner.REJECT_PERMISSIONS);
    if (rejectPermissionsValue != null) {
        String[] array = rejectPermissionsValue.split(",");
        rejectPermissions.addAll(Arrays.asList(array));
    }
    // Set permissions
    String setPermissionsValue = config.getProperties().getProperty(PDFSigner.SET_PERMISSIONS);
    if (setPermissionsValue != null) {
        String[] array = setPermissionsValue.split(",");
        try {
            setPermissions = Permissions.fromSet(Arrays.asList(array), true);
        } catch (UnknownPermissionException ex) {
            throw new SignServerException("Signer " + workerId + " missconfigured: " + ex.getMessage());
        }
    }
    // Remove permissions
    String removePermissionsValue = config.getProperties().getProperty(PDFSigner.REMOVE_PERMISSIONS);
    if (removePermissionsValue != null) {
        String[] array = removePermissionsValue.split(",");
        removePermissions = new HashSet<String>();
        removePermissions.addAll(Arrays.asList(array));
    }
    // Set ownerpassword
    setOwnerPassword = config.getProperties().getProperty(PDFSigner.SET_OWNERPASSWORD);

    // if signature is chosen to be visible proceed with setting visibility
    // properties
    if (add_visible_signature) {
        // page to draw visible signature at
        if (config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_PAGE) != null) {
            visible_sig_page = config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_PAGE);
        }

        LOG.debug("Using visible signature page: " + visible_sig_page);

        // The location of the visible signature rectangle(llx, lly, urx,
        // ury)
        // llx = lower left x coordinate, lly = lower left y coordinate, urx
        // = upper right x coordinate, ury = upper right y coordinate
        if (config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_RECTANGLE) != null) {
            visible_sig_rectangle = config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_RECTANGLE);
        }
        LOG.debug("Using rectangle: " + visible_sig_rectangle);

        String[] rect = visible_sig_rectangle.split(",");
        if (rect.length < 4) {
            throw new IllegalRequestException(
                    "RECTANGLE property must contain 4 comma separated values with no spaces.");
        }
        visible_sig_rectangle_llx = Integer.valueOf(rect[0]);
        visible_sig_rectangle_lly = Integer.valueOf(rect[1]);
        visible_sig_rectangle_urx = Integer.valueOf(rect[2]);
        visible_sig_rectangle_ury = Integer.valueOf(rect[3]);

        // custom image to use with signature
        // base64 encoded byte[]
        if (config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_BASE64) != null) {
            visible_sig_custom_image_base64 = config.getProperties()
                    .getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_BASE64);
            LOG.debug("base64 encoded custom image is set");
        }

        // custom image path. Do not set if base64 encoded image is
        // specified
        if (visible_sig_custom_image_base64 == null || visible_sig_custom_image_base64.isEmpty()) {
            if (config.getProperties().getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_PATH) != null) {
                visible_sig_custom_image_path = config.getProperties()
                        .getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_PATH);
                LOG.debug("using custom image path : " + visible_sig_custom_image_path);
            }
        }

        boolean use_image_from_base64_string = visible_sig_custom_image_base64 != null
                && !visible_sig_custom_image_base64.isEmpty();
        boolean use_image_from_path = visible_sig_custom_image_path != null
                && !visible_sig_custom_image_path.isEmpty();

        use_custom_image = use_image_from_base64_string || use_image_from_path;

        // custom image resizing (if we are using custom image)
        if (use_custom_image) {

            // retrieve custom image
            byte[] imageByteArray;
            if (use_image_from_base64_string) {
                imageByteArray = Base64.decode(visible_sig_custom_image_base64.getBytes());
            } else {
                try {
                    imageByteArray = readFile(visible_sig_custom_image_path);
                } catch (IOException e) {
                    throw new SignServerException("Error reading custom image data from path specified", e);
                }
            }

            try {
                custom_image = Image.getInstance(imageByteArray);
            } catch (BadElementException e) {
                throw new SignServerException("Problem constructing image from custom image data", e);
            } catch (MalformedURLException e) {
                throw new SignServerException("Problem constructing image from custom image data", e);
            } catch (IOException e) {
                throw new SignServerException("Problem constructing image from custom image data", e);
            }

            if (config.getProperties()
                    .getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_SCALE_TO_RECTANGLE) != null) {
                visible_sig_custom_image_scale_to_rectangle = Boolean.parseBoolean(config.getProperties()
                        .getProperty(PDFSigner.VISIBLE_SIGNATURE_CUSTOM_IMAGE_SCALE_TO_RECTANGLE).trim());
                LOG.debug("resize custom image to rectangle : " + visible_sig_custom_image_scale_to_rectangle);
            }

            // if we are using custom image and the
            // VISIBLE_SIGNATURE_CUSTOM_IMAGE_SCALE_TO_RECTANGLE is set to
            // true resize image to fit to rectangle specified
            // If set to false calculate urx and ury coordinates from image
            if (visible_sig_custom_image_scale_to_rectangle) {
                resizeImageToFitToRectangle();
            } else {
                calculateUpperRightRectangleCoordinatesFromImage();
            }
        }
    }

    // Certification level
    final String level = config.getProperty(PDFSigner.CERTIFICATION_LEVEL);
    if (level != null) {
        if (level.equalsIgnoreCase("NO_CHANGES_ALLOWED")) {
            certification_level = PdfSignatureAppearance.CERTIFIED_NO_CHANGES_ALLOWED;
        } else if (level.equalsIgnoreCase("FORM_FILLING_AND_ANNOTATIONS")) {
            certification_level = PdfSignatureAppearance.CERTIFIED_FORM_FILLING_AND_ANNOTATIONS;
        } else if (level.equalsIgnoreCase("FORM_FILLING")) {
            certification_level = PdfSignatureAppearance.CERTIFIED_FORM_FILLING;
        } else if (level.equalsIgnoreCase("NOT_CERTIFIED")) {
            certification_level = PdfSignatureAppearance.NOT_CERTIFIED;
        } else {
            throw new SignServerException("Unknown value for CERTIFICATION_LEVEL");
        }
    }
    if (LOG.isDebugEnabled()) {
        LOG.debug("using certification level: " + certification_level);
    }
}