Apache PDFBox 2.0.4, как проверить pdf с подфильтром "adbe.x509.rsa_sha1".?

Поскольку я могу получить объект сертификата из сертификата, который добавлен в части содержимого.., я запутался в том, как проверять / проверять подписанный контент для PKCS#1, т.е. adbe.x509.rsa_sha1 . Любая помощь будет оценена.!!

1 ответ

COSDictionary sigDict = sig.getCOSObject();
COSString contents = (COSString) sigDict.getDictionaryObject(COSName.CONTENTS);
// download the signed content
byte[] buf;
try (FileInputStream fis = new FileInputStream(infile))
{
    buf = sig.getSignedContent(fis);
}
COSString certString = (COSString) sigDict.getDictionaryObject(COSName.CERT);
byte[] certData = certString.getBytes();
CertificateFactory factory = CertificateFactory.getInstance("X.509");
ByteArrayInputStream certStream = new ByteArrayInputStream(certData);
Collection<? extends Certificate> certs = factory.generateCertificates(certStream);

// inspired by:
// https://www.programcreek.com/java-api-examples/index.php?source_dir=pades_signing_2.1.5-master/src/main/java/com/opentrust/spi/pdf/PDFEnvelopedSignature.java
ASN1InputStream asn1IS = new ASN1InputStream(new ByteArrayInputStream(contents.getBytes()));
ASN1Primitive asn1prim = asn1IS.readObject();
if (!(asn1prim instanceof ASN1OctetString))
{
    throw new IOException("ASN1 octet string expected, but got " + asn1prim.getClass().getSimpleName());
}
ASN1OctetString oct = (ASN1OctetString) asn1prim;
X509Certificate cert = (X509Certificate) certs.iterator().next();
Signature signature = Signature.getInstance("SHA1withRSA");
signature.initVerify(cert.getPublicKey());
signature.update(buf);
System.out.println("Verification result: " + signature.verify(oct.getOctets()));

Верхняя часть взята из примера ShowSignature.java PDFBox. Нижние части основаны на коде, найденном в классе PDFEnvelopedSignature в OpenTrust/pades_signing_2.1.5 от Paulo Soares, см. Лицензию в исходном коде здесь или здесь.

Пример файла можно найти в выпуске PDFBOX-2693.

Обновление 30.11.2018:

Получение алгоритма с cert.getSigAlgName() не всегда дает фактический алгоритм. Ссылка выше также показывает код для получения правильного алгоритма дайджеста, вставьте следующий код после строки с "oct = ":

Cipher c = Cipher.getInstance("RSA/NONE/PKCS1Padding", SecurityProvider.getProvider());
c.init(Cipher.DECRYPT_MODE, cert.getPublicKey());
byte[] raw = c.doFinal(oct.getOctets());
DigestInfo di = DigestInfo.getInstance(raw);
String algID = di.getAlgorithmId().getAlgorithm().getId();

Допустимые значения:

RIPEMD160  1.3.36.3.2.1            TeleTrusTObjectIdentifiers.ripemd160
SHA1       1.3.14.3.2.26           OIWObjectIdentifiers.idSHA1
SHA256     2.16.840.1.101.3.4.2.1  NISTObjectIdentifiers.id_sha256
SHA384     2.16.840.1.101.3.4.2.2  NISTObjectIdentifiers.id_sha384
SHA512     2.16.840.1.101.3.4.2.3  NISTObjectIdentifiers.id_sha512

Однако у меня никогда не было ничего, кроме SHA1, поэтому сейчас я его жестко запрограммировал.

Другие вопросы по тегам