У меня есть JAR, у которого есть класс, который должен подписывать PDF-файл, а также создавать отдельную подпись PKCS7. Проблема, однако, заключается в том, что я использую 2 разных провайдера шифрования: JCP (российский провайдер для создания присоединенной подписи PDF) и BC для создания отсоединенной подписи соответственно.
Код выглядит следующим образом:
public void signPdf(InputStream is, String folder, String fileNameWoExtension) throws Exception
{
// private key and certificate
PrivateKey key = keyStore.getPrivateKey();
Certificate[] chain = new Certificate[1];
chain[0] = keyStore.getCertificate();
X509Certificate cert = (X509Certificate)chain[0];
Date notBefore = cert.getNotBefore();
Date notAfter = cert.getNotAfter();
String serial = cert.getSerialNumber().toString(16).toUpperCase();
String subject = PdfPKCS7.getSubjectFields(cert).getField("CN");
String number = fileNameWoExtension.replace("appeal_", "");
// reader and stamper
PdfReader reader = new PdfReader(is);
FileOutputStream fout = new FileOutputStream(folder + File.separator + fileNameWoExtension + ".pdf");
PdfStamper stp = PdfStamper.createSignature(reader, fout, '\0');
StampsCreator.createEdsStamp(folder, serial, subject, notBefore, notAfter);
StampsCreator.createRegisterStamp(folder, new Date(), number);
PdfContentByte pcb = stp.getOverContent(1);
Image imageEds = Image.getInstance(folder + File.separator + StampsCreator.EDS_STAMP);
imageEds.scaleAbsolute(200, 87);
imageEds.setAbsolutePosition(75, 80);
imageEds.setAnnotation(new Annotation(0, 0, 0, 0, 3));
pcb.addImage(imageEds);
Image imageReg = Image.getInstance(folder + File.separator + StampsCreator.REGNUMBER_STAMP);
imageReg.scaleAbsolute(207, 20);
int height = (int) Math.floor(reader.getPageSize(1).getHeight());
imageReg.setAbsolutePosition(70, height - 130);
imageReg.setAnnotation(new Annotation(0, 0, 0, 0, 3));
pcb.addImage(imageReg);
PdfSignatureAppearance sap = stp.getSignatureAppearance();
sap.setSignDate(new GregorianCalendar());
sap.setCrypto(null, chain, null, null);
sap.setAcro6Layers(true);
sap.setRenderingMode(PdfSignatureAppearance.RenderingMode.DESCRIPTION);
PdfSignature dic;
dic = new PdfSignature(PdfName.ADOBE_CryptoProPDF, PdfName.ADBE_PKCS7_DETACHED);
dic.setDate(new PdfDate(sap.getSignDate()));
dic.setName(subject);
dic.setReason("Signed with CryptoPro");
sap.setCryptoDictionary(dic);
int csize = 4000;
HashMap<PdfName,Integer> exc = new HashMap<PdfName,Integer>();
exc.put(PdfName.CONTENTS, new Integer(csize * 2 + 2));
sap.preClose(exc);
System.out.println("preclosed " + key.getClass().getName() + " " + key.getAlgorithm());
System.out.println("1");
X509Certificate signerCert = (X509Certificate)chain[0];
System.out.println("2");
List certList = new ArrayList();
System.out.println("3");
certList.add(signerCert);
System.out.println("4");
Store certs = new JcaCertStore(certList);
System.out.println("5");
// signature
CMSSignedDataGenerator generator = new CMSSignedDataGenerator();
System.out.println("6");
ContentSigner signer = new JcaContentSignerBuilder(AlgorithmUtils.getDigestMessageAndAlgorithmsForJcaContentSignerBuilder(signerCert)).setProvider("BC").build(key);
System.out.println("7");
generator.addSignerInfoGenerator(
new JcaSignerInfoGeneratorBuilder(
new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
.build(signer, signerCert));
System.out.println("8");
generator.addCertificates(certs);
System.out.println("9");
//generator.addCertificates(new JcaCertStore(Arrays.asList(chain)));
//generator.addSigner(key, (X509Certificate)chain[0], JCP.GOST_EL_DH_OID, JCP.GOST_DIGEST_OID);
/*ArrayList<Certificate> list = new ArrayList<Certificate>();
for (int i = 0; i < chain.length; i++) {
list.add(chain[i]);
}*/
/*CertStore chainStore
= CertStore.getInstance("Collection", new CollectionCertStoreParameters(list), "BC");
generator.addCertificatesAndCRLs(chainStore);*/
CMSSignedData signedData;
System.out.println("9");
signedData = generator.generate(new CMSProcessableByteArray(IOUtils.toByteArray(sap.getRangeStream())), false);
System.out.println("10");
//CMSProcessable content = new CMSProcessableRange(sap);
//signedData = generator.generate(content, false, JCP.PROVIDER_NAME);
byte[] pk = signedData.getEncoded();
System.out.println("p7s data ready.");
byte[] outc = new byte[csize];
PdfDictionary dic2 = new PdfDictionary();
System.arraycopy(pk, 0, outc, 0, pk.length);
dic2.put(PdfName.CONTENTS, new PdfString(outc).setHexWriting(true));
System.out.println("signed ready.");
sap.close(dic2);
FileOutputStream fos = new FileOutputStream(folder + File.separator + fileNameWoExtension + ".p7s");
fos.write(pk);
fos.close();
}
Вот метод определения алгоритма внутри сертификата, используемого для создания подписи:
public static String getDigestMessageAndAlgorithmsForJcaContentSignerBuilder(X509Certificate cert)
{
switch (cert.getPublicKey().getAlgorithm())
{
case "GOST3410_2012_256":
return JCA_CONTENT_GOST_2012_256; //GOST3411-2012-256WITHECGOST3410-2012-256
case "GOST3410_2012_512":
return JCA_CONTENT_GOST_2012_512; //GOST3411-2012-512WITHECGOST3410-2012-512
case "GOST3410EL":
return JCA_CONTENT_GOST3410EL; //GOST3411withECGOST3410
default:
throw new IllegalArgumentException("Algorithm inside the certificate " + cert.getPublicKey().getAlgorithm() + " is not supported.");
}
}
Код, кажется, останавливаетсяв следующей строке:
ContentSigner signer = new JcaContentSignerBuilder(AlgorithmUtils.getDigestMessageAndAlgorithmsForJcaContentSignerBuilder(signerCert)).setProvider("BC").build(key);
Я понял это, потому что, когда я пытаюсь выполнить это, я получаю следующий вывод:
preclosed ru.CryptoPro.JCP.Key.GostExchPrivateKey GOST3410DH_2012_256
1
2
3
4
5
6
Почему это так? Это связано с использованием разных поставщиков криптографии? Я имею в виду, потому что PrivateKey
имеет тип ru.CryptoPro.JCP.Key.GostExchPrivateKey
, в то время как BC требует другого типа?
Заранее спасибо.