title: Implement Digital Signature in Client /Web Server Architecture
body: <p>I am trying to implement digital signature in web application as example provided by by Bruno Lowagie in White Paper.</p>
  
  <p>4.3.3 Signing a document on the server using a signature created on the client</p>
  
  <p>Pre-signing— the client asks the server for a hash.</p>
  
  <p>Post-signing— the client sends the signed bytes to the server.</p>
  
  <p>every thing is working fine in this example but when we are try to open pdf after signing
  it is giving an error <strong>Error during signature verification. Error encountered while validating: Internal cryptographic library error. Error Code: 0x2726</strong></p>
  
  <p><strong>Here is my code:</strong></p>
  
  <p>client:</p>
  
  <pre><code>  KeyStore eks = loadKeyStoreFromSmartCard("abc@123");
  
      // Check if X.509 certification chain is available
      Certificate[] certChain = new X509Certificate[1];
      certChain[0] = getcert_eToken(null, eks);
  
      String strCertificate  = encodeX509CertChainToBase64(certChain);
  
  
      ByteArrayOutputStream byteStream = new ByteArrayOutputStream(8192);
      PrintWriter out = new PrintWriter(byteStream, true);
  
      String postData = "certChain=" + strCertificate;
  
      try {
  
          HttpURLConnection connection = null;
          URL dataURL = null;
  
          dataURL = new URL("http://localhost:8085/Digital-Server/PreSignservlet");
  
          connection = (HttpURLConnection) dataURL.openConnection();
          connection.setRequestProperty("User-Agent",
                  "Mozilla/4.0 (compatible; MSIE 6.0; Windows 2000)");
          connection.setFollowRedirects(true);
          connection.setDoOutput(true);
          connection.setDoInput(true);
          connection.setUseCaches(false);
          connection.setAllowUserInteraction(false);
          connection.setRequestProperty("Content-Type",
                  "application/x-www-form-urlencoded");
          connection.setRequestProperty("Content-Language", "en-US");
          connection.setRequestProperty("Cookie", cookie);
          connection.connect();
  
          out.print(postData);
          out.flush();
          out.close();
  
          byteStream.writeTo(connection.getOutputStream());
          InputStream in = connection.getInputStream();
  
  
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          int read;
          byte[] data = new byte[256];
  
          while ((read = in.read(data)) != -1) {
              baos.write(data, 0, read);
          }
  
          byte[] hash = baos.toByteArray();
  
          PrivateKey privateKey = getprivate_eToken(null, eks);
  
          // we sign the bytes received from the server
          Signature sig = Signature.getInstance("SHA256withRSA");
          sig.initSign(privateKey);
          sig.update(hash);
          data = sig.sign();
  
          // --------------------------------------------
          connection.disconnect();
          in.close();
  
          //Calling Post Sign Servelet 
          dataURL = new URL("http://localhost:8085/Digital-Server/PostSignservlet");
          connection = (HttpURLConnection) dataURL.openConnection();
  
          connection.setRequestProperty("User-Agent",
                  "Mozilla/4.0 (compatible; MSIE 6.0; Windows 2000)");
          connection.setFollowRedirects(true);
          connection.setDoOutput(true);
          connection.setDoInput(true);
          connection.setUseCaches(false);
          connection.setAllowUserInteraction(false);
          connection.setRequestProperty("Content-Type",
                  "application/x-www-form-urlencoded");
          connection.setRequestProperty("Content-Language", "en-US");
          connection.setRequestProperty("Cookie", cookie);
          connection.connect();
          out.flush();
          out.close();
  
          byteStream.writeTo(connection.getOutputStream());
          byteStream.write(data);
  
          in = connection.getInputStream();
  
          OutputStream outputStream = new FileOutputStream(
                  "D:\\Digital Signature\\Digital-Server\\WebContent\\WEB-INF\\result\\jaihanuman.pdf");
  
          // int read = 0;
          byte[] bytes = new byte[8192];
  
          while ((read = in.read(bytes)) != -1) {
              outputStream.write(bytes, 0, read);
          }
  
          System.out.println("Done!");
  </code></pre>
  
  <p><strong>presign servlet:</strong></p>
  
  <pre><code>      Certificate[] chain = decodeX509CertChainToBase64(cert);
  
          // we create a reader and a stamper
  
          ServletContext context = getServletContext();
          String fullPath = context.getRealPath("/WEB-INF/result/hello.pdf");
  
          PdfReader reader = new PdfReader(fullPath);
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          PdfStamper stamper =  PdfStamper.createSignature(reader, baos, '\0');
  
          // we create the signature appearance
  
          PdfSignatureAppearance sap = stamper.getSignatureAppearance();
          sap.setReason("Test");
          sap.setLocation("On a server!");
          sap.setVisibleSignature(new Rectangle(72,737,400,780), 1, "sig");
          sap.setCertificate(chain[0]);
  
          // we create the signature infrastructure
          PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE,PdfName.ADBE_PKCS7_DETACHED);
          dic.setReason(sap.getReason());
          dic.setLocation(sap.getLocation());
          dic.setContact(sap.getContact());
          dic.setDate(new PdfDate(sap.getSignDate()));
          sap.setCryptoDictionary(dic);
  
          HashMap&lt;PdfName, Integer&gt; exc = new HashMap&lt;PdfName, Integer&gt;();
          exc.put(PdfName.CONTENTS, new Integer(8192 * 2 + 2));
          sap.preClose(exc);
  
          ExternalDigest externaldigest =new ExternalDigest() {
  
          public MessageDigest getMessageDigest(String hashAlgorithm)
                  throws GeneralSecurityException {
              return DigestAlgorithms.getMessageDigest(hashAlgorithm, null);
          }
      };
  
      PdfPKCS7 sgn = new PdfPKCS7(null, chain, "SHA256", null, externaldigest, false);
      InputStream data = sap.getRangeStream();
  
      byte hash[] = DigestAlgorithms.digest(data, externaldigest.getMessageDigest("SHA256"));
      Calendar cal = Calendar.getInstance();
      byte[] sh = sgn.getAuthenticatedAttributeBytes(hash, cal, null, null, CryptoStandard.CMS);
  
      // We store the objects we'll need for post signing in a session
      HttpSession session = req.getSession(true);
      session.setAttribute("sgn", sgn);
      session.setAttribute("hash", hash);
      session.setAttribute("cal", cal);
      session.setAttribute("sap", sap);
      session.setAttribute("baos", baos);
  
  
      // we write the hash that needs to be signed to the HttpResponse output
      OutputStream os = resp.getOutputStream();
      os.write(sh, 0, sh.length);
      os.flush();
      os.close();
      }
      catch(Exception ex)
      {
          ex.printStackTrace();
      }
      System.out.println("end of pre sign servelet---------------");
  </code></pre>
  
  <p><strong>post sign servlet:</strong></p>
  
  <pre><code>        try
          {
          // we get the objects we need for postsigning from the session
          System.out.println("call post servelet1");
          HttpSession session = req.getSession(false);
  
          PdfPKCS7 sgn = (PdfPKCS7)session.getAttribute("sgn");
          byte[] hash = (byte[])session.getAttribute("hash");
          Calendar cal = (Calendar)session.getAttribute("cal");
          PdfSignatureAppearance sap =(PdfSignatureAppearance) session.getAttribute("sap");
          ByteArrayOutputStream os =(ByteArrayOutputStream) session.getAttribute("baos");
          session.invalidate();
  
          // we read the signed bytes
  
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          InputStream is = req.getInputStream();
  
          int read;
          byte[] data = new byte[256];
          while ((read = is.read(data, 0, data.length)) != -1) {
          baos.write(data, 0, read);
          }
          // we complete the PDF signing process
  
          sgn.setExternalDigest(baos.toByteArray(), null, "RSA");
          byte[] encodedSig = sgn.getEncodedPKCS7(hash, cal, null, null, null, CryptoStandard.CADES);
          byte[] paddedSig = new byte[8192];
          System.arraycopy(encodedSig, 0, paddedSig, 0, encodedSig.length);
          PdfDictionary dic2 = new PdfDictionary();
          dic2.put(PdfName.CONTENTS, new PdfString(paddedSig).setHexWriting(true));
          sap.close(dic2);
  
          // we write the signed document to the HttpResponse output stream
  
          // let's write the file in memory to a file anyway
          ServletContext context = getServletContext();
          String fullPath = context.getRealPath("/WEB-INF/result/sign.pdf");
  
          byte[] pdf = os.toByteArray();
          OutputStream sos = resp.getOutputStream();
          sos.write(pdf, 0, pdf.length);
          sos.flush();
          sos.close();
  
          /*OutputStream sos = new FileOutputStream(fullPath);
          os.writeTo(sos);
          sos.flush();
          sos.close();*/
  
          }
          catch(Exception ex)
          {
              ex.printStackTrace();
          }
  
          System.out.println("call post servelet2");  
  </code></pre>
  
  <p>Here I am doing one extra thing, I am encoding certificate chain to  <strong>base64</strong> before sending
  to presign servlet. </p>