
Hello! I am an employee of Alfa-Bank and develop software with built-in cryptographic information protection.
In this article I want to talk about the following things:
')
- the benefits of PDF as an electronically signed document;
- Java platform, itextpdf library and CryptoPro CSP IMSP as signature tools;
- about what difficulties I had to face, about the improvement of itextpdf;
- give an example of code that performs several signatures;
- talk about the appropriateness of using PDF as a signed document.
In the modern information world, the importance of an electronic signature and the basic services provided by it (data integrity, and non-repudiation of authorship) cannot be overestimated. State bodies, individuals and legal entities make extensive use of electronic signatures in the exchange of information among themselves.
According to the law, an electronic signature can give documents legal force, equal in importance to a paper carrier, signed by a handwritten signature and sealed by an authorized person.
PDF Benefits
As a container for storing a variety of information in a friendly view of the person, the PDF format has rightfully gained its popularity. It will turn out to open in any OS. A PDF document may contain not only textual and tabular data, but also audio and video recordings, engineering graphics, and three-dimensional models. For additional processing of PDF documents, this format includes such a powerful tool as JavaScript support for changing the content in forms and fields upon the occurrence of an event or performing a user action.
Tools Adobe Systems (developer PDF) support the use of electronic signatures. Unlike messages with an attached enhanced electronic signature of the PKCS # 7 standard and its enhancement CAdES, no additional special software is required to view a signed PDF document. In addition to the cryptographic provider, which is required in all cases.
Those. Adobe tools allow you to visualize an electronic signature in a document.
When signing a PDF document, you can set visualization parameters, specify the page number, block size with a signature, the name of the field where to place it, add a graphic image, for example, a company logo, scan a personal signature of the manager and print the organization.
When viewing such documents, in addition to visualization in the body of the document, Acrobat and Adobe Reader display the “Signatures” tab with related information: an icon indicating the status of the signature verification, information on whether the document was changed, the result of the public key certificate, the last verification time , page and field containing an electronic signature.
Signature tools
The Java version was used: "1.8.0_111" HotSpot (TM) 64-Bit Server VM (build 25.111-b14).
As a certified means of protecting information from a licensed developer, we use the cryptographic provider CryptoPro CSP v4.0 and CryptoPro JCP - v.2.0, with the installation of the CryptoPro Java CSP v.4.0 module
Why CryptoPro JCP - v.2.0, with CryptoPro Java CSP v.4.0?
Because the provider of CryptoPro JCP, after a long non-certified period, received a certificate of conformity from the regulator until 12/31/2018, and then, according to information from the developer, with certification, uncertainty may reappear. The CryptoPro Java CSP v.4.0 module does not perform cryptographic transformations in itself and is essentially an API to the CryptoPro CSP provider, with the next certification of which there are no questions. Here it must be said that a valid certificate on the CIPP is not required, provided that the cryptographic provider is used exclusively for internal purposes.
In accordance with the Java Cryptography Architecture (JCA) specification, in my application, I specify and use the functions of a cryptographic provider: JCSP. After installing CryptoPro, this provider is displayed in the list of all available in the ../java/jdk1.8.x_xxx/jre/lib/security/java.security file, where you can configure which of them is preferable for using by default, unless explicitly indicated in the annex:
#
# List of providers and their preference orders (see above):
#
security.provider.1=ru.CryptoPro.JCSP.JCSP
We do not forget that the export restrictions of the Java platform, which block the operation of cryptographic providers with Russian encryption algorithms, should be lifted.
To do this, in ../java/jdk1.8.x_xxx/jre/lib/security, you must replace the
local_policy.jar and
US_export_policy.jar files
with the ones provided at:
Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 8 Downloadand containing in
default_local.policy and
default_US_export.policy :
grant {
// There is no restriction to any algorithms.
permission javax.crypto.CryptoAllPermission;
};
The use of iText library
itextpdf.com for working with PDF documents in Java was dictated by the CryptoPro provider.
CryptoPro JCP ships a Git patch file for the iTextpdf library version 5.1.3 -
jcp-2.0.xxxxx \ Doc \ itextpdf \ itextpp_5.1.3.gost.user.patch

The patch adapts itextpdf to work with the provider CryptoPro. You need to download the source code of the library version 5.1.3, then use the Git version control Bash command line to apply the patch: git apply --stat itextpdf_5.1.3.gost.user.patch

Next, you need to collect the resulting library from the updated source code and connect to the application.
You can find many examples in CryptoPro JCP in the sample
-sources.jar file. In particular, there are examples of signature and verification of electronic documents in PDF documents. (\ PDF \ SignVerifyPDFExample.java).
Problems and difficulties of assembly
After successfully updating the source code of itextpdf, dependencies on packages ru.CryptoPro.JCP and ru.CryptoPro.reprov.x509 appear in it.
Without them, the project with the source code itextpdf_5.1.3.gost will not build.
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:2.3.2:compile (default-compile) on project itextpdf: Compilation failure: Compilation failure:
[ERROR] \github\iTextpdf_5.1.3_patched_cryptopro_bc1.50\src\main\java\com\itextpdf\text\pdf\PdfPKCS7.java:[138,23] error: package ru.CryptoPro.JCP does not exist
[ERROR] \github\iTextpdf_5.1.3_patched_cryptopro_bc1.50\src\main\java\com\itextpdf\text\pdf\PdfPKCS7.java:[139,31] error: package ru.CryptoPro.reprov.x509 does not exist
You need to take the JCP.jar and JCPRevTools.jar files from the CryptoPro 2.0 distribution and place them in the JRE directory that Maven uses: Java \ jdk1.8.0_111 \ jre \ lib \ ext. Of course, they should be in the classPath of the application.
So, the library is assembled, we connect it to the application. And here comes the main problem. iTextpdf_5.1.3 contains a dependency on Bouncy Castle version 1.46 - an open source library that implements a cryptographic provider and support for ASN.1 structures.
<dependency> <groupId>org.bouncycastle</groupId> <artifactId>bctsp-jdk15</artifactId> <version>1.46</version> <type>jar</type> <scope>compile</scope> <optional>true</optional> </dependency>
The delivery of CryptoPro JCP 2.0 in turn has dependencies on Bouncy Castle version 1.50 bcpkix-jdk15on-1.50 and bcprov-jdk15on-1.5, respectively, they are placed in jre / lib / ext when installing CryptoPro.
As a result, when you start your application and the method of signing the PDF, we get the error:
Exception in thread "main" java.lang.NoClassDefFoundError: org/bouncycastle/asn1/DEREncodable
at com.itextpdf.text.pdf.PdfSigGenericPKCS.setSignInfo(PdfSigGenericPKCS.java:97)
at com.itextpdf.text.pdf.PdfSignatureAppearance.preClose(PdfSignatureAppearance.java:1003)
at com.itextpdf.text.pdf.PdfSignatureAppearance.preClose(PdfSignatureAppearance.java:904)
at com.itextpdf.text.pdf.PdfStamper.close(PdfStamper.java:194)
at ru.alfabank.ccjava.trustcore.logic.SignatureProcessor.pdfSignature(SignatureProcessor.java:965)
at ru.alfabank.ccjava.trustcore.logic.SignatureProcessor.main(SignatureProcessor.java:1363)
Caused by: java.lang.ClassNotFoundException: org.bouncycastle.asn1.DEREncodable
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 6 more
Every Java developer has come across such an exception in the main stream and knows that you can spend a lot of time analyzing the problem and how to fix it. The essence of the NoClassDefFoundError exception is as follows: it is thrown when the Java virtual machine cannot find the specific class that was available at the compilation stage during the execution of the application.
What turns out - the iTextpdf_5.1.3 library has a dependency on the older provider Bouncy Castle, and for the new versions of iTextpdf there is no patch from CryptoPro.
Specifically, in the delivery of CryptoPro JCP 2.0 dependencies on the new version of Bouncy Castle has the library CAdES.jar. If you remove this library from the JRE, or refuse to support the formation of CAdES signatures when installing CryptoPro JCP 2.0, the problem will be solved.
But what if CAdES support should remain?
To get rid of the library conflict, the following steps should be taken:
As a result, the project iTextpdf_5.1.3_patched_cryptopro_bc1.50 starts to build. Conflict resolved, CryptoPro and itextpdf link to the same version of org.bouncycastle 1.50.
The source code iTextpdf_5.1.3_patched_cryptopro_bc1.50 is uploaded to GitHub:
iTextpdf_5.1.3_patched_cryptopro_bc1.50Sample code, several PDF signatures
An example of using CryptoPro and iTextpdf_5.1.3_patched_cryptopro_bc1.50 is as follows:
public static byte[] samplePDFSignature(String[] aliases, byte[] data, char pdfVersion) throws SignatureProcessorException { ByteArrayOutputStream bais = new ByteArrayOutputStream(); HashMap<X509Certificate, PrivateKey> currSignAttrMap = new HashMap<X509Certificate, PrivateKey>(); for (String alias : aliases) { X509Certificate certificate = (X509Certificate) signAttributesMap1.get(alias)[0]; PrivateKey privateKey = (PrivateKey) signAttributesMap1.get(alias)[1]; currSignAttrMap.put(certificate, privateKey); if (certificate == null) { throw new SignatureProcessorException(PDF_SIGNATURE_ERROR + CERTIFICATE_NOT_FOUND_BY_ALIAS); } if (privateKey == null) { throw new SignatureProcessorException(PDF_SIGNATURE_ERROR + PRIVATE_KEY_NOT_FOUND_BY_ALIAS); } } try { FileInputStream fis = new FileInputStream(new File(FILE_PATH)); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buf = new byte[1024]; int n = 0; while ((n = fis.read(buf, 0, buf.length)) != -1) { baos.write(buf, 0, n); } fis.close(); byte[] im = baos.toByteArray(); X509Certificate innerCA = obtainCertFromTrustStoreJKS(false, INNER_CA); PdfStamper stp = null; PdfReader reader = null; int pageNumber = 1; for (Entry<X509Certificate, PrivateKey> entry : currSignAttrMap.entrySet()) { if (bais.toByteArray().length == 0) { reader = new PdfReader(data); } else { reader = new PdfReader(bais.toByteArray()); bais = new ByteArrayOutputStream(); } stp = PdfStamper.createSignature(reader, bais, pdfVersion);
The method takes as input a list of container names with keys of an electronic signature, bytes of a PDF document and the version number of the PDF format. According to the specified names, keys and certificates are retrieved from the cache. The image is loaded for visualization of the signature.
An object with a root certificate is created to form the certification path that is required by the setCrypto method of the com.itextpdf.text.pdf.PdfSignatureAppearance class.
The loop signs the pages of the PDF document with the keys whose names were transferred to the method.
For the demonstration, two signatures were made - valid and non-valid with an invalid certificate.


Tab "Signatures" is as follows:


Application of electronic signature of PDF documents
In my opinion, the signature directly in PDF format is a special case. Such a stamp in the file itself is intended more likely to visualize an EA for the purpose of checking it with eyes. This is convenient and effective when it comes to a small number of documents where automation is not required, and the operator performs the role of a reviewer.
With the intensive process of exchanging a large number of electronic documents, the operator will not cope. In this case, the information system performs automation, and there is no need for a beautiful visualization. Accordingly, it is unnecessary to waste the resources of the information system and electronic channels for the transfer of large PDF files and the processing of stamp images.
It is more practical to form the electronic signature as a separate file or to wrap the file and the signature in one PKCS # 7 standard container (CAdES). This standard with attached or disconnected signature is perfect for a large document flow between information systems.
The same PDF document can be signed by the CAdES standard with a detached signature, as a result there will be two files - the PDF itself and the container with the signature.
Recall the problems encountered when signing on to Java. Conclusion - the PDF format is currently poorly supported by CryptoPro in the part of the application programming interface for Java. The existing itextpdf library had to be edited independently.
In the field of activities related to the development of commercial software with embedded DTPM, such an approach is unacceptable, patches, updates and improvements should be performed by the organization-licensee. Therefore, the method of signing a PDF document given in the post can be used to demonstrate the possibilities and for internal use.
useful links
- Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 8
- Website CryptoPro
- ITextpdf Developer
- Bouncy Castle "Porting from earlier releases to 1.47 and later"
- Source code for iTextpdf_5.1.3_patched_cryptopro_bc1.50 in GitHub