jstedfast / MimeKit

A .NET MIME creation and parser library with support for S/MIME, PGP, DKIM, TNEF and Unix mbox spools.
http://www.mimekit.net
MIT License
1.81k stars 368 forks source link

System.FormatException: Failed to parse entity headers #836

Closed blutswende closed 1 year ago

blutswende commented 1 year ago

Describe the bug Hi. in the last few weeks I had some error when i want to check that the Content-Disposition header has the value attachment, with the MimeEntity.IsAttachment property.

There is a pdf inside a signed mail but that pdf did not have the header attachment.

Platform (please complete the following information):

Error

System.FormatException: Failed to parse entity headers.
   at MimeKit.MimeParser.ParseEntity(Byte* inbuf, CancellationToken cancellationToken) in D:\src\MimeKit\MimeKit\MimeParser.cs:line 1767
   at MimeKit.MimeParser.ParseEntity(CancellationToken cancellationToken) in D:\src\MimeKit\MimeKit\MimeParser.cs:line 1821
   at MimeKit.MimeEntity.Load(ParserOptions options, Stream stream, Boolean persistent, CancellationToken cancellationToken) in D:\src\MimeKit\MimeKit\MimeEntity.cs:line 1359
   at MimeKit.MimeEntity.Load(Stream stream, CancellationToken cancellationToken) in 

Expected behavior return true or false

Code Snippets If applicable, add code snippets to help explain your problem.


                                    // Load attachment into the stream
                                    MemoryStream ms = new MemoryStream(fileAtt.ContentBytes);

                                    // Create an MimeEntity object 
                                    var signedMessage = MimeEntity.Load(ms);

                                    if (signedMessage is MultipartSigned)
                                    {
                                        var multipart = signedMessage as Multipart;
                                        var attachments = multipart[0];

                                        if (attachments is Multipart)
                                        {
                                            var multipartAttachments = attachments as Multipart;

                                            foreach (var mAttachment in multipartAttachments)
                                            {
                                                if (mAttachment.IsAttachment)
                                                {
                                                    if (mAttachment is MessagePart)
                                                    {
                                                        var fileName = mAttachment.ContentDisposition?.FileName;
                                                        if (!string.IsNullOrEmpty(fileName))
                                                        {
                                                            var attachmentPart = (MessagePart)mAttachment;

                                                            var unsignedAttachment = new ImesDocumentAttachment(false, false, false);
                                                            unsignedAttachment.Name = fileName.RemoveInvalidChars();
                                                            unsignedAttachment.ContentType = mAttachment.ContentType.ToString();
                                                            unsignedAttachment.Content = new MemoryStream();

                                                            attachmentPart.WriteTo(unsignedAttachment.Content);
                                                            result.Add(unsignedAttachment);
                                                            Logger.Trace($"{Settings.MailAccount.name} - {message.Id.GetHashCode()} - Successfully added unsigned {unsignedAttachment.Name} to Attachments");
                                                        }
                                                    }
                                                    else
                                                    {
                                                        var part = (MimePart)mAttachment;
                                                        var fileName = part.FileName;

                                                        var unsignedAttachment = new ImesDocumentAttachment(false, false, false);
                                                        unsignedAttachment.Name = fileName.RemoveInvalidChars();
                                                        unsignedAttachment.ContentType = mAttachment.ContentType.ToString();
                                                        unsignedAttachment.Content = new MemoryStream();

                                                        part.Content.DecodeTo(unsignedAttachment.Content);

                                                        result.Add(unsignedAttachment);
                                                        Logger.Trace($"{Settings.MailAccount.name} - {message.Id.GetHashCode()} - Successfully added unsigned {unsignedAttachment.Name} to Attachments");
                                                    }
                                                }
                                            }
                                        }
                                    }

Additional context We are trying to get a pdf file from an signed email

jstedfast commented 1 year ago

Checking the IsAttachment property won't ever throw an exception about failing to parse headers.

The exception is coming from a call to MimeEntity.Load(Stream) which must be somewhere else in your program because it could never be thrown anywhere in the code snippet you pasted.

The exception you got suggests that you might be trying to parse a stream w/o resetting the Stream.Position back to 0, but it's possible that the stream is also just malformed (e.g. not MIME).

blutswende commented 1 year ago

Hi, ok maybe i'm throwing some problems in one bucket. Let me reevaluate the problem and I will come back to you.

blutswende commented 1 year ago

@jstedfast you were right. the exception was thrown at MimeEntity.Load(Stream). Reseting the Stream.Position doesn't fix the error.

Do you have an suggestion how to analyze the mail for invalid/valid MIME ?

jstedfast commented 1 year ago

Describe what it looks like.

blutswende commented 1 year ago
Content-Type: application/pkcs7-mime; smime-type=signed-data;
    name="smime.p7m"
Content-Disposition: attachment; filename="smime.p7m"
Content-Transfer-Encoding: base64
MIME-Version: 1.0
X-Djigzo-Info-SMIME-Signed: True
X-Djigzo-Info-Signer-ID-0-0: CN=xx-xx-xx-xx, DC=xxxxxx, DC=xxx,
 DC=com/3D806F//1.2.840.666666.1.1.1
X-Djigzo-Info-Signer-Verified-0-0: True
X-Djigzo-Info-Signer-Trusted-0-0: False
X-Djigzo-Info-Signer-Trusted-Info-0-0: Signing certificate not trusted.
 Message: Error building certPath. Unable to find certificate chain..
 Timestamp: 1664275876923
X-Djigzo-Info-Signer-Email-0-0: xxxxx@xxx.de

So I think that's the problem. The next time i will first have a look into the mail ;-)

jstedfast commented 1 year ago

That looks like valid headers. Does it not have any content?

blutswende commented 1 year ago

@jstedfast can i send you the mail in a secure way?

jstedfast commented 1 year ago

yea, zip it up and send it to jestedfa@microsoft.com

blutswende commented 1 year ago

Unfortunately i'm not allowed to forward this email.

jstedfast commented 1 year ago

I wrote a test case that attempts to parse the text you pasted and it parses correctly with or without an added blank line at the end (I wasn't sure if the blank line at the end existed or not).

Are you sure that's the entity that is failing?

blutswende commented 1 year ago

Maybe i can send you a file which has manipulated content by me without any data

jstedfast commented 1 year ago

Were you waiting for me to say okay? If so, yes, it's ok to send redacted content to me.

jstedfast commented 1 year ago

Okay, so I've taken a look at the sample you sent me via email and the file has a bunch of binary garbage before the start of the headers.

This is what is causing the parser to fail.