-
-
Notifications
You must be signed in to change notification settings - Fork 376
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
Can't create Multipart with custom ContentType #230
Comments
The fact that your work-around stopped working in 1.2.20 is a bug (and I just fixed that), but I don't really like adding a Multipart constructor that takes a ContentType. Instead, I propose a MultipartReport class. |
FWIW, you'll be able to do this: var content = new MultipartReport ("disposition-notification"); |
Wow, this is an exceptional support 👍 All my unit tests are successfull again :-) I will use it immediately after new MimeKit nuget version is available. |
I'll probably release a new nuget this weekend (I normally make releases on weekends due to lack of time on weeknights), so by Monday, there should be a new release waiting for you :) |
I've just released MimeKit 1.2.21 with these fixes to nuget.org |
New nuget packet version 1.2.21 works without any problem. Thank you 👍 |
@xtomas could you share the code how to construct application/edifact MimeMessage and sign then encrypt it using MimeKit? please |
To construct an var edifact = new MimePart ("application", "edifact") {
ContentObject = new ContentObject (contentStream)
}; To set that as the message body, you can just do: message.Body = edifact; I can't help you with encrypting since I know nothing about that... |
Hi @dawud-tan . I do not use edifact format for AS2 messages (but xml), but for signing/encrypting I've created class, derived from WindowsSecureMimeContext. /// <summary>
/// Windows Secure Mime Context extended for AS2 purposes
/// </summary>
internal class As2SecureMimeContext : WindowsSecureMimeContext
{
#region Delegates
/// <summary>
/// Mic delegate
/// </summary>
/// <param name="sender">sender object instance</param>
/// <param name="e">MessageIntegrityCheckArg instance</param>
public delegate void MicDelegate(object sender, MessageIntegrityCheckEventArgs e);
/// <summary>
/// Mic calculated event
/// </summary>
public event MicDelegate MicCalculated;
/// <summary>
/// On Mic calculated event related methods
/// </summary>
/// <param name="mic">MessageIntegrityCheck instance</param>
protected virtual void OnMicCalculated(MessageIntegrityCheck mic)
{
MicCalculated?.Invoke(this, new MessageIntegrityCheckEventArgs(mic));
}
#endregion Delegates
#region Overrides
/// <summary>
/// Sign signedContent using certificate associated with mailbox address
/// </summary>
/// <exception cref="ArgumentException">If signer or content is null.</exception>
/// <param name="signer">Use SecureMailboxAddress</param>
/// <param name="digestAlgo">sha1 and md5 supported only</param>
/// <param name="content">Stream instance</param>
/// <returns>MimeKit.MimePart instance</returns>
public override MimeKit.MimePart Sign(MimeKit.MailboxAddress signer, DigestAlgorithm digestAlgo, Stream content)
{
if (content == null)
throw new ArgumentNullException(nameof(content));
if (signer == null)
throw new ArgumentNullException(nameof(signer));
var mic = new MessageIntegrityCheck(content, (MicAlgorithm)digestAlgo);
OnMicCalculated(mic);
return base.Sign(signer, digestAlgo, content);
}
/// <summary>
/// Sign
/// </summary>
/// <exception cref="ArgumentNullException">If <paramref name="certificate"/> is null or empty or content is null.</exception>
/// <param name="certificate"><see cref="X509Certificate2"/> instance</param>
/// <param name="digestAlgo">DigestAlgorithm enum partnerCertificates</param>
/// <param name="content">Stream instance</param>
/// <returns>MimePart instance</returns>
public MimePart Sign(X509Certificate2 certificate, DigestAlgorithm digestAlgo, Stream content)
{
if (certificate == null)
throw new ArgumentNullException(nameof(certificate));
if (content == null)
throw new ArgumentNullException(nameof(content));
var contentInfo = new ContentInfo(ReadAllBytes(content));
var cmsSigner = GetRealCmsSigner(certificate, digestAlgo);
var mic = new MessageIntegrityCheck(contentInfo.Content, (MicAlgorithm)digestAlgo);
OnMicCalculated(mic);
var signed = new SignedCms(contentInfo, true);
signed.ComputeSignature(cmsSigner);
var signedData = signed.Encode();
return new ApplicationPkcs7Signature(new MemoryStream(signedData, false));
}
#endregion Overrides
#region Private methods
/// <summary>
/// Read all bytes using memory block stream
/// </summary>
/// <param name="stream">Stream instance</param>
/// <returns>byte array</returns>
protected static byte[] ReadAllBytes(Stream stream)
{
if (stream is MemoryBlockStream mbs)
return mbs.ToArray();
if (stream is MemoryStream ms)
return ms.ToArray();
using (var memory = new MemoryBlockStream())
{
stream.CopyTo(memory, 4096);
return memory.ToArray();
}
}
/// <summary>
/// Get Real <see cref="System.Security.Cryptography.Pkcs.CmsSigner">CmsSigner</see>
/// </summary>
/// <exception cref="ArgumentNullException">If <paramref name="certificate"/> is null.</exception>
/// <param name="certificate"><see cref="X509Certificate2"/> instance</param>
/// <param name="digestAlgo">DigestAlgorithm enum partnerCertificates</param>
/// <returns>RealCmsSigner(System.Security.Cryptography.Pkcs.CmsSigner) instance</returns>
protected virtual RealCmsSigner GetRealCmsSigner(X509Certificate2 certificate, DigestAlgorithm digestAlgo)
{
if (certificate == null)
throw new ArgumentNullException(nameof(certificate));
var signer = new RealCmsSigner(certificate)
{
DigestAlgorithm = new Oid(GetDigestOid(digestAlgo)),
IncludeOption = X509IncludeOption.EndCertOnly
};
signer.SignedAttributes.Add(new Pkcs9SigningTime());
return signer;
}
#endregion Private methods
}
/// <summary>
/// MIC EventArgs
/// </summary>
internal class MessageIntegrityCheckEventArgs : EventArgs
{
/// <summary>
/// Message Intergrity Check (MIC)
/// </summary>
public MessageIntegrityCheck MessageIntegrityCheck { get; internal set; }
/// <summary>a
/// Create Message Integrity Check event arguments
/// </summary>
/// <exception cref="ArgumentNullException">If mic is null.</exception>
/// <param name="mic">MessageIntegrityCheck Instance</param>
public MessageIntegrityCheckEventArgs(MessageIntegrityCheck mic)
{
MessageIntegrityCheck = mic ?? throw new ArgumentNullException(nameof(mic));
}
} To created signed multipart, I use this method. private MultipartSigned SignContent(X509Certificate2 certificate)
{
if (certificate == null)
throw new ArgumentNullException(nameof(certificate));
MultipartSigned signedParts;
using (var ctx = new As2SecureMimeContext())
{
// after mic is ready, set Mic property
ctx.MicCalculated += (s, mic) => Mic = mic.MessageIntegrityCheck;
signedParts = ctx.CreateAndVerify(certificate, DigestAlgorithm.Sha1, this.Content);
}
return signedParts;
} I hope, it will help you ;-) TJ |
@xtomas Your code example looks very helpfull. I'm also facing the task of writing an AS2 handler. Are you willing to share some more of your code using MimeKit? Especcially the MessageIntegrityCheck class would be helpfull. |
Hello Jeffrey,
I'm using your great library more than one year for AS2 protocol implementation. After branch 1.20 it stopped working. I guess the problem started after fix #221 (Fixed serialization of mime parts with empty content).
What I need is to create Multipart with given ContentType. But this constructor of MimeEntity is protected and in Multipart is not implemented so there is no way to use it outside MimeKit Assembly.
Here is example of correct AS2 Message.
Until 1.19 I was able to use workaround to create Multipart.
After you have fixed working with empty content, there is no boundary at the end. (in debug console there is message "Multipart without a boundary encountered!" and WriteEndBoundary is set to false.)
The easy fix I see is to add following constructor into Multipart class. It's working, I have tested that.
So my functional code after that is:
Do you see another solution?
Regards,
Tomas
The text was updated successfully, but these errors were encountered: