I have a problem during timestamping PDF file with Itextsharp and MakeSignature.SignDetached method.
- My certs are stored on a Luna HSM.
- itextsharp ver:5.5.11
- PkcsInterop.PDF ver: 1.3.0
Without timestamp, belowed code is working perfectly. When i want to sign with timestamp an exception is thrown :
The remote server returned an error: (504) Gateway Timeout.
And Fiddler gives me that response header :
HTTP/1.1 504 Fiddler - Receive Failure Date: Mon, 30 Apr 2018 11:28:57 GMT Content-Type: text/html; charset=UTF-8 Connection: close Cache-Control: no-cache, must-revalidate Timestamp: 14:28:57.430 [Fiddler] ReadResponse() failed: The server did not return a complete response for this request. Server returned 0 bytes.
public void SignPDF(byte[] pdf, SignData signData) //signData: my custom class, it's about sign image,location,size
{
string timeStampServer = "http://xxxxxxxx";
string timeStampUser = "xxxx";
string timeStampPass = "xxxx";
string cryptokiDLL = @"C:\Program Files\SafeNet\LunaClient\cryptoki.dll";
string tokenLabel = "xxx";
string pin = "xxxx";
string primaryKeyLabel = "xxxxx";
string certsDir = @"C:\CERTs";
iTextSharp.text.Image signImg = null;
iTextSharp.text.Rectangle signRec = null;
byte[] signedPDF = null;
string hash = null;
try
{
HashAlgorithm hashAlgorithm = HashAlgorithm.SHA256;
Pkcs11RsaSignature pkcs11RsaSignature = new Pkcs11RsaSignature(cryptokiDLL, null, tokenLabel, pin, primaryKeyLabel, null, hashAlgorithm);
byte[] signingCertificate = pkcs11RsaSignature.GetSigningCertificate();//1460
List<byte[]> otherCertificates = new List<byte[]>();
foreach (string file in Directory.GetFiles(certsDir))
otherCertificates.Add(File.ReadAllBytes(file));
var chain = CertUtils.BuildCertPath(signingCertificate, otherCertificates).ToList();
ITSAClient tsaClient = new TSAClientBouncyCastle(timeStampServer, timeStampUser, timeStampPass);
IOcspClient ocspClient = new OcspClientBouncyCastle();
List<ICrlClient> crlList = new List<ICrlClient>();
crlList.Add(new CrlClientOnline(chain));
using (PdfReader pdfReader = new PdfReader(pdf))
{
using (MemoryStream msPDFfinal = new MemoryStream())
{
using (PdfStamper pdfStamper = PdfStamper.CreateSignature(pdfReader, msPDFfinal, '\0'))
{
PdfWriter writer = pdfStamper.Writer;
PdfSignatureAppearance appearance = pdfStamper.SignatureAppearance;
byte[] signImgBinary = signData.ImzaBinary;
int x = signData.X;
int y = signData.Y;
int scale = signData.Scale;
int pageNum = signData.PageNum;
signImg = iTextSharp.text.Image.GetInstance(signImgBinary);
signImg.ScalePercent(scale);
float imgX = (float)x;
float imgY = (float)y;
float scaledW = signImg.ScaledWidth;
float scaledH = signImg.ScaledHeight;
signRec = new iTextSharp.text.Rectangle(imgX, imgY, imgX + scaledW, imgY + scaledH);
appearance.Layer2Text = " ";
appearance.Image = signImg;
appearance.SetVisibleSignature(signRec, pageNum, "SIG");
//without timestamp, it is signing the pdf. Everything is ok.
//MakeSignature.SignDetached(appearance, pkcs11RsaSignature, chain, null, null, null, 0, CryptoStandard.CADES);
//it returns 504 error, no server response
MakeSignature.SignDetached(appearance, pkcs11RsaSignature, chain, crlList, ocspClient, tsaClient, 0, CryptoStandard.CADES);
}
signedPDF = msPDFfinal.ToArray();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
and finally, according to this link what is wrong with godaddy's timestamp server and itextsharp? i have added user-agent and http protocol headers but nothing is changed, still getting error.
protected internal virtual byte[] GetTSAResponse(byte[] requestBytes) {
HttpWebRequest con = (HttpWebRequest)WebRequest.Create(tsaURL);
con.UserAgent = "itextsharp";
con.ProtocolVersion = HttpVersion.Version10;
con.ContentLength = requestBytes.Length;
con.ContentType = "application/timestamp-query";
con.Method = "POST";
con.KeepAlive = true;
if ((tsaUsername != null) && !tsaUsername.Equals("") ) {
string authInfo = tsaUsername + ":" + tsaPassword;
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo), Base64FormattingOptions.None);
con.Headers["Authorization"] = "Basic " + authInfo;
}
Stream outp = con.GetRequestStream();
outp.Write(requestBytes, 0, requestBytes.Length);
outp.Close();