Hello,
I would like to sign pdf with timestamp using windows certificate from certificate store (x509certificate2).
When I sign with pfx certificate I use this code and it works fine:
private static void SignWithTimeStamp()
{
string IN_FILE = "doc.pdf";
string OUT_FILE = "hello_signed_cs.pdf";
string CERT_PATH = "cert.pfx";
string CERT_PASSW= "password";
FileStream fs = new FileStream(CERT_PATH, FileMode.Open);
Pkcs12Store ks = new Pkcs12Store(fs, CERT_PASSW.ToCharArray());
string alias = null;
foreach (string al in ks.Aliases)
{
if (ks.IsKeyEntry(al) && ks.GetKey(al).Key.IsPrivate)
{
alias = al;
break;
}
}
fs.Close();
ICipherParameters pk = ks.GetKey(alias).Key;
X509CertificateEntry[] x = ks.GetCertificateChain(alias);
X509Certificate[] chain = new X509Certificate[x.Length];
for (int k = 0; k < x.Length; ++k)
{
chain[k] = x[k].Certificate;
}
ITSAClient tsc = new TSAClientBouncyCastle(TSA_URL, TSA_ACCNT, TSA_PASSW);
PdfReader reader = new PdfReader(IN_FILE);
FileStream fout = new FileStream(OUT_FILE, FileMode.Create);
PdfStamper stp = PdfStamper.CreateSignature(reader, fout, '\0');
PdfSignatureAppearance sap = stp.SignatureAppearance;
sap.SetCrypto(null, chain, null, PdfSignatureAppearance.SELF_SIGNED);
sap.SetVisibleSignature(new Rectangle(100, 100, 300, 200), 1, "Signature");
PdfSignature dic = new PdfSignature(PdfName.ADOBE_PPKLITE,
new PdfName("adbe.pkcs7.detached"));
dic.Reason = sap.Reason;
dic.Location = sap.Location;
dic.Contact = sap.Contact;
dic.Date = new PdfDate(sap.SignDate);
sap.CryptoDictionary = dic;
int contentEstimated = 15000;
// Preallocate excluded byte-range for the signature content (hex encoded)
Hashtable exc = new Hashtable();
exc[PdfName.CONTENTS] = contentEstimated * 2 + 2;
sap.PreClose(exc);
PdfPKCS7 sgn = new PdfPKCS7(pk, chain, null, "SHA1", false);
IDigest messageDigest = DigestUtilities.GetDigest("SHA1");
Stream data = sap.RangeStream;
byte[] buf = new byte[8192];
int n;
while ((n = data.Read(buf, 0, buf.Length)) > 0)
{
messageDigest.BlockUpdate(buf, 0, n);
}
byte[] hash = new byte[messageDigest.GetDigestSize()];
messageDigest.DoFinal(hash, 0);
DateTime cal = DateTime.Now;
byte[] ocsp = null;
if (chain.Length >= 2)
{
String url = PdfPKCS7.GetOCSPURL(chain[0]);
if (url != null && url.Length > 0)
ocsp = new OcspClientBouncyCastle(chain[0], chain[1], url).GetEncoded();
}
byte[] sh = sgn.GetAuthenticatedAttributeBytes(hash, cal, ocsp);
sgn.Update(sh, 0, sh.Length);
//HERE get timestamp
byte[] encodedSig = sgn.GetEncodedPKCS7(hash, cal, tsc, ocsp);
if (contentEstimated + 2 < encodedSig.Length)
throw new Exception("Not enough space");
byte[] paddedSig = new byte[contentEstimated];
Array.Copy(encodedSig, 0, paddedSig, 0, encodedSig.Length);
PdfDictionary dic2 = new PdfDictionary();
dic2.Put(PdfName.CONTENTS, new PdfString(paddedSig).SetHexWriting(true));
sap.Close(dic2);
}
This code work fine. But when I use X509Certificate2 from certificate store I can't convert its private key to ICipherParameters.
Is it possible? Can I use X509Certificate2 for signing with timestamp?
I get certificate and certificate chain with:
//get certificate from certificate store, this certificate has exportable private key
X509Certificate2 certificate = GetCertificate();
X509CertificateParser cp = new X509CertificateParser();
X509Certificate[] chain = new[] { cp.ReadCertificate(certificate.RawData) };
Thank you for info.