title: Sign PDF with Smartcard PKS11 through Windows Certificate Store
body: <p>My project consists in signing a PDF file using PKS11 (usb smartcard).</p>
  
  <p>What I need is:</p>
  
  <p>1) Plug in the USB smart card (and let the OS load the certificate in CurrentUser store (Windows))</p>
  
  <p>2) Call an application , no GUI needed, that sign a determined PDF with the loaded cert.</p>
  
  <p>Step 2 would need the user to input the PIN of the smartcard. For now that is not a concern, I can statically set it for testing purposes.</p>
  
  <p>The posts I have been reading are:</p>
  
  <p><a href="https://stackoverflow.com/questions/48411453/checking-for-the-accessibility-of-smart-card-private-keys-in-windows-10" title="Post1">checking-for-the-accessibility-of-smart-card-private-keys-in-windows-10</a></p>
  
  <p><a href="https://stackoverflow.com/questions/22236116/find-certificate-on-smartcard-currently-on-reader">find-certificate-on-smartcard-currently-on-reader</a></p>
  
  <p><a href="https://stackoverflow.com/questions/23152330/load-a-smart-card-or-other-private-certificate-in-cryptoserviceprovider-for-sign">load-a-smart-card-or-other-private-certificate-in-cryptoserviceprovider-for-sign</a></p>
  
  <p><a href="https://stackoverflow.com/questions/14997118/how-do-i-sign-a-pdf-document-using-a-certificate-from-the-windows-cert-store">how-do-i-sign-a-pdf-document-using-a-certificate-from-the-windows-cert-store</a></p>
  
  <p><a href="https://stackoverflow.com/questions/13204940/sign-pdf-with-itextsharp-5-3-3-and-usb-token">sign-pdf-with-itextsharp-5-3-3-and-usb-token</a></p>
  
  <pre><code>// Set up the PDF IO
  PdfReader reader = new PdfReader(@"C:\Users\martin\Documents\tosign.pdf");
  PdfStamper stamper = PdfStamper.CreateSignature(reader,
  new FileStream(@"C:\Users\martin\Documents\SignedPdf.pdf", FileMode.Create), 
  '\0');
  PdfSignatureAppearance sap = stamper.SignatureAppearance;
  sap.Reason = "For no apparent reason";
  sap.Location = "Place";
  
  var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
  certStore.Open(OpenFlags.ReadOnly);
  
  X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
  store.Open(OpenFlags.ReadOnly);
  
  X509Certificate2Collection collection = (X509Certificate2Collection)store.Certificates;
  X509Certificate2Collection fcollection = (X509Certificate2Collection)collection.Find(X509FindType.FindByTimeValid, DateTime.Now, false);
  X509Certificate2 cert = fcollection[0];
  
  
  
  BcX509.X509CertificateParser cp = new BcX509.X509CertificateParser();
  Org.BouncyCastle.X509.X509Certificate[] chain = new Org.BouncyCastle.X509.X509Certificate[] {
      cp.ReadCertificate(cert.RawData)
  };
  Console.WriteLine(cert);
  
  X509Certificate2 signatureCert = new X509Certificate2(cert);
  IExternalSignature externalSignature = new X509Certificate2Signature(cert, "SHA-1");
  
  MakeSignature.SignDetached(sap, externalSignature, chain, null, null, null, 0, CryptoStandard.CMS);
  </code></pre>
  
  <p>I get a runtime error </p>
  
  <blockquote>
    <p>System.ArgumentException: 'Unknown encryption algorithm
    System.Security.Cryptography.RSACng'</p>
  </blockquote>
  
  <p>in the line</p>
  
  <pre><code>IExternalSignature externalSignature = new X509Certificate2Signature(cert, "SHA-1");
  </code></pre>
  
  <p>I read somewhere that externalSignature is to be implemented with custom code depending on the USB vendor. Though in all the posts mentioned here, it seems that line should work with no problems. I tried to change the algorithm to SHA-256. Also I have been digging Github code of IExternalSignature interface to try to get a grasp out of it.</p>
  
  <p>In theory, I know the private key of the USB device will never be accessible, therefore I can not just try to sign with a "getprivatekey" method kind.</p>
  
  <p>In practice, I am a MEAN stack and Python dev, I have never coded in C#.</p>