I am trying to sign a mail but get a email with a p7s with my certificates and not a signed email

49 Views Asked by At

I have an issue, I do not understand why I have a s/mime certificate for my email; it doesn't sign my email body but generates an attachment with all certificates! Is this a bug or a brand-new way to export and email my local certificates to a random email address?

if (SmtpSettings.SignEmail)
{
    using var certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(SmtpSettings.CertificatePath, SmtpSettings.CertificatePassword);

    if (DateTime.TryParse(certificate.GetExpirationDateString(), out var expires) && expires > IClock.Instance.UtcNow)
    {
        // Get the email address from the certificate
        var name = new Org.BouncyCastle.Asn1.X509.X509Name(certificate.SubjectName.Name);
        var certificateEmail = name.GetValueList(Org.BouncyCastle.Asn1.X509.X509Name.EmailAddress);

        var signer = message.From.Cast<MailboxAddress>().Single();
        try
        {
            if (certificateEmail is null || certificateEmail.Count == 0 || (certificateEmail is not null && certificateEmail.Any(email => string.Equals(email, signer.Address, StringComparison.OrdinalIgnoreCase))))
            {
                using var smimeContext = new MimeKit.Cryptography.WindowsSecureMimeContext();
                await smimeContext.ImportAsync(SmtpSettings.CertificatePath, SmtpSettings.CertificatePassword).ConfigureAwait(false);
                using var memoryStream = new MemoryStream();
                message.Body.WriteTo(memoryStream);
                memoryStream.Position = 0;

                var signedContent = smimeContext.Sign(signer, MimeKit.Cryptography.DigestAlgorithm.Sha256, memoryStream);

                if (signedContent is not null)
                {
                    message.Body = signedContent;
                }
            }
        }catch (Exception ex)
        { 
            _logger?.LogError(ex,"Could not sign the email due to a {ex} Exception: {message}",ex.GetType().Name,ex.Message);
        }
    }
}
1

There are 1 best solutions below

0
Walter Verhoeven On

I posted my question to jstedfast in GitHub and 4 hours later, I had working code as replied two options, copied below, I took the top one, and now I get signed emails, here is what he told me to use:

using var certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(SmtpSettings.CertificatePath, SmtpSettings.CertificatePassword);

    if (DateTime.TryParse(certificate.GetExpirationDateString(), out var expires) && expires > IClock.Instance.UtcNow)
    {
        // Get the email address from the certificate
        var name = new Org.BouncyCastle.Asn1.X509.X509Name(certificate.SubjectName.Name);
        var certificateEmail = name.GetValueList(Org.BouncyCastle.Asn1.X509.X509Name.EmailAddress);
    
        var signer = message.From.Mailboxes.FirstOrDefault();
        try
        {
            if (certificateEmail is null || certificateEmail.Count == 0 || (certificateEmail is not null && certificateEmail.Any(email => string.Equals(email, signer.Address, StringComparison.OrdinalIgnoreCase))))
            {
                using var smimeContext = new MimeKit.Cryptography.WindowsSecureMimeContext();
                await smimeContext.ImportAsync(SmtpSettings.CertificatePath, SmtpSettings.CertificatePassword).ConfigureAwait(false);
                 
                var signedContent = MultipartSigned.Create(smimeContext, signer, MimeKit.Cryptography.DigestAlgorithm.Sha256, message.Body);
                message.Body = signedContent;
            }
        }catch (Exception ex)
        { 
            _logger?.LogError(ex,"Could not sign the email due to a {ex} Exception: {message}",ex.GetType().Name,ex.Message);
        }
    }

Or simpler:

using var certificate = new System.Security.Cryptography.X509Certificates.X509Certificate2(SmtpSettings.CertificatePath, SmtpSettings.CertificatePassword);

if (DateTime.TryParse(certificate.GetExpirationDateString(), out var expires) && expires > IClock.Instance.UtcNow)
{
    var signer = new MimeKit.Cryptography.CmsSigner(certificate);
    signer.DigestAlgorithm = MimeKit.Cryptography.DigestAlgorithm.Sha256;

    try
    {
        using var smimeContext = new MimeKit.Cryptography.WindowsSecureMimeContext();
        var signedContent = MultipartSigned.Create(smimeContext, signer, message.Body);
        message.Body = signedContent;
    }catch (Exception ex)
    { 
        _logger?.LogError(ex,"Could not sign the email due to a {ex} Exception: {message}",ex.GetType().Name,ex.Message);
    }
}

I hope it helps some one