I'am trying to verify signatures in pdf file. There are three of them. I have signed that file with the code i've found in internet and adopted to my needs, so it might be encorrect too. Here is that signed file pdf file
Verifier code here:
package com.mycompany.verifysignature;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.bouncycastle.crypto.digests.GOST3411Digest;
import ru.CryptoPro.CAdES.CAdESSignature;
import ru.CryptoPro.CAdES.CAdESType;
public class Main {
public static void main(String args[]) {
try {
ArrayList<Map<String, String>> resList = new ArrayList<Map<String, String>>();
InputStream pdfIs = new FileInputStream("/home/user1/Desktop/321-17.pdf");
com.itextpdf.text.pdf.PdfReader reader = new com.itextpdf.text.pdf.PdfReader(pdfIs);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
com.itextpdf.text.pdf.PdfStamper stamper = com.itextpdf.text.pdf.PdfStamper.createSignature(reader, baos, '\0');
com.itextpdf.text.pdf.PdfSignatureAppearance sap = stamper.getSignatureAppearance();
com.itextpdf.text.pdf.AcroFields fields = reader.getAcroFields();
for (String signame : fields.getSignatureNames()) {
HashMap<String, String> m = new HashMap();
m.put("name", signame.toString());
System.out.println("name:"+signame);
com.itextpdf.text.pdf.PdfDictionary sig = fields.getSignatureDictionary(signame);
if (sig != null && sig.getAsString(com.itextpdf.text.pdf.PdfName.REASON) != null) {
m.put("reason", sig.getAsString(com.itextpdf.text.pdf.PdfName.REASON).toString()
.replaceAll("\"", "\\\""));
System.out.println("reason:"+sig.getAsString(com.itextpdf.text.pdf.PdfName.REASON).toString()
.replaceAll("\"", "\\\""));
} else {
m.put("reason", "undefined");
System.out.println("reason:undefined");
}
byte signature[] = null;
if (sig != null && sig.getBytes() != null) {
signature = sig.getBytes();
}
byte hash[] = calcHash(sap.getRangeStream());
if (hash != null) {
CAdESSignature cadesSignature = new CAdESSignature(signature, hash, CAdESType.CAdES_X_Long_Type_1);
try {
cadesSignature.verify(null);
m.put("valid", "true");
System.out.println("valid:true");
} catch(Exception ex) {
m.put("valid", "false");
System.out.println("valid:false");
}
} else {
m.put("valid", "\"undefined\"");
System.out.println("valid:undefined");
}
// com.itextpdf.text.pdf.security.PdfPKCS7 pk = fields.verifySignature(signame);
//
// m.put("valid", new Boolean(pk.verify()).toString());
// System.out.println("valid:"+new Boolean(pk.verify()).toString());
resList.add(m);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
public static byte[] calcHash(InputStream is) {
if (is == null) return null;
try {
GOST3411Digest digest = new GOST3411Digest();
byte node[] = readBytesFromStream(is);
digest.update(node, 0, node.length);
byte[] resBuf = new byte[digest.getDigestSize()];
digest.doFinal(resBuf, 0);
return resBuf;
} catch (Throwable e) {
e.printStackTrace();
//throw new Exception(e);
}
return null;
}
private static byte[] readBytesFromStream(InputStream is) throws Exception {
ArrayList<Object[]> c = new ArrayList();
int n, size = 0;
byte b[] = null;
if (is == null) throw new Exception("input stream is null");
try {
while ((n = is.read(b = new byte[1024])) > 0) {
c.add(new Object[] { n, b });
size += n;
}
} catch (IOException e) {
e.printStackTrace();
}
byte rv[] = new byte[size];
int pos = 0;
for (Object[] bb : c) {
for (int i = 0; i < (Integer) bb[0]; i++) {
rv[pos++] = ((byte[]) bb[1])[i];
}
}
return rv;
}
}
I have signed file's digest, made with GOST3411, with test certificate, that is generated on cryptopro site.
When I open this file with pdf reader, it says there are 3 signatures. I have realy signed it three times. But the code above takes out from the pdf signature names that are not equal to the names I wrote. They are look like Signature1, Signature2 etc. There should be written "CN" in all three cases. Please help. What I have made wrong?
The file provided by the OP, 321-174.pdf, is signed using exactly one signature, not three, and the prime error is that the Contents of the signature dictionary content are not the CMS signature but instead something textually, probably base64 encoded. Thus, some decoding in-between in your code seems necessary.
That been said I cannot find GOST3410 in the Table 257 – SubFilter value algorithm support - of the specification ISO 32000-1- Thus its use in this context most likely wont be accepted.