Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot decrypt without adding certificate to personal store #38

Closed
CThuleHansen opened this issue Mar 12, 2014 · 6 comments
Closed

Cannot decrypt without adding certificate to personal store #38

CThuleHansen opened this issue Mar 12, 2014 · 6 comments
Labels
enhancement New feature or request

Comments

@CThuleHansen
Copy link

Hi.

When I attempt to decrypt an email using the WindowsSecureMimeContext it throws the exception:

System.Security.Cryptography.CryptographicException: The enveloped-data message does not contain the specified recipient.

   at System.Security.Cryptography.Pkcs.EnvelopedCms.DecryptContent(RecipientInfoCollection recipientInfos, X509Certificate2Collection extraStore)
   at System.Security.Cryptography.Pkcs.EnvelopedCms.Decrypt()
   at MimeKit.Cryptography.WindowsSecureMimeContext.Decrypt(Stream encryptedData)
   at MimeKit.Cryptography.ApplicationPkcs7Mime.Decrypt(SecureMimeContext ctx)
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.HandleEncryptedMail(ApplicationPkcs7Mime entity) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 179
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.EmailDistributer(MimeEntity entity) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 90
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.ParseMimeContent(Byte[] content) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 78
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.HandleNewMail(IBelVisEmailMessage belVisEmailMessage) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 45}

Which basically means, that it cannot find the certificate to use.
However I have imported the certificate:

var secureMimeContext = new WindowsSecureMimeContext();
var certificate = new X509Certificate2(certificateFilename,
                                                   certificatePassword);
var stream = new MemoryStream(certificate.GetRawCertData());
secureMimeContext.Import(stream, certificatePassword);
return secureMimeContext;

And a different way of importing:

var secureMimeContext = new WindowsSecureMimeContext();
var certificate = new X509Certificate2(certificateFilename,
                                                   certificatePassword);
var bouncyX509Certificate = Org.BouncyCastle.Security.DotNetUtilities.FromX509Certificate(certificate);
                secureMimeContext.Import(bouncyX509Certificate);

return secureMimeContext;

However none of them works.

I have tried to decrypt myself, which works great.
I load the certificate like this:

var certificateCollection = new X509Certificate2Collection(certificate);
var envelopedCms = new EnvelopedCms();
envelopedCms.Decode(data);
envelopedCms.Decrypt(certificateCollection);
return envelopedCms.ContentInfo.Content;

So I believe it is an issue, that it is so dependent on the certificate store.
Can you provide a fix or an idea on how to circumvent this issue?

@CThuleHansen
Copy link
Author

This is the same issue reported in http://stackoverflow.com/questions/22324124/mimekit-causing-bad-data-when-decrypting-an-email however it is probably also good to have it here :)

When I try to build your project myself, then the bouncy castle project cannot load in visual studio 2012.
Any help on this?

@jstedfast
Copy link
Owner

Are you using the visual-studio-2010 branch of bc-csharp? The default (master) branch is in vs2003 format.

I've updated my stackoverflow answer with the correct way to import the certificate + the private key (your implementations above are only importing the certificate and not the private key).

For convenience, I'll post the proper way to import the certificate + private key here as well:

private SecureMimeContext CreateSecureMimeContext (string certificateFilename, string certificatePassword)
{
    var secureMimeContext = new WindowsSecureMimeContext ();

    using (var stream = File.OpenRead (certificateFilename))
        secureMimeContext.Import (stream, certificatePassword);

    return secureMimeContext;
}

It's a common confusion for many people, but X509Certificate2 does not include a private key, it only references a private key, so if you use certificate.RawData or certificate.GetRawData() and parse the result, you lose the reference to the private key, which is why your implementations did not work.

I'll add an in-memory-only SecureMimeContext to MimeKit for the next release, but I'm curious why you do not want to import the certificates/keys into the user's certificate store?

(I'm not saying that you are wrong to not want to do that, I'm just curious so I can better understand use-cases that I did not originally plan for).

jstedfast added a commit that referenced this issue Mar 12, 2014
@CThuleHansen
Copy link
Author

Hi. Even though I import it like you show above, I still get the same exception:

{System.Security.Cryptography.CryptographicException: The enveloped-data message does not contain the specified recipient.

   at System.Security.Cryptography.Pkcs.EnvelopedCms.DecryptContent(RecipientInfoCollection recipientInfos, X509Certificate2Collection extraStore)
   at System.Security.Cryptography.Pkcs.EnvelopedCms.Decrypt()
   at MimeKit.Cryptography.WindowsSecureMimeContext.Decrypt(Stream encryptedData)
   at MimeKit.Cryptography.ApplicationPkcs7Mime.Decrypt(SecureMimeContext ctx)
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.HandleEncryptedMail(ApplicationPkcs7Mime entity) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 179
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.EmailDistributer(MimeEntity entity) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 90
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.ParseMimeContent(Byte[] content) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 78
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.HandleNewMail(IBelVisEmailMessage belVisEmailMessage) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 45}

Was this because there was an error in CreateSecureMimeContext?
Or is it because I manually have to import the certificate into my personal store?

I will explain my scenario of use later on :)

@jstedfast
Copy link
Owner

What happens if you use the DummySecureMimeContext instead of the WindowsSecureMimeContext?

@CThuleHansen
Copy link
Author

Wohoo! The DummySecureMimeContext works! Thought I had checked that..

Thank you very much for all your help jstedfast. I will mark your answer as correct on SO as well.

The reason why I would like to keep certificates in memory:
I have many certificates based on my root. Apparently the windows certificate store does not like this.
So when I have 5 different subcertificates based on the same root, only 1 works.
I just tested with this scenario, where I used the windowssecuremimecontext
1: Import cert1.pfx into personal store.
2: Import cert2.pfx into personal store.
3: Attempt to decrypt mail requiring cert1.pfx using WindowsSecureMimeContext
3.1: IT WORKED!
4: Attempt to decrypt mail requiring cert2.pfx using WindowsSecureMimeContext
4.1: Got the exception:

{System.Security.Cryptography.CryptographicException: Not enough storage is available to process this command.

   at System.Security.Cryptography.Pkcs.EnvelopedCms.DecryptContent(RecipientInfoCollection recipientInfos, X509Certificate2Collection extraStore)
   at System.Security.Cryptography.Pkcs.EnvelopedCms.Decrypt()
   at MimeKit.Cryptography.WindowsSecureMimeContext.Decrypt(Stream encryptedData)
   at MimeKit.Cryptography.ApplicationPkcs7Mime.Decrypt(SecureMimeContext ctx)
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.HandleEncryptedMail(ApplicationPkcs7Mime entity) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 179
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.EmailDistributer(MimeEntity entity) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 90
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.ParseMimeContent(Byte[] content) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 78
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.HandleNewMail(IBelVisEmailMessage belVisEmailMessage) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 45}

4.3: Sometimes I got this exception instead:

{Org.BouncyCastle.Cms.CmsException: illegal blocksize in message. ---> Org.BouncyCastle.Crypto.DataLengthException: input too large for RSA cipher.
   at Org.BouncyCastle.Crypto.Engines.RsaCoreEngine.ConvertInput(Byte[] inBuf, Int32 inOff, Int32 inLen)
   at Org.BouncyCastle.Crypto.Engines.RsaBlindedEngine.ProcessBlock(Byte[] inBuf, Int32 inOff, Int32 inLen)
   at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.DecodeBlock(Byte[] input, Int32 inOff, Int32 inLen)
   at Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.ProcessBlock(Byte[] input, Int32 inOff, Int32 length)
   at Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.DoFinal()
   at Org.BouncyCastle.Crypto.BufferedAsymmetricBlockCipher.DoFinal(Byte[] input, Int32 inOff, Int32 length)
   at Org.BouncyCastle.Security.WrapperUtilities.BufferedCipherWrapper.Unwrap(Byte[] input, Int32 inOff, Int32 length)
   at Org.BouncyCastle.Cms.KeyTransRecipientInformation.UnwrapKey(ICipherParameters key)
   --- End of inner exception stack trace ---
   at Org.BouncyCastle.Cms.KeyTransRecipientInformation.UnwrapKey(ICipherParameters key)
   at Org.BouncyCastle.Cms.KeyTransRecipientInformation.GetContentStream(ICipherParameters key)
   at Org.BouncyCastle.Cms.RecipientInformation.GetContent(ICipherParameters key)
   at MimeKit.Cryptography.SecureMimeContext.Decrypt(Stream encryptedData)
   at MimeKit.Cryptography.ApplicationPkcs7Mime.Decrypt(SecureMimeContext ctx)
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.HandleEncryptedMail(ApplicationPkcs7Mime entity) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 179}

5: Attempt to decrypt mail requiring cert1.pfx using DefaultSecureMimeContext
5.1: WOHOO IT WORKS!
6: Attempt to decrypt mail requiring cert2.pfx using DefaultSecureMimeContext
6.1: Failed with the exception:

{System.Security.Cryptography.CryptographicException: Not enough storage is available to process this command.

   at System.Security.Cryptography.Pkcs.EnvelopedCms.DecryptContent(RecipientInfoCollection recipientInfos, X509Certificate2Collection extraStore)
   at System.Security.Cryptography.Pkcs.EnvelopedCms.Decrypt()
   at MimeKit.Cryptography.WindowsSecureMimeContext.Decrypt(Stream encryptedData)
   at MimeKit.Cryptography.ApplicationPkcs7Mime.Decrypt(SecureMimeContext ctx)
   at DC.Communications.Counterparties.BelVis.MailRecv.MailHandlers.BelVisMailHandler.HandleEncryptedMail(ApplicationPkcs7Mime entity) in c:\source\projects\DC.BelVis\trunk\DC.Communications.Counterparties.BelVis\DC.Communications.Counterparties.BelVis.MailRecv\MailHandlers\BelVisMailHandler.cs:line 179}
  1. Testing both cases with DummySecureMimeContext - both works.

I have checked my certmgr.msc - personal store, and both certificates are there.
It is not your library that fails, it is something within MS libraries. Outlook has the same issue, I can only decrypt emails using cert1.pfx but not cert2.pfx.
These issues does not appear, when I use the certificates in memory.
I do not generate the certificates myself, perhaps it is an issue in the certificates, but none the less, it works with in-memory certificates.

I also switch servers a lot, and it is easier to simply keep them in a file

@jstedfast
Copy link
Owner

Cool, glad that the DummySecureMimeContext works for you.

I've added DummySecureMimeContext to the main MimeKit module and renamed it to TemporarySecureMimeContext (hopefully this is a better name, I didn't like Dummy).

Thanks for explaining about the errors you get when you have multiple certificates with the same root. I never would have guessed that problem.

I've just released a MimeKit 0.28 nuget package which contains the TemorarySecureMimeContext.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants