我正在使用iTextSharp库对PDF文档进行签名。
当我使用标准TSAClientBouncyCastle
类从GoDaddy的服务器获取时间戳时(http://tsa.starfieldtech.com),响应是一个空流。
同时,它可以完美地与其他符合RFC 3161的时间戳服务器配合使用。此外,当我使用Microsoft的signtool.exe用/tr
选项对exe文件进行签名时,它可以与Godaddy的服务器一起使用。
因此,我想知道使用iTextSharp库以编程方式获取时间戳的尝试有什么问题。
更新
我用过这个样品:
http://sourceforge.net/p/itextsharp/code/HEAD/tree/tutorial/signatures/chapter2/C2_01_SignHelloWorld/C2_01_SignHelloWorld.cs
只需修改一下,我就指定了一个带有构造函数的TSAClient
,该构造函数接受URL。
这意味着不需要调用:
MakeSignature.SignDetached(appearance, pks, chain, null, null, null, 0, subfilter);
我使用:
ITSAClient tsaClient = new TSAClientBouncyCastle("http://tsa.starfieldtech.com/");
MakeSignature.SignDetached(外观,pks,chain,null,null,tsaClient,0,subfilter);
当我使用标准
TSAClientBouncyCastle
类从GoDaddy的服务器获取时间戳时(http://tsa.starfieldtech.com),响应是一个空流。
我可以使用iTextSharp&C#而不是iText&Java语言
通过检查实际的网络流量,时间戳请求对象被证明是完全相同的,但在封装HTTP请求中使用的HTTP标头中存在微小差异。
逐个调整TSAClientBouncyCastle.GetTSAResponse
中的请求标头,用户代理标头被证明是罪魁祸首:
- .Net
HttpWebRequest
默认情况下似乎没有添加这样的标头,但是 - Java
HttpURLConnection
默认添加这样一个包含Java版本的头作为值,例如"Java/1.8.0_20"
在TSAClientBouncyCastle.GetTSAResponse
中显式添加这样的头之后,例如:
/**
* Get timestamp token - communications layer
* @return - byte[] - TSA response, raw bytes (RFC 3161 encoded)
*/
protected internal virtual byte[] GetTSAResponse(byte[] requestBytes) {
HttpWebRequest con = (HttpWebRequest)WebRequest.Create(tsaURL);
// Additional User-Agent header to make http://tsa.starfieldtech.com happy
con.UserAgent = "iTextSharp";
con.ContentLength = requestBytes.Length;
con.ContentType = "application/timestamp-query";
con.Method = "POST";
时间戳服务器返回适当的时间戳响应。
由于用户代理标头是按建议指定的,但不是必需的,因此焦点中的时间戳服务器的这种行为非常可疑。
事实上,我必须首先解决一个不同的问题:我必须在这里使用HTTP代理,并且代理总是干扰返回的iTextSharp/C#时间戳请求(但同样不干扰iText/Java时间戳请求)
System.Net.WebException : The remote server returned an error: (417) Expectation Failed.
at System.Net.HttpWebRequest.GetResponse()
将HTTP协议版本限制为1.0
con.ProtocolVersion = Version.Parse("1.0");
解决了这个问题。
(@BrunoLowagie,@PauloSoares:在iTextSharp中添加用户代理标头应该没有什么坏处,但我怀疑通常将HTTP限制在1.0是个好主意。)