0

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 following code will work in a client server based senerio.

My code is:

import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfSignatureAppearance;
import com.lowagie.text.pdf.PdfStamper;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CRL;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import javax.servlet.RequestDispatcher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.mscapi.SunMSCAPI;

public class Testing {
    private static boolean resFlag;

    public static void main (String args[])
    {
     try {

        BouncyCastleProvider providerBC = new BouncyCastleProvider();
        Security.addProvider(providerBC);
        SunMSCAPI providerMSCAPI = new SunMSCAPI();
        Security.addProvider(providerMSCAPI);
        KeyStore ks = KeyStore.getInstance("Windows-MY");
        ks.load(null, null);
        String alias = (String)ks.aliases().nextElement();
        PrivateKey pk = (PrivateKey)ks.getKey(alias, null);
        Certificate[] chain = ks.getCertificateChain(alias);


//         //String e = request.getParameter("digiFile");
//         KeyStore ks = KeyStore.getInstance("pkcs12");
//         String f10 = CommonUtil.getRealPath();
//         String str8 = f10 + "/DigiFiles/";
//         //System.out.println("str8-->>>>>>>>" + str8 + e);
//          ks.load(new FileInputStream("F:/DigiFiles/Anurag Goel.pfx"), "123".toCharArray());
//
//
//         System.out.println("The actual path is " + str8);
//         String alias = (String)ks.aliases().nextElement();
//         PrivateKey key = (PrivateKey)ks.getKey(alias, "123".toCharArray());
//         Certificate[] chain = ks.getCertificateChain(alias);
         PdfReader reader = new PdfReader("F:/test.pdf");
         FileOutputStream os = new FileOutputStream("F:/SampleOutPut61.pdf");
         PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0',null,true);
         PdfSignatureAppearance appearance = stamper.getSignatureAppearance();
         appearance.setCrypto(pk, chain, (CRL[])null, PdfSignatureAppearance.VERISIGN_SIGNED);
         appearance.setReason("elicense project");
         appearance.setLocation("Assam");
         appearance.setVisibleSignature("hi");
         stamper.close();
      } catch (KeyStoreException var27) {
         var27.printStackTrace();
         resFlag = false;
      } catch (NoSuchAlgorithmException var28) {
         var28.printStackTrace();
         resFlag = false;
      } catch (CertificateException var29) {
         var29.printStackTrace();
         resFlag = false;
      } catch (FileNotFoundException var30) {
         var30.printStackTrace();
         resFlag = false;
      } catch (IOException var31) {
         var31.printStackTrace();
         resFlag = false;
      } catch (UnrecoverableKeyException var32) {
         var32.printStackTrace();
         resFlag = false;
      } catch (DocumentException var33) {
         var33.printStackTrace();
         resFlag = false;
      } catch (Exception var34) {
         var34.printStackTrace();
         resFlag = false;
      } finally {
         RequestDispatcher rd;


      }

   }
}

Please give me suggestion . thanks all

ASADUL
  • 308
  • 5
  • 17

1 Answers1

2
  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.

Bruno Lowagie
  • 75,994
  • 9
  • 109
  • 165
  • Please give me a solution how i could use it a client server scenario. My server is linux server. – ASADUL Feb 07 '15 at 12:32
  • There are different solutions. You can find them in this free ebook: http://pages.itextpdf.com/ebook-digital-signatures-for-pdf.html It would lead us to far to copy/paste entire pages from that book into an answer (and being the author of that book, I would see that as an infringement on my copyright because it would go beyond fair use). – Bruno Lowagie Feb 07 '15 at 12:34
  • @Brono Actually i am following your pdf. Plz explain or attached same example to linux server and window client environment. I am in great trouble. – ASADUL Feb 07 '15 at 12:45
  • If you use `com.lowagie` packages, you are *not* following the examples in my book. If you want an example that works on Linux, take a look at the example in section 4.1.1. The full source code can be found [here](http://sourceforge.net/p/itext/code/HEAD/tree/tutorial/signatures/src/main/java/signatures/chapter4/C4_01_SignWithPKCS11HSM.java). If you are in great trouble, you should hire an expert. Do you have a license to use iText on a server? – Bruno Lowagie Feb 07 '15 at 12:50
  • i am using my server to generate the PDFbut my USB will be on my client machine. – ASADUL Feb 10 '15 at 07:33
  • If your USB is on your client machine, then your private key will be on your client machine. You can not extract your private key from your USB key (if you could, you would have a severe security problem: your USB would be worthless). You can not create a signature without a private key. Hence you have to do the signing on the client machine. Read the free ebook and you'll understand. – Bruno Lowagie Feb 10 '15 at 08:11
  • @Brono I have studied the Books.My client machine are windows and any how i can not sign my pdf in server if i used my USB in client. So i think i need to download the certificate first and then need to sign it. – ASADUL Feb 10 '15 at 09:44
  • Your question is very strange. What do you mean when you say "I need to download the certificate first"? Are you talking about the keystore with the public and private key? That keystore is on your USB token and **there is no way you can extract the private key from your USB token!** – Bruno Lowagie Feb 10 '15 at 10:07
  • @Brono that is my mistake actually i want to explain that first i have to download the pdf and there after i can do the signing process by using my USB. Is it ok – ASADUL Feb 10 '15 at 10:11
  • Yes, you should do the signing on the client side. – Bruno Lowagie Feb 10 '15 at 10:12
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/70633/discussion-between-asadul-and-bruno-lowagie). – ASADUL Feb 10 '15 at 12:25