+1 vote

We have an HSM device. Can we create a signed and encrypted smime with the key on the device?

by

1 Answer

0 votes

To create a signed/encrypted SMIME email using Mail.dll you need an X509Certificate2 instance:

MailBuilder builder = new MailBuilder();
builder.Text = "Hello";
builder.Subject = "Encrypted and signed";
builder.From.Add(new MailBox("alice@example.com", "Alice"));
builder.To.Add(new MailBox("bob@example.com", "Bob"));

builder.SignWith(new X509Certificate2("AlicePrivateSignCertificate.pfx", ""));
builder.EncryptWith(new X509Certificate2("AlicePublicCertificate.pfx", ""));
builder.EncryptWith(new X509Certificate2("BobsPublicCertificate.pfx", ""));

IMail email = builder.Create();

You can use this code to list certificates stored in CurrentUser store:

X509Store store = new X509Store(StoreName.My,StoreLocation.CurrentUser);
store.Open(OpenFlags.Read);

Trace.WriteLine("count = " + store.Certificates.Count);
foreach (X509Certificate2 certificate in store.Certificates)
{
    Trace.WriteLine(certificate.Subject);
}
store.Close();

If your HSM device acts as a key-store you can use the code above.

Below is the code that shows how to sign data externally:

private byte[] ExternalSign_SmartCard_or_HSM(byte[] plainData)
{
    // This is a .NET version, you use HSM device here to sign data.

    SignedCms signedCms = new SignedCms(new ContentInfo(plainData), true);

    X509Certificate2 certificate = new X509Certificate2("cert.pfx"), 
        "",
        X509KeyStorageFlags.PersistKeySet)
    CmsSigner signer = new CmsSigner(certificate);
    signer.IncludeOption = X509IncludeOption.WholeChain;
    signer.DigestAlgorithm = new System.Security.Cryptography.Oid(
        CommonOids.Sha1);
    signer.SignedAttributes.Add(new Pkcs9SigningTime(DateTime.Now));

    signedCms.ComputeSignature(signer);
    return signedCms.Encode();
}

[Test]
public void Build_ExternalSign_SmartCard_or_HSM_ValidSignature()
{
    MailBuilder builder = new MailBuilder();
    MimeData attachment = builder.AddAttachment(new byte[] { 1, 2, 3 });
    attachment.SetFileName("file.bin", true);

    builder.Html = "some <strong>html</strong> content";
    IMail plain = builder.Create();

    MimeBase plainRoot = plain.Document.Root;

    // here you prepate a signature
    byte[] plainData = plainRoot.Render();
    byte[] signatureData = ExternalSign_SmartCard_or_HSM(plainData);

    MimeFactory f = new MimeFactory();

    MimeMultipart root = f.CreateMimeMultipart(ContentType.MultipartSigned);
    root.ContentTypeHeader["protocol"] = "application/pkcs7-signature";
    root.ContentTypeHeader["micalg"] = "sha-1";

    root.Parts.Add(plainRoot);   // you must use the same plain root you signed here
                                 // (same random generated boundaries must be used).

    // alternatively you can re-create it from plain Data:
    // root.Parts.Add(f.Create(plainData));  

    MimePkcs7Signature signature = f.CreatePkcs7Signature(signatureData);
    root.Parts.Add(signature);

    IMail mail = new MailFactory().CreateMail(root);
    mail.Subject = "subject";
    mail.From.Add(new MailBox("email@in-the-certificate.com"));
    mail.To.Add(new MailBox("to@example.com"));

    Console.WriteLine(mail.RenderAsASCII());

    byte[] eml = mail.Render();

    // This parses eml and checks the signature 
    // No exception -> it's valid

    IMail parsed = new MailBuilder().CreateFromEml(eml);
    Assert.AreEqual("1.0", parsed.MimeVersion);
    Assert.IsNotNull(parsed.Date);
    Assert.IsNotNull(parsed.MessageID);
    parsed.CheckSignature(true);
}
by (301k points)
edited by
...