How to ask for PIN/Password of Certificate from windows cert store (usb smart card) - C# NET8

37 Views Asked by At

I'm trying to sign (visible custom signature) a pdf using iText7 and BouncyCastle in c# (NET 8.0), but after an update of iText7 I had to change some obsolete functions. Now I can detect and select the certificate, but I cannot export the private key as I need the PIN/Password for the smart card, and Windows doesn't ask for this password anymore. Here is my code:

public class X509Certificate2Signature : IExternalSignature
{
    private string hashAlgorithm;
    private byte[] privateKey;
    private string encryptionAlgorithm;
    private X509Certificate2 certificate;
    private string digestAlgorithm;
    public X509Certificate2Signature(X509Certificate2 certificate, string hashAlgorithm)
    {
        
        if (!certificate.HasPrivateKey)
            throw new ArgumentException("No private key.");
        this.certificate = certificate;
       

        this.digestAlgorithm = this.hashAlgorithm = DigestAlgorithms.GetDigest(DigestAlgorithms.GetAllowedDigest(hashAlgorithm));

        //X509Certificate2UI.(certificate);

        if (certificate.GetRSAPrivateKey() is RSA)
        {
            encryptionAlgorithm = "RSA";

            RSA rSA = certificate.GetRSAPrivateKey();
            try
            {

                privateKey = rSA.ExportRSAPrivateKey();
            }
            catch
            {
                try
                {
                    privateKey = rSA.ExportPkcs8PrivateKey(); //<- here is the Problem, cannot export
                }
                catch (Exception ex)
                {
                    throw new Exception("Errore: " + ex.Message);
                }
            }
        }
        else if (certificate.GetDSAPrivateKey() is DSA)
        {
            encryptionAlgorithm = "DSA";
            privateKey = certificate.GetDSAPrivateKey().ExportPkcs8PrivateKey();
        }
        else
            throw new ArgumentException("Unknown encryption algorithm!");

    }

and this is the call:

try
{
    if (!Directory.Exists(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + System.IO.Path.DirectorySeparatorChar + "Temp"))
        Directory.CreateDirectory(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + System.IO.Path.DirectorySeparatorChar + "Temp");

    float x, y, w, h, pH, pW;
    int angle = _Deg;

    w = _W * 2.8f;
    h = _H * 2.8f;
    x = _X * 2.8f;
    y = _Y * 2.8f;

    pH = _pageH;
    pW = _pageW;





    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, true);

    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";

    List<IX509Certificate> chain = new List<IX509Certificate>();
    X509Chain x509chain = new X509Chain();
    x509chain.Build(myCert);
    
    
    foreach (X509ChainElement x509ChainElement in x509chain.ChainElements)
    {
        var certToAdd = DotNetUtilities.FromX509Certificate(x509ChainElement.Certificate);

        var toAdd = new X509CertificateBC(certToAdd);

        chain.Add(toAdd);
    }



    IX509Certificate cert = new X509CertificateBC(DotNetUtilities.FromX509Certificate(myCert));

    string subject = myCert.Subject;
    string contact = string.Empty;
    string[] fields = subject.Split(',');
    Dictionary<string, string> fieldDic = new Dictionary<string, string>();
    foreach (string s in fields)
    {
        string[] t = s.Trim().Split('=');
        if (t.Length == 2)
        {
            fieldDic.Add(t[0].Trim(), t[1].Trim());
        }
    }
    string name = fieldDic.Keys.Contains("CN") ? fieldDic["CN"] : string.Empty;

    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();

        SignatureFieldAppearance sap = new SignatureFieldAppearance("SignExample");
        signer.SetSignatureCreator("Example");
        
        signer.SetReason(!string.IsNullOrEmpty(SigReason) ? SigReason.ToUpper() : string.Empty);

        signer.SetContact(contact);
        signer.SetLocation(!string.IsNullOrEmpty(SigLocation) ? SigLocation.ToUpper() : 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.SetContent(sb.ToString());
        var assembly = typeof(PaDESSigner).GetTypeInfo().Assembly;
        byte[] imgBytes = new byte[0];
        using (Stream? resource = assembly.GetManifestResourceStream("pdf_signatureLogo.jpg"))
        {
            if (resource != null)
            {
                imgBytes = new byte[resource.Length];
                resource.Read(imgBytes, 0, (int)resource.Length);
            }
        }

        if (imgBytes.Length > 0)
        {
            iText.IO.Image.ImageData img = iText.IO.Image.ImageDataFactory.Create(imgBytes, false);
            img.SetXYRatio(0.5f);
            img.SetRotation(angle);

            iText.Layout.Properties.BackgroundImage.Builder builder = new iText.Layout.Properties.BackgroundImage.Builder();
            
            builder.SetImage(new iText.Kernel.Pdf.Xobject.PdfImageXObject(img));
            builder.SetBackgroundRepeat(new iText.Layout.Properties.BackgroundRepeat(iText.Layout.Properties.BackgroundRepeat.BackgroundRepeatValue.NO_REPEAT));
            builder.SetBackgroundBlendMode(iText.Layout.Properties.BlendMode.OVERLAY);
            
            
            
            sap.SetBackgroundImage(builder.Build());
        }
        AffineTransform af = new AffineTransform();
        af.Rotate((float)(Math.PI / 180) * angle);
        
        sap.SetFixedPosition(_page, x, y, w);

        signer.SetSignDate(now);


        signer.SetSignatureAppearance(sap);
        signer.GetDocument().GetCatalog().SetModified();

        X509Certificate2Signature externalSignature = new X509Certificate2Signature(myCert, "SHA-256");
        signer.SignDetached(externalSignature, chain.ToArray(), null, null, null, 0, PdfSigner.CryptoStandard.CMS);

        try
        {
            File.Delete(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + System.IO.Path.DirectorySeparatorChar + "Temp" + System.IO.Path.DirectorySeparatorChar + "t0.pdf");
        }
        catch { }
        try
        {
            File.Delete(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + System.IO.Path.DirectorySeparatorChar + "Temp" + System.IO.Path.DirectorySeparatorChar + "t2.pdf");
        }
        catch { }

        return true;
    }
}
catch (Exception ex)
{
    MessageBox.Show(ex.ToString());
    try
    {
        File.Delete(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + System.IO.Path.DirectorySeparatorChar + "Temp" + System.IO.Path.DirectorySeparatorChar + "t0.pdf");
    }
    catch { }
    try
    {
        File.Delete(System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + System.IO.Path.DirectorySeparatorChar + "Temp" + System.IO.Path.DirectorySeparatorChar + "t2.pdf");
    }
    catch { }
    return false;
}

How can I ask for the pin in secure mode and export/use the certificate private key?

0

There are 0 best solutions below