All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.somospnt.signature.SigUtils Maven / Gradle / Ivy

Go to download

This is a libray to digital signing a PDF and a PFX valid certificate. Based in PDFBox official SVN example.

The newest version!
/*
 * Copyright 2017 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.somospnt.signature;

import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.PDSignature;
import org.bouncycastle.asn1.x509.KeyPurposeId;

/**
 * Utility class for the signature / timestamp examples.
 *
 * @author Tilman Hausherr
 */
final class SigUtils {

    private static final Log LOG = LogFactory.getLog(SigUtils.class);

    private SigUtils() {
    }

    /**
     * Get the access permissions granted for this document in the DocMDP
     * transform parameters dictionary. Details are described in the table
     * "Entries in the DocMDP transform parameters dictionary" in the PDF
     * specification.
     *
     * @param doc document.
     * @return the permission value. 0 means no DocMDP transform parameters
     * dictionary exists. Other return values are 1, 2 or 3. 2 is also returned
     * if the DocMDP transform parameters dictionary is found but did not
     * contain a /P entry, or if the value is outside the valid range.
     */
    protected static int getMDPPermission(PDDocument doc) {
        COSBase base = doc.getDocumentCatalog().getCOSObject().getDictionaryObject(COSName.PERMS);
        if (base instanceof COSDictionary) {
            COSDictionary permsDict = (COSDictionary) base;
            base = permsDict.getDictionaryObject(COSName.DOCMDP);
            if (base instanceof COSDictionary) {
                COSDictionary signatureDict = (COSDictionary) base;
                base = signatureDict.getDictionaryObject("Reference");
                if (base instanceof COSArray) {
                    COSArray refArray = (COSArray) base;
                    for (int i = 0; i < refArray.size(); ++i) {
                        base = refArray.getObject(i);
                        if (base instanceof COSDictionary) {
                            COSDictionary sigRefDict = (COSDictionary) base;
                            if (COSName.DOCMDP.equals(sigRefDict.getDictionaryObject("TransformMethod"))) {
                                base = sigRefDict.getDictionaryObject("TransformParams");
                                if (base instanceof COSDictionary) {
                                    COSDictionary transformDict = (COSDictionary) base;
                                    int accessPermissions = transformDict.getInt(COSName.P, 2);
                                    if (accessPermissions < 1 || accessPermissions > 3) {
                                        accessPermissions = 2;
                                    }
                                    return accessPermissions;
                                }
                            }
                        }
                    }
                }
            }
        }
        return 0;
    }

    /**
     * Set the access permissions granted for this document in the DocMDP
     * transform parameters dictionary. Details are described in the table
     * "Entries in the DocMDP transform parameters dictionary" in the PDF
     * specification.
     *
     * @param doc The document.
     * @param signature The signature object.
     * @param accessPermissions The permission value (1, 2 or 3).
     */
    protected static void setMDPPermission(PDDocument doc, PDSignature signature, int accessPermissions) {
        COSDictionary sigDict = signature.getCOSObject();

        COSDictionary transformParameters = new COSDictionary();
        transformParameters.setItem(COSName.TYPE, COSName.getPDFName("TransformParams"));
        transformParameters.setInt(COSName.P, accessPermissions);
        transformParameters.setName(COSName.V, "1.2");
        transformParameters.setNeedToBeUpdated(true);

        COSDictionary referenceDict = new COSDictionary();
        referenceDict.setItem(COSName.TYPE, COSName.getPDFName("SigRef"));
        referenceDict.setItem("TransformMethod", COSName.DOCMDP);
        referenceDict.setItem("DigestMethod", COSName.getPDFName("SHA256"));
        referenceDict.setItem("TransformParams", transformParameters);
        referenceDict.setNeedToBeUpdated(true);

        COSArray referenceArray = new COSArray();
        referenceArray.add(referenceDict);
        sigDict.setItem("Reference", referenceArray);
        referenceArray.setNeedToBeUpdated(true);

        COSDictionary catalogDict = doc.getDocumentCatalog().getCOSObject();
        COSDictionary permsDict = new COSDictionary();
        catalogDict.setItem(COSName.PERMS, permsDict);
        permsDict.setItem(COSName.DOCMDP, signature);
        catalogDict.setNeedToBeUpdated(true);
        permsDict.setNeedToBeUpdated(true);
    }

    /**
     * Log if the certificate is not valid for signature usage. Doing this
     * anyway results in Adobe Reader failing to validate the PDF.
     *
     * @param x509Certificate
     * @throws java.security.cert.CertificateParsingException
     */
    protected static void checkCertificateUsage(X509Certificate x509Certificate) throws CertificateParsingException {
        boolean[] keyUsage = x509Certificate.getKeyUsage();
        if (keyUsage != null && !keyUsage[0] && !keyUsage[1]) {
            LOG.error("Certificate key usage does not include "
                    + "digitalSignature nor nonRepudiation");
        }
        List extendedKeyUsage = x509Certificate.getExtendedKeyUsage();
        if (extendedKeyUsage != null
                && !extendedKeyUsage.contains(KeyPurposeId.id_kp_emailProtection.toString())
                && !extendedKeyUsage.contains(KeyPurposeId.id_kp_codeSigning.toString())
                && !extendedKeyUsage.contains(KeyPurposeId.anyExtendedKeyUsage.toString())
                && !extendedKeyUsage.contains("1.2.840.113583.1.1.5")
                && !extendedKeyUsage.contains("1.3.6.1.4.1.311.10.3.12")) {
            LOG.error("Certificate extended key usage does not include "
                    + "emailProtection, nor codeSigning, nor anyExtendedKeyUsage, "
                    + "nor 'Adobe Authentic Documents Trust'");
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy