Skip to content

Commit

Permalink
Add encrypt & sign smime
Browse files Browse the repository at this point in the history
  • Loading branch information
PrzemyslawKlys committed May 15, 2024
1 parent adb1c0c commit 8495d39
Showing 1 changed file with 222 additions and 8 deletions.
230 changes: 222 additions & 8 deletions Sources/Mailozaurr/Smtp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Net.Security;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Cryptography.X509Certificates;

namespace Mailozaurr;

Expand Down Expand Up @@ -134,6 +135,10 @@ public Smtp(string logPath, bool logConsole, bool logObject, bool logTimestamps,
logServerPrefix, logClientPrefix, logOverwrite);
Client = Logging.ProtocolLogger == null ? new ClientSmtp() : new ClientSmtp(Logging.ProtocolLogger);
stopwatch = Stopwatch.StartNew();


//MySecureMimeContext.DatabasePath = "C:\\Temp\\certdb.sqlite";
//CryptographyContext.Register(typeof(MySecureMimeContext));
}

public void CreateMessage() {
Expand All @@ -157,14 +162,14 @@ public SmtpResult Connect(string server, int port, SecureSocketOptions secureSoc
}
Client.Connect(server, port, secureSocketOptions);
Settings.Logger.WriteVerbose($"Connected to {server} on {port} port using SSL: {secureSocketOptions}");
return new SmtpResult(true, SentTo, SentFrom, server, port, stopwatch.Elapsed, "");
return new SmtpResult(true, EmailAction.Connect, SentTo, SentFrom, server, port, stopwatch.Elapsed, "");
} catch (Exception ex) {
Settings.Logger.WriteWarning($"Send-EmailMessage - Error: {ex.Message}");
Settings.Logger.WriteWarning($"Send-EmailMessage - Possible issue: Port? ({port} was used), Using SSL? ({secureSocketOptions}, was used). You can also try 'SkipCertificateValidation' or 'SkipCertificateRevocation'.");
if (ErrorAction == ActionPreference.Stop) {
throw;
}
return new SmtpResult(false, SentTo, SentFrom, server, port, stopwatch.Elapsed, ex.Message);
return new SmtpResult(false, EmailAction.Connect, SentTo, SentFrom, server, port, stopwatch.Elapsed, ex.Message);
}
}

Expand All @@ -183,14 +188,14 @@ public SmtpResult Authenticate(ICredentials Credentials, bool isOAuth = false) {
Client.Authenticate(Credentials);
Settings.Logger.WriteVerbose($"Send-EmailMessage - Authenticated using ICredentials");
}
return new SmtpResult(true, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
return new SmtpResult(true, EmailAction.Authenticate, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
} catch (Exception ex) {
Settings.Logger.WriteWarning($"Send-EmailMessage - Error: {ex.Message}");
Settings.Logger.WriteWarning($"Send-EmailMessage - Possible issue: OAuth? ({isOAuth} was used), ICredentials? ({Credentials}, was used).");
if (ErrorAction == ActionPreference.Stop) {
throw;
}
return new SmtpResult(false, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, ex.Message);
return new SmtpResult(false, EmailAction.Authenticate, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, ex.Message);
}
}

Expand All @@ -212,29 +217,29 @@ public SmtpResult Authenticate(string username, string password, bool isSecureSt
try {
Client.Authenticate(username, password);
Settings.Logger.WriteVerbose($"Send-EmailMessage - Authenticated as {username}");
return new SmtpResult(true, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
return new SmtpResult(true, EmailAction.Authenticate, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
} catch (Exception ex) {
Settings.Logger.WriteWarning($"Send-EmailMessage - Error: {ex.Message}");
Settings.Logger.WriteWarning($"Send-EmailMessage - Possible issue: Username? ({username} was used), Password?.");
if (ErrorAction == ActionPreference.Stop) {
throw;
}
return new SmtpResult(false, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, ex.Message);
return new SmtpResult(false, EmailAction.Authenticate, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, ex.Message);
}
}

public SmtpResult Send() {
try {
Client.Send(Message);
Settings.Logger.WriteVerbose($"Send-EmailMessage - Sent email to {SentTo}");
return new SmtpResult(true, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
return new SmtpResult(true, EmailAction.Send, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
} catch (Exception ex) {
Settings.Logger.WriteWarning($"Send-EmailMessage - Error: {ex.Message}");
Settings.Logger.WriteWarning($"Send-EmailMessage - Possible issue: Message? ({Message} was used).");
if (ErrorAction == ActionPreference.Stop) {
throw;
}
return new SmtpResult(false, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, ex.Message);
return new SmtpResult(false, EmailAction.Send, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, ex.Message);
}
}

Expand All @@ -247,4 +252,213 @@ public void Dispose() {
Client.Dispose();
stopwatch.Stop();
}

public SmtpResult Encrypt(string pfxFilePath, string password) {
X509Certificate2 certificate = new X509Certificate2(pfxFilePath, password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
return Encrypt(certificate);
}

public SmtpResult Encrypt(string certificateThumbprint) {
// Load the certificate from the Windows Certificate Store
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);

X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);

store.Close();

if (certificates.Count > 0) {
// Use the certificate directly from the store to encrypt the email
return Encrypt(certificates[0]);
} else {
if (ErrorAction == ActionPreference.Stop) {
throw new Exception("Certificate not found in the store.");
}
return new SmtpResult(true, EmailAction.SMimeEncrypt, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, "Certificate not found in the store.");
}
}

public SmtpResult Encrypt(X509Certificate2 certificate) {
MimeMessage message = Message;
// encrypt our message body using our custom S/MIME cryptography context
using (var ctx = new DefaultSecureMimeContext()) {
try {
// Create a CmsRecipientCollection and add the CmsRecipient to it
var recipients = new CmsRecipientCollection();
recipients.Add(new CmsRecipient(certificate));

// Encrypt the message body with the certificate
message.Body = ApplicationPkcs7Mime.Encrypt(ctx, recipients, message.Body);
} catch (Exception ex) {
Settings.Logger.WriteWarning($"Send-EmailMessage - Error: {ex.Message}");
Settings.Logger.WriteWarning($"Send-EmailMessage - Possible issue: Certificate? ({certificate.Thumbprint} was used).");
if (ErrorAction == ActionPreference.Stop) {
throw;
}
return new SmtpResult(false, EmailAction.SMimeEncrypt, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, ex.Message);
}
}

Message = message;
return new SmtpResult(true, EmailAction.SMimeEncrypt, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
}

public SmtpResult MultipartSign(X509Certificate2 certificate) {
MimeMessage message = Message;
// digitally sign our message body using our custom S/MIME cryptography context
//Exception calling "MultipartSignFromStore" with "1" argument(s): "SQLite is not available. Install the System.Data.SQLite nuget package."
using (var ctx = new DefaultSecureMimeContext()) {
try {
var signer = new CmsSigner(certificate) {
DigestAlgorithm = DigestAlgorithm.Sha1
};
message.Body = MultipartSigned.Create(ctx, signer, message.Body);

} catch (Exception ex) {
Settings.Logger.WriteWarning($"Send-EmailMessage - Error: {ex.Message}");
Settings.Logger.WriteWarning($"Send-EmailMessage - Possible issue: Certificate? ({certificate.Thumbprint} was used).");
if (ErrorAction == ActionPreference.Stop) {
throw;
}
return new SmtpResult(false, EmailAction.SMimeSignature, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, ex.Message);
}
}
Message = message;
return new SmtpResult(true, EmailAction.SMimeSignature, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
}

public SmtpResult MultipartSign(string pfxFilePath, string password) {
X509Certificate2 certificate = new X509Certificate2(pfxFilePath, password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
return MultipartSign(certificate);
}

public SmtpResult MultipartSign(string certificateThumbprint) {
// Load the certificate from the Windows Certificate Store
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);

X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);

store.Close();

if (certificates.Count > 0) {
// Use the certificate directly from the store to sign the email
return MultipartSign(certificates[0]);
} else {
throw new Exception("Certificate not found in the store.");
}
}


//public SmtpResult MultipartSignFromStore(string certificateThumbprint, string pfxPassword) {
// // Load the certificate from the Windows Certificate Store
// X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
// store.Open(OpenFlags.ReadOnly);

// X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);

// store.Close();

// if (certificates.Count > 0) {
// // Export the certificate to a PFX file
// byte[] pfxData = certificates[0].Export(X509ContentType.Pfx, pfxPassword);

// // Import the certificate from the PFX data
// X509Certificate2 certificate = new X509Certificate2(pfxData, pfxPassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);

// // Sign the email with the certificate
// //using (var ctx = new DefaultSecureMimeContext()) {
// // var signer = new CmsSigner(certificate) {
// // DigestAlgorithm = DigestAlgorithm.Sha1
// // };
// // Message.Body = MultipartSigned.Create(ctx, signer, Message.Body);
// //}
// return MultipartSign(certificate);
// } else {
// throw new Exception("Certificate not found in the store.");
// }
//}


public void Pkcs7Sign(string pfxFilePath, string password) {
X509Certificate2 certificate = new X509Certificate2(pfxFilePath, password, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet);
Pkcs7Sign(certificate);
}

public void Pkcs7Sign(string certificateThumbprint) {
// Load the certificate from the Windows Certificate Store
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);

X509Certificate2Collection certificates = store.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false);

store.Close();

if (certificates.Count > 0) {
// Use the certificate directly from the store to sign the email
Pkcs7Sign(certificates[0]);
} else {
throw new Exception("Certificate not found in the store.");
}
}


public SmtpResult Pkcs7Sign(X509Certificate2 certificate) {
try {
MimeMessage message = Message;
// digitally sign our message body using our custom S/MIME cryptography context
using (var ctx = new DefaultSecureMimeContext()) {
// Create a signer with the certificate
var signer = new CmsSigner(certificate) {
DigestAlgorithm = DigestAlgorithm.Sha256
};

// Sign the message body with the signer
message.Body = ApplicationPkcs7Mime.Sign(ctx, signer, message.Body);
}

Message = message;
return new SmtpResult(true, EmailAction.SMimeSignaturePKCS7, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
} catch (Exception ex) {
Settings.Logger.WriteWarning($"Send-EmailMessage - Error: {ex.Message}");
Settings.Logger.WriteWarning($"Send-EmailMessage - Possible issue: Certificate? ({certificate.Thumbprint} was used).");
if (ErrorAction == ActionPreference.Stop) {
throw;
}
return new SmtpResult(false, EmailAction.SMimeSignaturePKCS7, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, ex.Message);
}
}

public SmtpResult SignAndEncrypt(string certificateThumbprint) {
// Sign the email
SmtpResult signResult = MultipartSign(certificateThumbprint);
if (!signResult.Status) {
return signResult;
}

// Encrypt the signed email
SmtpResult encryptResult = Encrypt(certificateThumbprint);
if (!encryptResult.Status) {
return encryptResult;
}

return new SmtpResult(true, EmailAction.SMimeSignAndEncrypt, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
}

public SmtpResult SignAndEncrypt(string pfxFilePath, string password) {
// Sign the email
SmtpResult signResult = MultipartSign(pfxFilePath, password);
if (!signResult.Status) {
return signResult;
}

// Encrypt the signed email
SmtpResult encryptResult = Encrypt(pfxFilePath, password);
if (!encryptResult.Status) {
return encryptResult;
}

return new SmtpResult(true, EmailAction.SMimeSignAndEncrypt, SentTo, SentFrom, Server, Port, stopwatch.Elapsed, Logging);
}

}

0 comments on commit 8495d39

Please sign in to comment.