AltF4Uninstall
AltF4Uninstall

Reputation: 302

Key not valid for use in specified state CryptographicException with BouncyCastle

Been searching the web and blogs and finding scraps here and there, and trying to put them all together to be able to use System.Security.Cryptography.X509Certificates to digitally sign a PDF file with iTextSharp library.

I have a sign button with the following code behind it:

    Dim m As New PdfManipulation
    Dim store As New X509Store("MY", StoreLocation.CurrentUser)
    store.Open(OpenFlags.ReadOnly Or OpenFlags.OpenExistingOnly)

    Dim collection As X509Certificate2Collection = CType(store.Certificates, X509Certificate2Collection)
    Dim fcollection As X509Certificate2Collection = CType(collection.Find(X509FindType.FindByTimeValid, DateTime.Now, False), X509Certificate2Collection)
    Dim scollection As X509Certificate2Collection = X509Certificate2UI.SelectFromCollection(fcollection, "Test Certificate Select", "Select a certificate from the following list to get information on that certificate", X509SelectionFlag.SingleSelection)

    For Each x509 As X509Certificate2 In scollection
        m.DigitallySignPdf("C:\Users\my\Desktop\populates.pdf", "C:\Users\my\Desktop\A.pdf", "topmostSubform[0].Page1[0].SignatureField1[0]", x509)
    Next x509

    store.Close()

The above code works, it opens up my cert store and I choose a certificate. It then passes the certificate to the following PdfManiuplation class for signing.

PdfManipulation Code:

Public Class PdfManipulation

Public Sub DigitallySignPdf(ByVal sourceDocument As String, _
                            ByVal destinationPath As String, _
                            ByVal fieldNameToSign As String, _
                            ByVal signature As X509Certificate2)

    Dim reader As New PdfReader(sourceDocument)
    Using fout As New FileStream(destinationPath, FileMode.Create, FileAccess.ReadWrite)
        Using stamper As PdfStamper = PdfStamper.CreateSignature(reader, fout, ControlChars.NullChar)
            ' appearance
            Dim appearance As PdfSignatureAppearance = stamper.SignatureAppearance
            appearance.SetVisibleSignature(fieldNameToSign)

            ' digital signature
            Dim akp = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(signature.PrivateKey).Private
            Dim es As IExternalSignature = New PrivateKeySignature(akp, "SHA-256")
            Dim cp As New Org.BouncyCastle.X509.X509CertificateParser()


            MakeSignature.SignDetached(appearance, es, New Org.BouncyCastle.X509.X509Certificate() {cp.ReadCertificate(signature.RawData)}, Nothing, Nothing, Nothing, 0, CryptoStandard.CMS)

            stamper.Close()

        End Using
    End Using

End Sub

End Class

When it gets to

Dim akp = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(signature.PrivateKey).Private

thats when the Exception is thrown. The certificate I choose is the same certificate I sign everything with on my machine, so I know it's good. Any help as to why this would be throwing this error would be greatly appreciated, or a pointer in the right direction.

Also here is my list of Imports:

Imports System.Security.Cryptography
Imports System.Security.Permissions
Imports System.IO
Imports System.Security.Cryptography.X509Certificates
Imports iTextSharp.text.pdf.security
Imports iTextSharp.text
Imports iTextSharp.text.pdf

And have to add a reference to:

System.Security

StackTrace:

    System.Security.Cryptography.CryptographicException was unhandled
  HResult=-2146893813
  Message=Key not valid for use in specified state.

  Source=mscorlib
  StackTrace:
       at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
       at System.Security.Cryptography.Utils._ExportKey(SafeKeyHandle hKey, Int32 blobType, Object cspObject)
       at System.Security.Cryptography.RSACryptoServiceProvider.ExportParameters(Boolean includePrivateParameters)
       at Org.BouncyCastle.Security.DotNetUtilities.GetRsaKeyPair(RSA rsa)
       at Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(AsymmetricAlgorithm privateKey)
       at AccessRequest.PdfManipulation.DigitallySignPdf(String sourceDocument, String destinationPath, String fieldNameToSign, X509Certificate2 signature) in C:\PdfManipulation.vb:line 237
       at Form.btnSubmit_Click(Object sender, EventArgs e) in C:\Form.vb:line 251
       at System.Windows.Forms.Control.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnClick(EventArgs e)
       at System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ButtonBase.WndProc(Message& m)
       at System.Windows.Forms.Button.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(ApplicationContext context)
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       at app.My.MyApplication.Main(String[] Args) in 11111.vb:line 81
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

Also after further testing and looking at the Private key through the IDE, I did notice

signature.privatekey.CspKeyContainerInfo.Exportable = False

would this possibly be the cause of the error and if so, how do make a selected certificate exportable? As the only thing I have seen through searching is actually creating a new certificate and setting the StorageFlag to Exportable and I am not trying to create a new certificate. I am just trying to use the selected certificate.

Upvotes: 3

Views: 6265

Answers (2)

Simon
Simon

Reputation: 2066

You are right pointing out about the certificate not being exportable

So change:

Dim akp = Org.BouncyCastle.Security.DotNetUtilities.GetKeyPair(signature.PrivateKey).Private

Dim es As IExternalSignature = New PrivateKeySignature(akp, "SHA-256")

to just:

Dim es As IExternalSignature = New security.X509Certificate2Signature(signature, "SHA-256")

Upvotes: 0

AltF4Uninstall
AltF4Uninstall

Reputation: 302

The error was being caused by the fact that Private Certificate was NOT exportable.

I had been wondering through all my testing why I was not being prompted even once for my smart card pin for the certificate I was choosing. Which lead me to finally selecting one of my certificates that I know would not ask for pin, and viola, the pdf exported and was signed. Even stepped through the code to view the certificate privatekey property and this time it read

signature.privatekey.CspKeyContainerInfo.Exportable = True

Which finally matched another form i discovered, that stated they fixed their error by making the private key exportable. Now all I have to do is figure out how to make this work with certificates that should be asking me for my pin. If i ever discover that problem I will post back here.

Upvotes: 4

Related Questions