我能够使用PDFBox1.8.5对PDF文档进行数字签名,多亏了PDFBOX中提供的这个出色的示例。
https://github.com/apache/pdfbox/blob/1.8/examples/src/main/java/org/apache/pdfbox/examples/signature/createSignature.java
签名此示例时,请使用本地计算机的日期/时间(第175行):
//有效签名signature.SetSignDate(Calendar.GetInstance())所需的签名日期;
有人知道如何使用PDFBOX的外部TSA吗?
多谢了。
createSignature
PDFBox示例在2.0.0-Snapshot开发版本中进行了扩展,可以选择包含来自某些TSA的时间戳。
主要区别在于,在sign(InputStream)
中创建CMS签名后,CMS签名容器在另一个方法signtimestamps(CMSSignedData)
中得到增强,以同时携带签名时间戳:
public byte[] sign(InputStream content) throws IOException
{
...
CMSSignedData signedData = gen.generate(processable, false);
// vvv Additional call
if (tsaClient != null)
{
signedData = signTimeStamps(signedData);
}
// ^^^ Additional call
return signedData.getEncoded();
...
}
// vvv Additional helper methods
private CMSSignedData signTimeStamps(CMSSignedData signedData)
throws IOException, TSPException
{
SignerInformationStore signerStore = signedData.getSignerInfos();
List<SignerInformation> newSigners = new ArrayList<SignerInformation>();
for (SignerInformation signer : (Collection<SignerInformation>)signerStore.getSigners())
{
newSigners.add(signTimeStamp(signer));
}
return CMSSignedData.replaceSigners(signedData, new SignerInformationStore(newSigners));
}
private SignerInformation signTimeStamp(SignerInformation signer)
throws IOException, TSPException
{
AttributeTable unsignedAttributes = signer.getUnsignedAttributes();
ASN1EncodableVector vector = new ASN1EncodableVector();
if (unsignedAttributes != null)
{
vector = unsignedAttributes.toASN1EncodableVector();
}
byte[] token = tsaClient.getTimeStampToken(signer.getSignature());
ASN1ObjectIdentifier oid = PKCSObjectIdentifiers.id_aa_signatureTimeStampToken;
ASN1Encodable signatureTimeStamp = new Attribute(oid, new DERSet(byteToASN1Object(token)));
vector.add(signatureTimeStamp);
Attributes signedAttributes = new Attributes(vector);
SignerInformation newSigner = SignerInformation.replaceUnsignedAttributes(
signer, new AttributeTable(signedAttributes));
if (newSigner == null)
{
return signer;
}
return newSigner;
}
private ASN1Object byteToASN1Object(byte[] data) throws IOException
{
ASN1InputStream in = new ASN1InputStream(data);
try
{
return in.readObject();
}
finally
{
in.close();
}
}
// ^^^ Additional helper methods
(createSignature.java,2.0.0-快照开发版本)
这里的tsaclient
是一个新的createSignature
成员变量,其中包含一个与所讨论的外部TSA接口的tsaclient
实例:
/**
* Time Stamping Authority (TSA) Client [RFC 3161].
* @author Vakhtang Koroghlishvili
* @author John Hewson
*/
public class TSAClient
{
private static final Log log = LogFactory.getLog(TSAClient.class);
private final URL url;
private final String username;
private final String password;
private final MessageDigest digest;
public TSAClient(URL url, String username, String password, MessageDigest digest)
{
this.url = url;
this.username = username;
this.password = password;
this.digest = digest;
}
public byte[] getTimeStampToken(byte[] messageImprint) throws IOException
{
digest.reset();
byte[] hash = digest.digest(messageImprint);
// 32-bit cryptographic nonce
SecureRandom random = new SecureRandom();
int nonce = random.nextInt();
// generate TSA request
TimeStampRequestGenerator tsaGenerator = new TimeStampRequestGenerator();
tsaGenerator.setCertReq(true);
ASN1ObjectIdentifier oid = getHashObjectIdentifier(digest.getAlgorithm());
TimeStampRequest request = tsaGenerator.generate(oid, hash, BigInteger.valueOf(nonce));
// get TSA response
byte[] tsaResponse = getTSAResponse(request.getEncoded());
TimeStampResponse response;
try
{
response = new TimeStampResponse(tsaResponse);
response.validate(request);
}
catch (TSPException e)
{
throw new IOException(e);
}
TimeStampToken token = response.getTimeStampToken();
if (token == null)
{
throw new IOException("Response does not have a time stamp token");
}
return token.getEncoded();
}
// gets response data for the given encoded TimeStampRequest data
// throws IOException if a connection to the TSA cannot be established
private byte[] getTSAResponse(byte[] request) throws IOException
{
log.debug("Opening connection to TSA server");
// todo: support proxy servers
URLConnection connection = url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestProperty("Content-Type", "application/timestamp-query");
log.debug("Established connection to TSA server");
if (username != null && password != null)
{
if (!username.isEmpty() && !password.isEmpty())
{
connection.setRequestProperty(username, password);
}
}
// read response
OutputStream output = null;
try
{
output = connection.getOutputStream();
output.write(request);
}
finally
{
IOUtils.closeQuietly(output);
}
log.debug("Waiting for response from TSA server");
InputStream input = null;
byte[] response;
try
{
input = connection.getInputStream();
response = IOUtils.toByteArray(input);
}
finally
{
IOUtils.closeQuietly(input);
}
log.debug("Received response from TSA server");
return response;
}
// returns the ASN.1 OID of the given hash algorithm
private ASN1ObjectIdentifier getHashObjectIdentifier(String algorithm)
{
// TODO can bouncy castle or Java provide this information?
if (algorithm.equals("MD2"))
{
return new ASN1ObjectIdentifier("1.2.840.113549.2.2");
}
else if (algorithm.equals("MD5"))
{
return new ASN1ObjectIdentifier("1.2.840.113549.2.5");
}
else if (algorithm.equals("SHA-1"))
{
return new ASN1ObjectIdentifier("1.3.14.3.2.26");
}
else if (algorithm.equals("SHA-224"))
{
return new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.4");
}
else if (algorithm.equals("SHA-256"))
{
return new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.1");
}
else if (algorithm.equals("SHA-394"))
{
return new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.2");
}
else if (algorithm.equals("SHA-512"))
{
return new ASN1ObjectIdentifier("2.16.840.1.101.3.4.2.3");
}
else
{
return new ASN1ObjectIdentifier(algorithm);
}
}
}
(tsaclient.java,2.0.0-快照开发版本)
由于这些添加仅取决于所使用的BouncyCastle版本,而不是PDFBox代码,因此该代码也应易于后端口,以便与PDFBox 1.8.x一起使用。
问题内容: 当我尝试自签名时,如下所示。 它给出如下警告: 没有提供-tsa或- tsacert,并且这个jar没有时间戳记。如果没有时间戳,则用户可能无法在签署者证书的到期日期(2014-05-08)或以后的任何吊销日期之后验证此jar。 请帮助解决问题。 问题答案: 最近的Java 7提供了(礼貌吗?)关于已经存在十年的警告。 Trusted Timestamping在Java 5(2004)
我试图签署一个pdf与时间戳和LTV启用,以便它是这样显示在Adobe Reader: 在英语中,它意味着“签名包括嵌入的时间戳”和“签名启用了LTV”。下面是我使用的代码: 基于此答案,我需要一种方法将TSA证书的CRL获取到,但是。。如何获得TSA证书?我是否需要向TSA发出请求并读取响应,然后将其添加到?注意,这已经在。请注意,我使用的是免费的TSA服务器。 更新 因为它是一个免费的TSA服
我已经通过TSA创建了带有时间戳的数字签名。在本文中,我在TSA响应中为building chain添加了证书,用于building chain。这很好,而且还创建了签名,但在使用pdf box API for Java将此签名嵌入pdf时,它给错误提供的空间不足,无法写入签名。PDF框中是否有可用于处理签名大小的配置? 任何帮助都将不胜感激。
系统支持自动写入创建和更新的时间戳字段(默认关闭),有两种方式配置支持。 第一种方式是全局开启,在数据库配置文件中进行设置: // 开启自动写入时间戳字段 'auto_timestamp' => true, 第二种是在需要的模型类里面单独开启: <?php namespace app\index\model; use think\Model; class User extends Model
我尝试使用外部Web服务对pdf进行数字签名。此Web服务包含用户证书,用户可以使用他们的凭据和一次性密码生成的代码访问该证书。 旁注:web服务应该期望pdf摘要(哈希),但奇怪的是,它却接受整个文件。 无论如何,实现如下: pdf已成功签名,但使用Adobe Reader并检查签名字段时,似乎缺少可信时间戳,如图所示: 看起来,来自远程服务的响应是一个签名对象,我只需要将其嵌入到PDF文件中。
我确实使用IText通过延迟签名(SignDeferred)将签名应用于pdf文档。该过程包含以下步骤: 为siging准备pdf文档 为pdf文档中的签名预留空间 使用自签名证书 整个过程工作,我以一个pdf文档结束,其中签名被设置并有效。 原始pdf是pdf-A1a,但生成的pdf不再是有效的pdf-A1a。我知道有一个关于IText PDF-a支持的文档(https://kb.itextpd