- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我们正在尝试启用签名 LTV。我正在使用下面的代码来添加验证。当signature.isTsp()为假时,PDF显示签名未启用LTV
,尽管在其他情况下(signature.isTsp()为true)它显示为有效。当我们打开 PDF 并尝试通过右键单击签名来手动添加验证信息时,它会毫无问题地启用 LTV。不确定我们在这里缺少什么。任何输入都会非常有帮助。
// Adds LTV-enabled information to the PDF document.
private ByteArrayOutputStream addLtv(final IOcspClient ocspClient,
final ByteArrayOutputStream docStream)
throws IOException, GeneralSecurityException {
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
final InputStream signedStream = new ByteArrayInputStream(docStream.toByteArray());
final PdfReader reader = new PdfReader(signedStream);
final PdfDocument document =
new PdfDocument(reader, new PdfWriter(outputStream), new StampingProperties().useAppendMode());
final LtvVerification verification = new LtvVerification(document);
final SignatureUtil signatureUtil = new SignatureUtil(document);
final List<String> signatureNames = signatureUtil.getSignatureNames();
final String sigName = signatureNames.get(signatureNames.size() - 1);
final PdfPKCS7 signature = signatureUtil.verifySignature(sigName);
final CrlClientOnline crl = new CrlClientOnline();
if (!signature.isTsp()) {
for (final String name: signatureNames) {
addVerificationInfo(ocspClient, verification, crl, name);
}
} else {
addVerificationInfo(ocspClient, verification, crl, sigName);
}
document.close();
return outputStream;
}
private void addVerificationInfo(final IOcspClient ocspClient, final LtvVerification verification,
final CrlClientOnline crl,
final String name) throws IOException, GeneralSecurityException {
verification.addVerification(
name, ocspClient, crl,
LtvVerification.CertificateOption.WHOLE_CHAIN,
LtvVerification.Level.OCSP_CRL,
LtvVerification.CertificateInclusion.NO);
}
最佳答案
您的代码并不总是支持 LTV 的 PDF 的主要原因是它没有添加与 OCSP 响应签名相关的验证信息。
它也不添加 CRL 签名的验证信息。不过,由于 CRL 通常由签名者证书的颁发者证书进行签名,并且该颁发者证书的验证信息已添加到主签名的上下文中,因此 LTV 启用通常不会因为缺少 CRL 签名验证信息而失败。因此,如果您只能使用 CRL,那么您的代码很可能确实已经支持 LTV 的 PDF。
在this answer的背景下(特别是其“使用自己的实用程序类的方法”部分)我为 iText 5 创建了一个实用程序类 AdobeLtvEnabling
,允许启用 LTV 的 PDF,主要使用 iText 5 本身中的零碎内容。与您的代码相比,它确实添加了 OCSP 响应签名(以及 CRL 签名)的验证信息。
在这里您可以找到该类到 iText 7 的端口。
AdobeLtvEnabling
此实用程序类捆绑了 LTV 所需的代码,以在签名的 PDF 文档中启用签名。这些代码片段大部分取自现有的 iText 代码。此类未设计为从 LtvVerification
派生的主要原因是该类所需的变量和方法是私有(private)
。由于该类最初是为 iText 5 编写的,因此可能可以在其中找到一些 iText-5-isms...
public class AdobeLtvEnabling {
/**
* Use this constructor with a {@link PdfDocument} in append mode. Otherwise
* the existing signatures will be damaged.
*/
public AdobeLtvEnabling(PdfDocument pdfDocument) {
this.pdfDocument = pdfDocument;
}
/**
* Call this method to have LTV information added to the {@link PdfDocument}
* given in the constructor.
*/
public void enable(IOcspClient ocspClient, ICrlClient crlClient) throws OperatorException, GeneralSecurityException, IOException, StreamParsingException, OCSPException {
SignatureUtil signatureUtil = new SignatureUtil(pdfDocument);
List<String> names = signatureUtil.getSignatureNames();
for (String name : names) {
PdfPKCS7 pdfPKCS7 = signatureUtil.verifySignature(name, BouncyCastleProvider.PROVIDER_NAME);
PdfSignature sig = signatureUtil.getSignature(name);
List<X509Certificate> certificatesToCheck = new ArrayList<>();
certificatesToCheck.add(pdfPKCS7.getSigningCertificate());
while (!certificatesToCheck.isEmpty()) {
X509Certificate certificate = certificatesToCheck.remove(0);
addLtvForChain(certificate, ocspClient, crlClient, getSignatureHashKey(sig));
}
}
outputDss();
}
//
// the actual LTV enabling methods
//
void addLtvForChain(X509Certificate certificate, IOcspClient ocspClient, ICrlClient crlClient, PdfName key) throws GeneralSecurityException, IOException, StreamParsingException, OperatorCreationException, OCSPException {
ValidationData validationData = new ValidationData();
while (certificate != null) {
System.out.println(certificate.getSubjectX500Principal().getName());
X509Certificate issuer = getIssuerCertificate(certificate);
validationData.certs.add(certificate.getEncoded());
byte[] ocspResponse = ocspClient.getEncoded(certificate, issuer, null);
if (ocspResponse != null) {
System.out.println(" with OCSP response");
validationData.ocsps.add(ocspResponse);
X509Certificate ocspSigner = getOcspSignerCertificate(ocspResponse);
if (ocspSigner != null) {
System.out.printf(" signed by %s\n", ocspSigner.getSubjectX500Principal().getName());
}
addLtvForChain(ocspSigner, ocspClient, crlClient, getOcspHashKey(ocspResponse));
} else {
Collection<byte[]> crl = crlClient.getEncoded(certificate, null);
if (crl != null && !crl.isEmpty()) {
System.out.printf(" with %s CRLs\n", crl.size());
validationData.crls.addAll(crl);
for (byte[] crlBytes : crl) {
addLtvForChain(null, ocspClient, crlClient, getCrlHashKey(crlBytes));
}
}
}
certificate = issuer;
}
validated.put(key, validationData);
}
void outputDss() throws IOException {
PdfDictionary dss = new PdfDictionary();
PdfDictionary vrim = new PdfDictionary();
PdfArray ocsps = new PdfArray();
PdfArray crls = new PdfArray();
PdfArray certs = new PdfArray();
PdfCatalog catalog = pdfDocument.getCatalog();
if (pdfDocument.getPdfVersion().compareTo(PdfVersion.PDF_2_0) < 0) {
catalog.addDeveloperExtension(PdfDeveloperExtension.ESIC_1_7_EXTENSIONLEVEL5);
catalog.addDeveloperExtension(new PdfDeveloperExtension(PdfName.ADBE, new PdfName("1.7"), 8));
}
for (PdfName vkey : validated.keySet()) {
PdfArray ocsp = new PdfArray();
PdfArray crl = new PdfArray();
PdfArray cert = new PdfArray();
PdfDictionary vri = new PdfDictionary();
for (byte[] b : validated.get(vkey).crls) {
PdfStream ps = new PdfStream(b);
ps.setCompressionLevel(CompressionConstants.DEFAULT_COMPRESSION);
ps.makeIndirect(pdfDocument);
crl.add(ps);
crls.add(ps);
crls.setModified();
}
for (byte[] b : validated.get(vkey).ocsps) {
b = buildOCSPResponse(b);
PdfStream ps = new PdfStream(b);
ps.setCompressionLevel(CompressionConstants.DEFAULT_COMPRESSION);
ps.makeIndirect(pdfDocument);
ocsp.add(ps);
ocsps.add(ps);
ocsps.setModified();
}
for (byte[] b : validated.get(vkey).certs) {
PdfStream ps = new PdfStream(b);
ps.setCompressionLevel(CompressionConstants.DEFAULT_COMPRESSION);
ps.makeIndirect(pdfDocument);
cert.add(ps);
certs.add(ps);
certs.setModified();
}
if (ocsp.size() > 0) {
ocsp.makeIndirect(pdfDocument);
vri.put(PdfName.OCSP, ocsp);
}
if (crl.size() > 0) {
crl.makeIndirect(pdfDocument);
vri.put(PdfName.CRL, crl);
}
if (cert.size() > 0) {
cert.makeIndirect(pdfDocument);
vri.put(PdfName.Cert, cert);
}
vri.put(PdfName.TU, new PdfDate().getPdfObject());
vri.makeIndirect(pdfDocument);
vrim.put(vkey, vri);
}
vrim.makeIndirect(pdfDocument);
vrim.setModified();
dss.put(PdfName.VRI, vrim);
if (ocsps.size() > 0) {
ocsps.makeIndirect(pdfDocument);
dss.put(PdfName.OCSPs, ocsps);
}
if (crls.size() > 0) {
crls.makeIndirect(pdfDocument);
dss.put(PdfName.CRLs, crls);
}
if (certs.size() > 0) {
certs.makeIndirect(pdfDocument);
dss.put(PdfName.Certs, certs);
}
dss.makeIndirect(pdfDocument);
dss.setModified();
catalog.put(PdfName.DSS, dss);
}
//
// VRI signature hash key calculation
//
static PdfName getCrlHashKey(byte[] crlBytes) throws NoSuchAlgorithmException, IOException, CRLException, CertificateException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(crlBytes));
byte[] signatureBytes = crl.getSignature();
DEROctetString octetString = new DEROctetString(signatureBytes);
byte[] octetBytes = octetString.getEncoded();
byte[] octetHash = hashBytesSha1(octetBytes);
PdfName octetName = new PdfName(convertToHex(octetHash));
return octetName;
}
static PdfName getOcspHashKey(byte[] basicResponseBytes) throws NoSuchAlgorithmException, IOException {
BasicOCSPResponse basicResponse = BasicOCSPResponse.getInstance(basicResponseBytes);
byte[] signatureBytes = basicResponse.getSignature().getBytes();
DEROctetString octetString = new DEROctetString(signatureBytes);
byte[] octetBytes = octetString.getEncoded();
byte[] octetHash = hashBytesSha1(octetBytes);
PdfName octetName = new PdfName(convertToHex(octetHash));
return octetName;
}
static PdfName getSignatureHashKey(PdfSignature sig) throws NoSuchAlgorithmException, IOException {
PdfString contents = sig.getContents();
byte[] bc = PdfEncodings.convertToBytes(contents.getValue(), null);
if (PdfName.ETSI_RFC3161.equals(sig.getSubFilter())) {
try ( ASN1InputStream din = new ASN1InputStream(new ByteArrayInputStream(bc)) ) {
ASN1Primitive pkcs = din.readObject();
bc = pkcs.getEncoded();
}
}
byte[] bt = hashBytesSha1(bc);
return new PdfName(convertToHex(bt));
}
static byte[] hashBytesSha1(byte[] b) throws NoSuchAlgorithmException {
MessageDigest sh = MessageDigest.getInstance("SHA1");
return sh.digest(b);
}
static String convertToHex(byte[] bytes) {
ByteBuffer buf = new ByteBuffer();
for (byte b : bytes) {
buf.appendHex(b);
}
return PdfEncodings.convertToString(buf.toByteArray(), null).toUpperCase();
}
//
// OCSP response helpers
//
static X509Certificate getOcspSignerCertificate(byte[] basicResponseBytes) throws CertificateException, OCSPException, OperatorCreationException {
JcaX509CertificateConverter converter = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME);
BasicOCSPResponse borRaw = BasicOCSPResponse.getInstance(basicResponseBytes);
BasicOCSPResp bor = new BasicOCSPResp(borRaw);
for (final X509CertificateHolder x509CertificateHolder : bor.getCerts()) {
X509Certificate x509Certificate = converter.getCertificate(x509CertificateHolder);
JcaContentVerifierProviderBuilder jcaContentVerifierProviderBuilder = new JcaContentVerifierProviderBuilder();
jcaContentVerifierProviderBuilder.setProvider(BouncyCastleProvider.PROVIDER_NAME);
final PublicKey publicKey = x509Certificate.getPublicKey();
ContentVerifierProvider contentVerifierProvider = jcaContentVerifierProviderBuilder.build(publicKey);
if (bor.isSignatureValid(contentVerifierProvider))
return x509Certificate;
}
return null;
}
static byte[] buildOCSPResponse(byte[] BasicOCSPResponse) throws IOException {
DEROctetString doctet = new DEROctetString(BasicOCSPResponse);
ASN1EncodableVector v2 = new ASN1EncodableVector();
v2.add(OCSPObjectIdentifiers.id_pkix_ocsp_basic);
v2.add(doctet);
ASN1Enumerated den = new ASN1Enumerated(0);
ASN1EncodableVector v3 = new ASN1EncodableVector();
v3.add(den);
v3.add(new DERTaggedObject(true, 0, new DERSequence(v2)));
DERSequence seq = new DERSequence(v3);
return seq.getEncoded();
}
//
// X509 certificate related helpers
//
static X509Certificate getIssuerCertificate(X509Certificate certificate) throws IOException, StreamParsingException {
String url = getCACURL(certificate);
if (url != null && url.length() > 0) {
HttpURLConnection con = (HttpURLConnection)new URL(url).openConnection();
if (con.getResponseCode() / 100 != 2) {
throw new PdfException(PdfException.InvalidHttpResponse1).setMessageParams(con.getResponseCode());
}
InputStream inp = (InputStream) con.getContent();
X509CertParser parser = new X509CertParser();
parser.engineInit(new ByteArrayInputStream(StreamUtil.inputStreamToArray(inp)));
return (X509Certificate) parser.engineRead();
}
return null;
}
static String getCACURL(X509Certificate certificate) {
ASN1Primitive obj;
try {
obj = getExtensionValue(certificate, Extension.authorityInfoAccess.getId());
if (obj == null) {
return null;
}
ASN1Sequence AccessDescriptions = (ASN1Sequence) obj;
for (int i = 0; i < AccessDescriptions.size(); i++) {
ASN1Sequence AccessDescription = (ASN1Sequence) AccessDescriptions.getObjectAt(i);
if ( AccessDescription.size() != 2 ) {
continue;
}
else if (AccessDescription.getObjectAt(0) instanceof ASN1ObjectIdentifier) {
ASN1ObjectIdentifier id = (ASN1ObjectIdentifier)AccessDescription.getObjectAt(0);
if ("1.3.6.1.5.5.7.48.2".equals(id.getId())) {
ASN1Primitive description = (ASN1Primitive)AccessDescription.getObjectAt(1);
String AccessLocation = getStringFromGeneralName(description);
if (AccessLocation == null) {
return "" ;
}
else {
return AccessLocation ;
}
}
}
}
} catch (IOException e) {
return null;
}
return null;
}
static ASN1Primitive getExtensionValue(X509Certificate certificate, String oid) throws IOException {
byte[] bytes = certificate.getExtensionValue(oid);
if (bytes == null) {
return null;
}
ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(bytes));
ASN1OctetString octs = (ASN1OctetString) aIn.readObject();
aIn = new ASN1InputStream(new ByteArrayInputStream(octs.getOctets()));
return aIn.readObject();
}
static String getStringFromGeneralName(ASN1Primitive names) throws IOException {
ASN1TaggedObject taggedObject = (ASN1TaggedObject) names ;
return new String(ASN1OctetString.getInstance(taggedObject, false).getOctets(), "ISO-8859-1");
}
//
// inner class
//
static class ValidationData {
final List<byte[]> crls = new ArrayList<byte[]>();
final List<byte[]> ocsps = new ArrayList<byte[]>();
final List<byte[]> certs = new ArrayList<byte[]>();
}
//
// member variables
//
final PdfDocument pdfDocument;
final Map<PdfName,ValidationData> validated = new HashMap<PdfName,ValidationData>();
}
您可以像这样使用 AdobeLtvEnabling
类:
try ( PdfReader pdfReader = new PdfReader(SOURCE);
PdfWriter pdfWriter = new PdfWriter(TARGET);
PdfDocument pdfDocument = new PdfDocument(pdfReader, pdfWriter,
new StampingProperties().preserveEncryption().useAppendMode())) {
AdobeLtvEnabling adobeLtvEnabling = new AdobeLtvEnabling(pdfDocument);
IOcspClient ocsp = new OcspClientBouncyCastle(null);
ICrlClient crl = new CrlClientOnline();
adobeLtvEnabling.enable(ocsp, crl);
}
( MakeLtvEnabled 测试 testLtvEnableSignWithoutLtv
)
由于此代码本质上是从引用答案的 iText 5 代码移植而来,因此它也继承了该答案中列出的限制:
代码在一些简化的限制下工作,特别是:
如果您不能接受这些限制,您可以相应地改进代码。
关于java - iText7 LtvVerification.addVerification 未启用 LTV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51639464/
我找到了 this excellent question and answer它以 x/y(加上 center x/y 和 degrees/radians)开始并计算旋转- 到 x'/y'。这个计算很
全部: 我已经创建了一个 Windows 窗体和一个按钮。在另一个线程中,我试图更改按钮的文本,但它崩溃了;但是如果我尝试更改按钮的颜色,它肯定会成功。我认为如果您更改任何 Windows 窗体控件属
本网站的另一个问题已证实,C 中没有缩写的字面后缀,并且可以执行以下操作: short Number = (short)1; 但是转换它和不这样做有什么区别: short Number = 1; 您使
我有下表: ID (int) EMAIL (varchar(50)) CAMPAIGNID (int) isSubscribe (bit) isActionByUser (bit) 此表存储了用户对事
也就是说,无需触发Javascript事件即可改变的属性,如何保留我手动选中或取消选中的复选框的状态,然后复制到另一个地方? 运行下面的代码片段并选中或取消选中其中的一些,然后点击“复制”: $('#
我在网上找到的所有关于递增指针导致段错误的示例都涉及指针的取消引用 - 如果我只想递增它(例如在 for 循环的末尾)并且我不在乎它是否最终进入无效内存,因为我不会再使用它。例如,在这个程序中,每次迭
我有一个 Spring MVC REST 服务,它使用 XStream 将消息与 XML 相互转换。 有什么方法可以将请求和响应中的 xml(即正文)打印到普通的 log4j 记录器? 在 Contr
做我的任务有一个很大的挑战,那就是做相互依赖的任务我在这张照片中说的。假设我们有两个任务 A 和 B,执行子任务 A1、A2 和 B1、B2,假设任务 B 依赖于 A。 要理想地执行任务 B,您应该执
通过阅读该网站上的几个答案,我了解到 CoInitialize(Ex) should be called by the creator of a thread 。然后,在该线程中运行的任何代码都可以使
这个问题已经困扰我一段时间了。我以前从未真正使用过 ListViews,也没有使用过 FirebaseListAdapters。我想做的就是通过显示 id 和用户位置来启动列表的基础,但由于某种原因,
我很难解释这两个(看似简单)句子的含义: “受检异常由编译器在编译时检查” 这是什么意思?编译器检查是否捕获了所有已检查的异常(在代码中抛出)? “未经检查的异常在运行时检查,而不是编译时” 这句话中
我有一个包含排除子字符串的文本文件,我想迭代该文件以检查并返回不带排除子字符串的输入项。 这里我使用 python 2.4,因此下面的代码可以实现此目的,因为 with open 和 any 不起作用
Spring 的缓存框架能否了解请求上下文的身份验证状态,或者更容易推出自己的缓存解决方案? 最佳答案 尽管我发现这个用例 super 奇怪,但您可以为几乎任何与 SpEL 配合使用的内容设置缓存条件
我有以下函数模板: template HeldAs* duplicate(MostDerived *original, HeldAs *held) { // error checking omi
如果我的应用程序具有设备管理员/设备所有者权限(未获得 root 权限),我如何才能从我的应用程序中终止(或阻止启动)另一个应用程序? 最佳答案 设备所有者可以阻止应用程序: DevicePolicy
非常简单的问题,但我似乎无法让它正常工作。 我有一个组件,其中有一些 XSLT(用于导航)。它通过 XSLT TBB 使用 XSLT Mediator 发布。 发布后
我正在将一个对象拖动到一个可拖放的对象内,该对象也是可拖动的。放置对象后,它会嵌套在可放置对象内。同样,如果我将对象拖到可放置的外部,它就不再嵌套。 但是,如果我经常拖入和拖出可放置对象,则可拖动对象
我正在尝试为按钮和弹出窗口等多个指令实现“取消选择”功能。也就是说,我希望当用户单击不属于指令模板一部分的元素时触发我的函数。目前,我正在使用以下 JQuery 代码: $('body').click
我从 this question 得到了下面的代码,该脚本用于在 Google tasks 上更改 iframe[src="about:blank"] 内的 CSS使用 Chrome 扩展 Tempe
我有一些 @Mock 对象,但没有指定在该对象上调用方法的返回值。该方法返回 int (不是 Integer)。我很惊讶地发现 Mockito 没有抛出 NPE 并返回 0。这是预期的行为吗? 例如:
我是一名优秀的程序员,十分优秀!