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

Error: The enveloped-data message does not contain the specified recipient. #784

Closed
Mehabooba opened this issue Mar 30, 2022 · 3 comments
Closed
Labels
question A question about how to do something

Comments

@Mehabooba
Copy link

Mehabooba commented Mar 30, 2022

We are trying to decrypt the signed and encrypted email using mimekit. we are able to decrypt the mail from my local machine. The same code once deployed to azure functions is throwing error 'The enveloped-data message does not contain the specified recipient.' in the decrypt function.

public MimeEntity Decrypt_509cert(ILogger log, MimeMessage message)
{
    using var WindowsSecurityMimeContext = new WindowsSecureMimeContext();

    X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    certStore.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection signCertCollection = certStore.Certificates.Find(
            X509FindType.FindByThumbprint,
            "xxxxxxxxxxx",
            false);
    X509Certificate2 signCertificate = signCertCollection[0];
    var decryptionCertPassword = "xxxxx";
    var decryptionCertBytes = signCertificate.RawData;
    using var stream = new MemoryStream(decryptionCertBytes);
	WindowsSecurityMimeContext.Import(stream, decryptionCertPassword, X509KeyStorageFlags.Exportable);
    ApplicationPkcs7Mime encryptedContent = message.Body as ApplicationPkcs7Mime;
    MimeEntity decryptedContent = encryptedContent.Decrypt(WindowsSecurityMimeContext);
    return decryptedContent;
}

We also referred to a similar issue in the link: #38

as suggested there we tried using TemporarySecureMimeContext() instead of WindowsSecureMimeContext()

using var temporarySecurityMimeContextv = new TemporarySecureMimeContext();
temporarySecurityMimeContextv.Import(streamd, decryptionCertPassword);

we get the error : BouncyCastle.Crypto: illegal object in GetInstance: Org.BouncyCastle.Asn1.DerSequence.

we also tried envelopedCms as referred in the link but we are getting the error 'asn1 bad tag value met.' in envelopedCms.Decode(data);

var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var cert = store.Certificates.Find(X509FindType.FindByThumbprint, "0F303BAD81F333C7857D9F24BD58A4EE058BFFA3", false);
var envelopedCms = new EnvelopedCms();
var messageAsBytes = new UnicodeEncoding().GetBytes(encryptedContent.ToString());
envelopedCms.Decode(messageAsBytes);
envelopedCms.Decrypt(cert); //Throws BadData exception
var decryptedBytes = envelopedCms.ContentInfo.Content;

Please see if you can provide us with the solution.
Thanks in advance

@jstedfast
Copy link
Owner

In your first case:

X509Certificate2 signCertificate = signCertCollection[0];
var decryptionCertPassword = "xxxxx";
var decryptionCertBytes = signCertificate.RawData;
using var stream = new MemoryStream(decryptionCertBytes);
WindowsSecurityMimeContext.Import(stream, decryptionCertPassword, X509KeyStorageFlags.Exportable);

That doesn't do what you think it's doing. It does NOT import the private key which is needed for verifying the signature. That ONLY imports the certificate itself.

That's why that doesn't work.

As for your second case:

var messageAsBytes = new UnicodeEncoding().GetBytes(encryptedContent.ToString());
envelopedCms.Decode(messageAsBytes);
envelopedCms.Decrypt(cert); //Throws BadData exception

Well, obviously ;-)

Assuming that the encryptedContent variable is of type ApplicationPkcs7Mime, when you call ToString() on it, it writes the full MIME part (including the MIME headers) to a stream and then converts it into a string using iso-8859-1 because no other charset can represent binary characters.

This is a problem for multiple reasons:

  1. EnvelopedCms.Decrypt() cannot handle MIME headers.
  2. A string that represents iso-8859-1 characters cannot be converted back into a byte array using the Unicode charset converter, it has to use the iso-8859-1 charset converter.
  3. EnvelopedCms.Decrypt() cannot handle MIME-encoded content which means if the Content-Transfer-Encoding of the application/pkcs7-mime part is anything other than binary, it needs to be decoded.

If you were going to decrypt manually, you'd need to get the raw encrypted content like this:

var pkcs7Mime = message.Body as ApplicationPkcs7Mime;
byte[] encryptedContent;
using (var stream = new MemoryStream ()) {
    pkcs7Mime.Content.DecodeTo (stream);
    encryptedContent = stream.ToArray ();
}

envelopedCms.Decode(encryptedContent);
envelopedCms.Decrypt(cert);

Instead of that, though, I would recommend using the MimeKit APIs. To do that, all you should have to do is to stop importing cert.RawData (because that only contains the raw certificate data and not the private key which you ALSO need).

In other words:

var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadOnly);
var cert = store.Certificates.Find(X509FindType.FindByThumbprint, "0F303BAD81F333C7857D9F24BD58A4EE058BFFA3", false);

var ctx = new TemporarySecureMimeContext ();
ctx.Import (cert);  // This will import both the certificate *and* the private key *as long as* the PrivateKey property is not null

// NOW you can decrypt:
var decrypted = pkcs7MimePart.Decrypt (ctx);

@jstedfast jstedfast added the question A question about how to do something label Mar 30, 2022
@Mehabooba
Copy link
Author

When I try to use TemporarySecureMimeContext I am getting this error.
image
If I convert to bouncy castle certificate I dont see the private key

instead of TemporarySecureMimeContext if we use WindowsSecureMimeContext, then it works in local but in azure portal it throws me error while import function as access denied.

ctx.Import(cert[0]);
Please suggest how to use private certificates with key and password in TemporarySecureMimeContext

@jstedfast
Copy link
Owner

jstedfast commented Apr 1, 2022

In the meantime, you can Export() the X509Certificate2 to pfx format and import that.

In other words, change your code to this:

public MimeEntity Decrypt_509cert(ILogger log, MimeMessage message)
{
    using var WindowsSecurityMimeContext = new WindowsSecureMimeContext();

    X509Store certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser);
    certStore.Open(OpenFlags.ReadOnly);
    X509Certificate2Collection signCertCollection = certStore.Certificates.Find(
            X509FindType.FindByThumbprint,
            "xxxxxxxxxxx",
            false);
    X509Certificate2 signCertificate = signCertCollection[0];
    var decryptionCertPassword = "xxxxx";
    var decryptionCertBytes = signCertificate.Export (X509ContentType.Pfx, decryptionCertPassword);
    using var stream = new MemoryStream(decryptionCertBytes);
	WindowsSecurityMimeContext.Import(stream, decryptionCertPassword, X509KeyStorageFlags.Exportable);
    ApplicationPkcs7Mime encryptedContent = message.Body as ApplicationPkcs7Mime;
    MimeEntity decryptedContent = encryptedContent.Decrypt(WindowsSecurityMimeContext);
    return decryptedContent;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question A question about how to do something
Projects
None yet
Development

No branches or pull requests

2 participants