Статус: Новичок
Группы: Участники
Зарегистрирован: 11.05.2017(UTC) Сообщений: 2
Сказал(а) «Спасибо»: 1 раз
|
Добрый день! Для подписания файла PDF использую вариант без правки iText из темы "как программно из java подписать PDF-файл ГОСТ-овым ключом?". Код немного изменил:
Код:
File temp = new File("./signed.pdf");
FileOutputStream fOut = new FileOutputStream(temp);
PdfStamper stp = PdfStamper.createSignature(reader, fOut, '\0');
// Подготовка ПДФ документа
PdfSignatureAppearance sap = stp.getSignatureAppearance();
sap.setVisibleSignature(new Rectangle(signX, signY, signX + signWidth, signY - signHeight), page, null);
sap.setSignDate(new GregorianCalendar());
DateFormat dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm");
text1 = text1.replaceAll("%datetime%", dateFormat.format(sap.getSignDate().getTime()));
sap.setLayer2Text(text1 + "\n" + text2);
String winDir = System.getenv("windir");
String arialTff = winDir + "\\fonts\\ARIAL.TTF";
BaseFont bf = BaseFont.createFont(arialTff, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
Font font = new Font(bf, 7, Font.NORMAL);
sap.setLayer2Font(font);
sap.setRenderingMode(PdfSignatureAppearance.RenderingMode.DESCRIPTION);
sap.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);
PdfSignature dic;
PdfName filterName = new PdfName("CryptoPro PDF");
dic = new PdfSignature(filterName, PdfName.ADBE_PKCS7_DETACHED);
dic.setDate(new PdfDate(sap.getSignDate()));
dic.setName(((X509CertImpl)xcert).getSubjectDN().getName());
dic.setReason(text2);
dic.setCert(xcert.getEncoded());
sap.setCryptoDictionary(dic);
int csize = 4000;
HashMap<PdfName, Integer> exc = new HashMap<>();
exc.put(PdfName.CONTENTS, new Integer(csize * 2 + 2));
sap.preClose(exc);
// подписание
byte[] data = CMSSign(IOUtils.readFully(sap.getRangeStream(), -1, true), key, chain, certCA, true);
byte[] outc = new byte[csize];
PdfDictionary dic2 = new PdfDictionary();
System.arraycopy(data, 0, outc, 0, data.length);
dic2.put(PdfName.CONTENTS, new PdfString(outc).setHexWriting(true));
sap.close(dic2);
fOut.close();
Код:
public static byte[] CMSSign(byte[] data, PrivateKey key, Certificate[] certs, byte[] certCA, boolean detached) throws Exception {
// sign
final Signature signature = Signature.getInstance(JCP.GOST_EL_SIGN_NAME, "JCSP");
signature.initSign(key);
signature.update(data);
final byte[] sign = signature.sign();
// create cms format
return createCMS(data, sign, certs, certCA, detached);
}
public static byte[] createCMS(byte[] buffer, byte[] sign, Certificate[] certs, byte[] certCA, boolean detached) throws Exception {
final ContentInfo all = new ContentInfo();
all.contentType = new Asn1ObjectIdentifier(
new OID("1.2.840.113549.1.7.2").value);
final SignedData cms = new SignedData();
all.content = cms;
cms.version = new CMSVersion(1);
// digest
cms.digestAlgorithms = new DigestAlgorithmIdentifiers(1);
final DigestAlgorithmIdentifier a = new DigestAlgorithmIdentifier(
new OID(JCP.GOST_DIGEST_OID).value);
a.parameters = new Asn1Null();
cms.digestAlgorithms.elements[0] = a;
if (detached) {
cms.encapContentInfo = new EncapsulatedContentInfo(
new Asn1ObjectIdentifier(
new OID("1.2.840.113549.1.7.1").value), null);
} else {
cms.encapContentInfo =
new EncapsulatedContentInfo(new Asn1ObjectIdentifier(
new OID("1.2.840.113549.1.7.1").value),
new Asn1OctetString(buffer));
}
// certificate
final int ncerts = certs.length;
cms.certificates = new CertificateSet(ncerts + 1);
cms.certificates.elements = new CertificateChoices[ncerts + 1];
for(int i = 0; i < cms.certificates.elements.length - 1; i++) {
final ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate certificate =
new ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate();
final Asn1BerDecodeBuffer decodeBuffer =
new Asn1BerDecodeBuffer(certs[i].getEncoded());
certificate.decode(decodeBuffer);
cms.certificates.elements[i] = new CertificateChoices();
cms.certificates.elements[i].set_certificate(certificate);
}
final ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate certificate =
new ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate();
final Asn1BerDecodeBuffer decodeBuffer =
new Asn1BerDecodeBuffer(certCA);
certificate.decode(decodeBuffer);
cms.certificates.elements[cms.certificates.elements.length - 1] = new CertificateChoices();
cms.certificates.elements[cms.certificates.elements.length - 1].set_certificate(certificate);
// signer info
cms.signerInfos = new SignerInfos(1);
cms.signerInfos.elements[0] = new SignerInfo();
cms.signerInfos.elements[0].version = new CMSVersion(1);
cms.signerInfos.elements[0].sid = new SignerIdentifier();
final byte[] encodedName = ((X509Certificate) certs[0]).getIssuerX500Principal().getEncoded();
final Asn1BerDecodeBuffer nameBuf = new Asn1BerDecodeBuffer(encodedName);
final Name name = new Name();
name.decode(nameBuf);
final CertificateSerialNumber num = new CertificateSerialNumber(
((X509Certificate) certs[0]).getSerialNumber());
cms.signerInfos.elements[0].sid.set_issuerAndSerialNumber(
new IssuerAndSerialNumber(name, num));
cms.signerInfos.elements[0].digestAlgorithm =
new DigestAlgorithmIdentifier(new OID(JCP.GOST_DIGEST_OID).value);
cms.signerInfos.elements[0].digestAlgorithm.parameters = new Asn1Null();
cms.signerInfos.elements[0].signatureAlgorithm =
new SignatureAlgorithmIdentifier(new OID(JCP.GOST_EL_KEY_OID).value);
cms.signerInfos.elements[0].signatureAlgorithm.parameters = new Asn1Null();
cms.signerInfos.elements[0].signature = new SignatureValue(sign);
// encode
final Asn1BerEncodeBuffer asnBuf = new Asn1BerEncodeBuffer();
all.encode(asnBuf, true);
return asnBuf.getMsgCopy();
}
Первый раз подписание проходит нормально, проверку подпись проходит. Но, когда я подписываю файл повторно другой подписью, первая подпись становится недействительной. Acrobat пишет такое: Цитата:Ошибка при подтверждении подписи.
Неожиданное значение байтового диапазона подписанных данных. Подробно: Байтовый диапазон подписи недействителен Подскажите, пожалуйста, в чем ошибка? PS: версия iText 5.5.10 Отредактировано пользователем 11 мая 2017 г. 15:40:09(UTC)
| Причина: Не указана
|