I'm trying to set a visible signature on a PDF file with iText7 and BouncyCastle in C#, using a certificate stored on a smartcard.
All goes well since I have to create the IExternalSignature
object to use in the SignDetached()
function of the PdfSigner. At this point I cannot handle to request the PIN code of the Smart Card, so I cannot get the PrivateKey and the signing process fails. How can I do that?
Here is a portion of my code:
X509Store st = new X509Store(StoreName.My, StoreLocation.CurrentUser);
st.Open(OpenFlags.ReadOnly);
X509Certificate2Collection col = st.Certificates;
X509Certificate2 myCert = null;
X509Certificate2Collection finder = col.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
X509Certificate2Collection final = new X509Certificate2Collection();
byte[] firma = new byte[] { 3, 2, 6, 64 };
foreach (X509Certificate2 xcert in finder)
{
byte[] attrs = GetExtensionValue(xcert, "2.5.29.15");
if (attrs != null)
{
bool add = false;
if (attrs.Length == firma.Length)
{
for (int i = 0; i < attrs.Length; i++)
{
if (attrs[i] == firma[i])
{
add = true;
}
else
{
add = false;
break;
}
}
}
if (add)
final.Add(xcert);
}
}
X509Certificate2Collection sel = X509Certificate2UI.SelectFromCollection(final, "Certificati", "Seleziona il Certificato per Firmare il Documento", X509SelectionFlag.SingleSelection);
if (sel.Count > 0)
{
X509Certificate2Enumerator en = sel.GetEnumerator();
en.MoveNext();
myCert = en.Current;
}
st.Close();
DateTime now = DateTime.Now;
string tmp = System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + System.IO.Path.DirectorySeparatorChar + "Temp" + System.IO.Path.DirectorySeparatorChar + "t0.pdf";
IList<Org.BouncyCastle.X509.X509Certificate> chain = new List<Org.BouncyCastle.X509.X509Certificate>();
X509Chain x509chain = new X509Chain();
x509chain.Build(myCert);
foreach (X509ChainElement x509ChainElement in x509chain.ChainElements)
{
chain.Add(DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate));
}
Org.BouncyCastle.X509.X509Certificate cert = DotNetUtilities.FromX509Certificate(myCert);
string contact = string.Empty;
string name = cert.SubjectDN.GetValueList()[1].ToString();
PdfReader reader = new PdfReader(inputPDF);
using (FileStream os = new FileStream(outputPDF, FileMode.Create))
{
PdfSigner signer = new PdfSigner(reader, os, new StampingProperties());
StampingProperties properties = new StampingProperties();
PdfSignatureAppearance sap = signer.GetSignatureAppearance();
sap.SetSignatureCreator("MyProgramSigner");
sap.SetRenderingMode(PdfSignatureAppearance.RenderingMode.GRAPHIC_AND_DESCRIPTION);
sap.SetReason(!string.IsNullOrEmpty(SigReason) ? SigReason.ToUpper() : string.Empty);
sap.SetContact(contact);
sap.SetLocation(string.IsNullOrEmpty(SigLocation) ? SigLocation.ToUpper() : string.Empty);
sap.SetReasonCaption(string.Empty);
sap.SetLocationCaption(string.Empty);
StringBuilder sb = new StringBuilder();
sb.Append("Documento firmato digitalmente da " + name.ToUpper() + " " + now.ToString("dddd dd/MM/yyyy") + " alle " + now.ToString("HH:mm:ss"));
if (!string.IsNullOrEmpty(SigLocation) || !string.IsNullOrEmpty(SigReason))
sb.AppendLine();
if (!string.IsNullOrEmpty(SigReason))
sb.Append("Motivo della firma: " + SigReason.ToUpper());
if (!string.IsNullOrEmpty(SigLocation) && !string.IsNullOrEmpty(SigReason))
sb.Append("; ");
if (!string.IsNullOrEmpty(SigLocation))
sb.Append("Luogo Firma: " + SigLocation.ToUpper());
sap.SetLayer2Text(sb.ToString());
iText.IO.Image.ImageData img = iText.IO.Image.ImageDataFactory.Create(Properties.Resources.pdf_signatureLogo, null, false);
sap.SetImage(img);
sap.SetImageScale(.5f);
AffineTransform af = new AffineTransform();
af.Rotate((float)(Math.PI / 180) * angle);
Rectangle rect = new Rectangle(x, y, w, h);
sap.SetPageRect(rect);
sap.SetPageNumber(_page);
signer.SetSignDate(now);
sap.SetSignatureGraphic(sap.GetImage());
sap.SetCertificate(cert);
signer.GetDocument().GetCatalog().SetModified();
IExternalSignature pks = new PrivateKeySignature(pk, DigestAlgorithms.SHA256); // what is pk? I don't know, tried many things, but none worked...
signer.SignDetached(pks, chain.ToArray(), null, null, null, 0, PdfSigner.CryptoStandard.CMS);
return true;
}