Sigining a PDF using USB driver in server client condition

前端 未结 1 1166
别跟我提以往
别跟我提以往 2021-01-26 04:45

I am doing a project where i need to sign a pdf using a usb based digital signature. I have tried the following code locally and able to sign the pdf. my problem is weather the

相关标签:
1条回答
  • 2021-01-26 05:38
    1. You are using the wrong iText version, hence you are creating signatures that are not future proof (please read this book to find out what's wrong with your code).
    2. You are depending on the fact that the operating system is Windows. Is your server also a Windows server? Your code won't work if it's a Linux server. Check with your hosting provider and also ask your hosting provider if it is allowed for you to have a USB token on that server (if it's not a dedicated server, chances are they are going to refuse that).
    3. You are using Windows-MY which means that you delegate the authentication to the operating system. If the USB needs a passphrase (they usually do), Windows will open up a dialog box for you to fill out that passphrase. If you deploy this on a server: will you have somebody sitting next to that server to fill out that password every time somebody requests a signature?
    4. USB tokens are designed for people to sign a document manually. They usually have specific limitations. For instance: normally, you can not apply more than 1 signature per second. This is usually insufficient in a web context. In a web context, you are expected to use install a Hardware Security Module (HSM) on your server.

    While your code may work on a server in theory, I see a lot of reasons why it's not a wise decision to use the code that works on a standalone machine in a client/server environment. There are too many practical issues (such as authentication, speed, wrong version of iText,...) that can make your project go wrong. I would answer "no" to your question whether that code will work in a client/server scenario.

    Update:

    In your comments to my answer, you indicate that your server is a Linux server. It should be obvious that using "Windows-MY" will never work on a Linux server. You'll have to use PKCS#11 instead of Windows-MY to talk to the hardware device on which your token is stored. This is a code sample that works on a Luna SA from SafeNet. As you can see, it uses PKCS#11:

    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.security.GeneralSecurityException;
    import java.security.KeyStore;
    import java.security.PrivateKey;
    import java.security.Provider;
    import java.security.Security;
    import java.security.cert.Certificate;
    import java.security.cert.X509Certificate;
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    import java.util.Properties;
    
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    
    import sun.security.pkcs11.SunPKCS11;
    
    import com.itextpdf.text.DocumentException;
    import com.itextpdf.text.Rectangle;
    import com.itextpdf.text.log.LoggerFactory;
    import com.itextpdf.text.log.SysoLogger;
    import com.itextpdf.text.pdf.PdfReader;
    import com.itextpdf.text.pdf.PdfSignatureAppearance;
    import com.itextpdf.text.pdf.PdfStamper;
    import com.itextpdf.text.pdf.security.BouncyCastleDigest;
    import com.itextpdf.text.pdf.security.CertificateUtil;
    import com.itextpdf.text.pdf.security.CrlClient;
    import com.itextpdf.text.pdf.security.CrlClientOnline;
    import com.itextpdf.text.pdf.security.DigestAlgorithms;
    import com.itextpdf.text.pdf.security.ExternalDigest;
    import com.itextpdf.text.pdf.security.ExternalSignature;
    import com.itextpdf.text.pdf.security.MakeSignature;
    import com.itextpdf.text.pdf.security.OcspClient;
    import com.itextpdf.text.pdf.security.OcspClientBouncyCastle;
    import com.itextpdf.text.pdf.security.PrivateKeySignature;
    import com.itextpdf.text.pdf.security.TSAClient;
    import com.itextpdf.text.pdf.security.TSAClientBouncyCastle;
    import com.itextpdf.text.pdf.security.MakeSignature.CryptoStandard;
    
    public class C4_01_SignWithPKCS11HSM {
    
        public static final String SRC = "/home/itext/hello.pdf";
        public static final String PROPS = "/home/itext/key.properties";
        public static final String DEST = "/home/itext/hello_hsm.pdf";
    
        public void sign(String src, String dest,
                Certificate[] chain, PrivateKey pk,
                String digestAlgorithm, String provider, CryptoStandard subfilter,
                String reason, String location,
                Collection<CrlClient> crlList,
                OcspClient ocspClient,
                TSAClient tsaClient,
                int estimatedSize)
                        throws GeneralSecurityException, IOException, DocumentException {
            // Creating the reader and the stamper
            PdfReader reader = new PdfReader(src);
            FileOutputStream os = new FileOutputStream(dest);
            PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0');
            // Creating the appearance
            PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
            appearance.setReason(reason);
            appearance.setLocation(location);
            appearance.setVisibleSignature(new Rectangle(36, 748, 144, 780), 1, "sig");
            // Creating the signature
            ExternalSignature pks = new PrivateKeySignature(pk, digestAlgorithm, provider);
            ExternalDigest digest = new BouncyCastleDigest();
            MakeSignature.signDetached(appearance, digest, pks, chain, crlList, ocspClient, tsaClient, estimatedSize, subfilter);
        }
    
        public static void main(String[] args) throws IOException, GeneralSecurityException, DocumentException {
    
            LoggerFactory.getInstance().setLogger(new SysoLogger());
    
            Properties properties = new Properties();
            properties.load(new FileInputStream(PROPS));
            char[] pass = properties.getProperty("PASSWORD").toCharArray();
            String pkcs11cfg = properties.getProperty("PKCS11CFG");
    
            BouncyCastleProvider providerBC = new BouncyCastleProvider();
            Security.addProvider(providerBC);
            FileInputStream fis = new FileInputStream(pkcs11cfg);
            Provider providerPKCS11 = new SunPKCS11(fis);
            Security.addProvider(providerPKCS11);
    
            KeyStore ks = KeyStore.getInstance("PKCS11");
            ks.load(null, pass);
            String alias = (String)ks.aliases().nextElement();
            PrivateKey pk = (PrivateKey)ks.getKey(alias, pass);
            Certificate[] chain = ks.getCertificateChain(alias);
            OcspClient ocspClient = new OcspClientBouncyCastle();
            TSAClient tsaClient = null;
            for (int i = 0; i < chain.length; i++) {
                X509Certificate cert = (X509Certificate)chain[i];
                String tsaUrl = CertificateUtil.getTSAURL(cert);
                if (tsaUrl != null) {
                    tsaClient = new TSAClientBouncyCastle(tsaUrl);
                    break;
                }
            }
            List<CrlClient> crlList = new ArrayList<CrlClient>();
            crlList.add(new CrlClientOnline(chain));
            C4_01_SignWithPKCS11HSM app = new C4_01_SignWithPKCS11HSM();
            app.sign(SRC, DEST, chain, pk, DigestAlgorithms.SHA256, providerPKCS11.getName(), CryptoStandard.CMS,
                    "HSM test", "Ghent", crlList, ocspClient, tsaClient, 0);
        }
    }
    

    The content of the config file that is used looks like this:

    Name = Luna
    library = /usr/lunasa/lib/libCryptoki2_64.so
    slot = 1
    

    Note that the so may be in another directory in your case, and your certificate may be in another slot. I also use a properties file to store the password for the certificate. Obviously I won't share my password ;-)

    This example was tested on a server owned by GlobalSign using a GlobalSign certificate.

    0 讨论(0)
提交回复
热议问题