From 0c681f220c125c56605a2859872f02950ab3c9b1 Mon Sep 17 00:00:00 2001 From: bbottema Date: Wed, 20 Mar 2024 17:22:18 +0100 Subject: [PATCH] #498: Finally implement builder API to configure S/MIME signing and/or encryption algorithms, and actually use it. Added tests to test some variations, including both RSA (already present) and DSA (added new key for this in pkcs store). --- .../org/simplejavamail/api/email/Email.java | 51 ++- .../api/email/EmailPopulatingBuilder.java | 406 ++++++++---------- .../api/email/EqualsHelper.java | 4 +- .../email/config/SmimeEncryptionConfig.java | 172 ++++++++ .../api/email/config/SmimeSigningConfig.java | 148 +++++++ .../internal/config/EmailProperty.java | 4 +- .../internal/modules/SMIMEModule.java | 7 +- .../internal/util/MiscUtil.java | 2 +- .../converter/EmailConverter.java | 21 +- .../SpecializedMimeMessageProducer.java | 8 +- .../email/internal/EmailException.java | 27 +- .../internal/EmailPopulatingBuilderImpl.java | 151 ++----- .../internal/EmailStartingBuilderImpl.java | 8 +- .../simplejavamail/mailer/MailerHelper.java | 12 +- .../mailer/internal/EmailGovernanceImpl.java | 33 +- .../simplejavamail/api/email/EmailTest.java | 7 +- .../config/ConfigLoaderTest.java | 2 +- .../converter/EmailConverterTest.java | 4 +- .../EmailPopulatingBuilderImpl1Test.java | 21 +- .../EmailPopulatingBuilderImpl2Test.java | 28 +- .../smimesupport/SmimeSignAndEncryptTest.java | 77 +++- .../simplejavamail/mailer/MailerLiveTest.java | 69 ++- .../org/simplejavamail/mailer/MailerTest.java | 4 +- .../mailer/internal/MailerImplTest.java | 16 +- .../simplejavamail/util/TestDataHelper.java | 2 +- .../test/resources/pkcs12/about all this.txt | 7 +- .../resources/pkcs12/smime_keystore.pkcs12 | Bin 4418 -> 6875 bytes .../test/resources/simplejavamail.properties | 2 +- .../smimesupport/CMSAlgorithmResolver.java | 38 ++ .../internal/smimesupport/SMIMESupport.java | 37 +- .../smimesupport/model/SmimeDetailsImpl.java | 25 +- .../SimpleJavaMailProperties.java | 3 + .../resources/pkcs12/smime_keystore.pkcs12 | Bin 4418 -> 4542 bytes .../test/resources/simplejavamail.properties | 2 +- 34 files changed, 889 insertions(+), 509 deletions(-) create mode 100644 modules/core-module/src/main/java/org/simplejavamail/api/email/config/SmimeEncryptionConfig.java create mode 100644 modules/core-module/src/main/java/org/simplejavamail/api/email/config/SmimeSigningConfig.java create mode 100644 modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/CMSAlgorithmResolver.java diff --git a/modules/core-module/src/main/java/org/simplejavamail/api/email/Email.java b/modules/core-module/src/main/java/org/simplejavamail/api/email/Email.java index 186ba857e..e24adb922 100644 --- a/modules/core-module/src/main/java/org/simplejavamail/api/email/Email.java +++ b/modules/core-module/src/main/java/org/simplejavamail/api/email/Email.java @@ -5,14 +5,14 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.simplejavamail.api.email.config.DkimConfig; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.api.internal.smimesupport.model.PlainSmimeDetails; -import org.simplejavamail.api.mailer.config.Pkcs12Config; import org.simplejavamail.internal.config.EmailProperty; import org.simplejavamail.internal.util.MiscUtil; -import java.io.InputStream; +import java.io.File; import java.io.Serializable; -import java.security.cert.X509Certificate; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Date; @@ -192,17 +192,17 @@ public class Email implements Serializable { private final DkimConfig dkimConfig; /** - * @see EmailPopulatingBuilder#signWithSmime(Pkcs12Config) - * @see EmailPopulatingBuilder#signWithSmime(InputStream, String, String, String) + * @see EmailPopulatingBuilder#encryptWithSmime(SmimeEncryptionConfig) + * @see EmailPopulatingBuilder#encryptWithSmime(File, String, String) */ - private final X509Certificate x509CertificateForSmimeEncryption; + private final SmimeEncryptionConfig smimeEncryptionConfig; /** - * @see EmailPopulatingBuilder#encryptWithSmime(X509Certificate) - * @see EmailPopulatingBuilder#encryptWithSmime(InputStream) + * @see EmailPopulatingBuilder#signWithSmime(SmimeSigningConfig) + * @see EmailPopulatingBuilder#signWithSmime(File, String, String, String, String) */ // data source is not serializable, so transient - private final transient Pkcs12Config pkcs12ConfigForSmimeSigning; + private transient final SmimeSigningConfig smimeSigningConfig; /** * @see EmailPopulatingBuilder#getSmimeSignedEmail() @@ -274,8 +274,8 @@ public Email(@NotNull final EmailPopulatingBuilder builder) { emailToForward = builder.getEmailToForward(); originalSmimeDetails = builder.getOriginalSmimeDetails(); sentDate = builder.getSentDate(); - x509CertificateForSmimeEncryption = builder.getX509CertificateForSmimeEncryption(); - pkcs12ConfigForSmimeSigning = builder.getPkcs12ConfigForSmimeSigning(); + smimeEncryptionConfig = builder.getSmimeEncryptionConfig(); + smimeSigningConfig = builder.getSmimeSigningConfig(); dkimConfig = builder.getDkimConfig(); } @@ -335,18 +335,18 @@ public String toString() { s += ",\n\tforwardingEmail=true"; } - if (smimeSignedEmail != null || pkcs12ConfigForSmimeSigning != null - || x509CertificateForSmimeEncryption != null || !(originalSmimeDetails instanceof PlainSmimeDetails)) { + if (smimeSignedEmail != null || smimeSigningConfig != null + || smimeEncryptionConfig != null || !(originalSmimeDetails instanceof PlainSmimeDetails)) { s += ",\n\tsmime details: {\n"; s += "\t----------------------\n"; if (smimeSignedEmail != null) { s += "\t\tsmimeSignedEmail=" + smimeSignedEmail + ",\n"; } - if (pkcs12ConfigForSmimeSigning != null) { - s += "\t\tpkcs12ConfigForSmimeSigning=" + pkcs12ConfigForSmimeSigning + ",\n"; + if (smimeSigningConfig != null) { + s += "\t\tsmimeSigningConfig=" + smimeSigningConfig + ",\n"; } - if (x509CertificateForSmimeEncryption != null) { - s += "\t\tx509CertificateForSmimeEncryption=" + x509CertificateForSmimeEncryption; + if (smimeEncryptionConfig != null) { + s += "\t\tsmimeEncryptionConfig=" + smimeEncryptionConfig; } s += "\t\toriginalSmimeDetails=" + originalSmimeDetails + "\n"; s += "\t----------------------\n\t}"; @@ -600,23 +600,22 @@ public Map> getHeaders() { public DkimConfig getDkimConfig() { return dkimConfig; } - /** - * @see EmailPopulatingBuilder#signWithSmime(Pkcs12Config) - * @see EmailPopulatingBuilder#signWithSmime(InputStream, String, String, String) + * @see EmailPopulatingBuilder#encryptWithSmime(SmimeEncryptionConfig) + * @see EmailPopulatingBuilder#encryptWithSmime(File, String, String) */ @Nullable - public X509Certificate getX509CertificateForSmimeEncryption() { - return x509CertificateForSmimeEncryption; + public SmimeEncryptionConfig getSmimeEncryptionConfig() { + return smimeEncryptionConfig; } /** - * @see EmailPopulatingBuilder#encryptWithSmime(X509Certificate) - * @see EmailPopulatingBuilder#encryptWithSmime(InputStream) + * @see EmailPopulatingBuilder#signWithSmime(SmimeSigningConfig) + * @see EmailPopulatingBuilder#signWithSmime(File, String, String, String, String) */ @Nullable - public Pkcs12Config getPkcs12ConfigForSmimeSigning() { - return pkcs12ConfigForSmimeSigning; + public SmimeSigningConfig getSmimeSigningConfig() { + return smimeSigningConfig; } /** diff --git a/modules/core-module/src/main/java/org/simplejavamail/api/email/EmailPopulatingBuilder.java b/modules/core-module/src/main/java/org/simplejavamail/api/email/EmailPopulatingBuilder.java index d320f20c6..aac41dc77 100644 --- a/modules/core-module/src/main/java/org/simplejavamail/api/email/EmailPopulatingBuilder.java +++ b/modules/core-module/src/main/java/org/simplejavamail/api/email/EmailPopulatingBuilder.java @@ -9,17 +9,16 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.simplejavamail.api.email.config.DkimConfig; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.api.internal.clisupport.model.Cli; import org.simplejavamail.api.internal.clisupport.model.CliBuilderApiType; import org.simplejavamail.api.mailer.Mailer; import org.simplejavamail.api.mailer.config.EmailGovernance; -import org.simplejavamail.api.mailer.config.Pkcs12Config; import org.simplejavamail.internal.config.EmailProperty; import java.io.File; -import java.io.InputStream; import java.net.URL; -import java.security.cert.X509Certificate; import java.util.Collection; import java.util.Date; import java.util.List; @@ -129,7 +128,7 @@ public interface EmailPopulatingBuilder { * @param configProperties The properties that should not be overridden when sending the email. */ EmailPopulatingBuilder dontApplyOverrideValueFor(@NotNull EmailProperty @NotNull ...configProperties); - + /** * Sets optional ID to a fixed value, which is otherwise generated by the underlying JavaMail framework when sending the email. *

@@ -140,7 +139,7 @@ public interface EmailPopulatingBuilder { * @param id The mime message id, example: {@code <123@456>} */ EmailPopulatingBuilder fixingMessageId(@Nullable String id); - + /** * Delegates to {@link #from(String, String)} with empty name. * @@ -148,7 +147,7 @@ public interface EmailPopulatingBuilder { */ @Cli.ExcludeApi(reason = "API is subset of another API") EmailPopulatingBuilder from(@NotNull String fromAddress); - + /** * Delegates to {@link #from(Recipient)} with a new {@link Recipient} wrapped around the given name and email address. * @@ -156,17 +155,17 @@ public interface EmailPopulatingBuilder { * @param fromAddress The address that will be visible to the receivers of this email. */ EmailPopulatingBuilder from(@Nullable String name, @NotNull String fromAddress); - + /** * Delegates to {@link #from(Recipient)} with a new {@link Recipient} wrapped around the given fixed name and email address. */ EmailPopulatingBuilder from(@Nullable String fixedName, @NotNull InternetAddress fromAddress); - + /** * Delegates to {@link #from(Recipient)} with a new {@link Recipient} wrapped around the given email address. */ EmailPopulatingBuilder from(@NotNull InternetAddress fromAddress); - + /** * Sets the address of the sender of this email with given {@link Recipient} (ignoring its {@link Message.RecipientType} if provided). *

@@ -180,7 +179,7 @@ public interface EmailPopulatingBuilder { * @see #withReplyTo(Recipient) */ EmailPopulatingBuilder from(@NotNull Recipient recipient); - + /** * Delegates to {@link #withReplyTo(Recipient)} with a new {@link Recipient} wrapped around the given email address. * @@ -188,7 +187,7 @@ public interface EmailPopulatingBuilder { */ @Cli.ExcludeApi(reason = "API is subset of another API") EmailPopulatingBuilder withReplyTo(@NotNull String replyToAddress); - + /** * Delegates to {@link #withReplyTo(Recipient)} with a new {@link Recipient} wrapped around the given fixed name and email address. * @@ -196,12 +195,12 @@ public interface EmailPopulatingBuilder { * @param replyToAddress The address that receivers will get when they reply to the email. Any name included in the address will be ignored. */ EmailPopulatingBuilder withReplyTo(@Nullable String fixedName, @NotNull String replyToAddress); - + /** * Delegates to {@link #withReplyTo(Recipient)} with a new {@link Recipient} wrapped around the given address. */ EmailPopulatingBuilder withReplyTo(@NotNull InternetAddress replyToAddress); - + /** * Delegates to {@link #withReplyTo(Recipient)} with a new {@link Recipient} wrapped around the given fixed name and address. */ @@ -222,7 +221,7 @@ public interface EmailPopulatingBuilder { * @see #withReplyTo(String, String) */ EmailPopulatingBuilder withReplyTo(@NotNull List recipients); - + /** * Delegates to {@link #withBounceTo(Recipient)} with a new {@link Recipient} wrapped around the email address (or null if missing). * @@ -231,7 +230,7 @@ public interface EmailPopulatingBuilder { @Cli.ExcludeApi(reason = "API is subset of another API") @SuppressWarnings("unused") EmailPopulatingBuilder withBounceTo(@Nullable String bounceToAddress); - + /** * Delegates to {@link #withBounceTo(Recipient)} with a new {@link Recipient} wrapped around the given name and email address. * @@ -239,20 +238,20 @@ public interface EmailPopulatingBuilder { * @param bounceToAddress The address of the receiver of the bounced email */ EmailPopulatingBuilder withBounceTo(@Nullable String name, @NotNull String bounceToAddress); - + /** * Delegates to {@link #withBounceTo(Recipient)} with a new {@link Recipient} wrapped around the given address. */ @SuppressWarnings("UnusedReturnValue") EmailPopulatingBuilder withBounceTo(@NotNull InternetAddress bounceToAddress); - + /** * Delegates to {@link #withBounceTo(Recipient)} with a new {@link Recipient} wrapped around the given fixed name and address. */ @Cli.ExcludeApi(reason = "Method is not detailed enough for CLI") @SuppressWarnings("unused") EmailPopulatingBuilder withBounceTo(@Nullable String name, @NotNull InternetAddress bounceToAddress); - + /** * Sets the bounceTo address of this email with given {@link Recipient} (ignoring its {@link Message.RecipientType} if provided). *

@@ -264,14 +263,14 @@ public interface EmailPopulatingBuilder { * @see #withBounceTo(String, String) */ EmailPopulatingBuilder withBounceTo(@Nullable Recipient recipient); - + /** * Sets the optional subject of this email. * * @param subject Optional text to be used in the subject field of the email. */ EmailPopulatingBuilder withSubject(@Nullable String subject); - + /** * Delegates to {@link #withPlainText(String)}. * @@ -280,7 +279,7 @@ public interface EmailPopulatingBuilder { */ @Cli.OptionNameOverride("withPlainTextFromFile") EmailPopulatingBuilder withPlainText(@NotNull File textFile); - + /** * Sets the optional email message body in plain text. *

@@ -295,7 +294,7 @@ public interface EmailPopulatingBuilder { * @see #appendText(String) */ EmailPopulatingBuilder withPlainText(@Nullable String text); - + /** * Delegates to {@link #prependText(String)}. * @@ -304,7 +303,7 @@ public interface EmailPopulatingBuilder { @Cli.OptionNameOverride("prependTextFromFile") @SuppressWarnings("unused") EmailPopulatingBuilder prependText(@NotNull File textFile); - + /** * Prepends text to the current plain text body (or starts it if plain text body is missing). * @@ -315,7 +314,7 @@ public interface EmailPopulatingBuilder { * @see #withPlainText(String) */ EmailPopulatingBuilder prependText(@NotNull String text); - + /** * Delegates to {@link #appendText(String)}. * @@ -324,7 +323,7 @@ public interface EmailPopulatingBuilder { @Cli.OptionNameOverride("appendTextFromFile") @SuppressWarnings("unused") EmailPopulatingBuilder appendText(@NotNull File textFile); - + /** * Appends text to the current plain text body (or starts it if plain text body is missing). * @@ -335,7 +334,7 @@ public interface EmailPopulatingBuilder { * @see #withPlainText(String) */ EmailPopulatingBuilder appendText(@NotNull String text); - + /** * Delegates to {@link #withHTMLText(String)}. * @@ -344,7 +343,7 @@ public interface EmailPopulatingBuilder { */ @Cli.OptionNameOverride("withHTMLTextFromFile") EmailPopulatingBuilder withHTMLText(@NotNull File textHTMLFile); - + /** * Sets the optional email message body in HTML text. *

@@ -359,7 +358,7 @@ public interface EmailPopulatingBuilder { * @see #appendTextHTML(String) */ EmailPopulatingBuilder withHTMLText(@Nullable String textHTML); - + /** * Delegates to {@link #prependTextHTML(String)}. * @@ -368,7 +367,7 @@ public interface EmailPopulatingBuilder { @Cli.OptionNameOverride("prependTextHTMLFromFile") @SuppressWarnings("unused") EmailPopulatingBuilder prependTextHTML(@NotNull File textHTMLFile); - + /** * Prepends HTML text to the current HTML text body (or starts it if HTML text body is missing). * @@ -379,7 +378,7 @@ public interface EmailPopulatingBuilder { * @see #withHTMLText(String) */ EmailPopulatingBuilder prependTextHTML(@NotNull String textHTML); - + /** * Delegates to {@link #appendTextHTML(String)}. * @@ -388,7 +387,7 @@ public interface EmailPopulatingBuilder { @Cli.OptionNameOverride("appendTextHTMLFromFile") @SuppressWarnings("unused") EmailPopulatingBuilder appendTextHTML(@NotNull File textHTMLFile); - + /** * Appends HTML text to the current HTML text body (or starts it if HTML text body is missing). * @@ -399,7 +398,7 @@ public interface EmailPopulatingBuilder { * @see #withHTMLText(String) */ EmailPopulatingBuilder appendTextHTML(@NotNull String textHTML); - + /** * Sets the optional calendar details that clients such as Outlook might be able to handle. Will be set as alternative bodypart similar to * {@link #withPlainText(String)} and {@link #withHTMLText(String)}. @@ -427,12 +426,12 @@ public interface EmailPopulatingBuilder { * Delegates to {@link #withRecipients(Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO}. */ EmailPopulatingBuilder to(@NotNull Recipient @NotNull ...recipients); - + /** * Delegates to {@link #withRecipients(Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO}. */ EmailPopulatingBuilder to(@NotNull Collection recipients); - + /** * Delegates to {@link #withRecipients(String, boolean, Collection, Message.RecipientType)}, with recipientType={@link Message.RecipientType#TO} and * fixedName=true assigning or overwriting existing names with the provided name. @@ -449,7 +448,7 @@ public interface EmailPopulatingBuilder { * */ EmailPopulatingBuilder to(@Nullable String name, String oneOrMoreAddresses); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO} and empty default name. * @@ -463,116 +462,116 @@ public interface EmailPopulatingBuilder { */ @Cli.ExcludeApi(reason = "API is subset of another API method") EmailPopulatingBuilder to(@NotNull String oneOrMoreAddresses); - + /** * Alias for {@link #toWithFixedName(String, String...)}. */ EmailPopulatingBuilder to(@Nullable String name, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Alias for {@link #toWithFixedName(String, Collection)}. */ EmailPopulatingBuilder to(@Nullable String name, @NotNull Collection oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder toMultiple(@NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder toMultiple(@NotNull Collection oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO}. */ EmailPopulatingBuilder toWithFixedName(@Nullable String name, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO}. */ EmailPopulatingBuilder toWithDefaultName(@NotNull String name, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO}. */ EmailPopulatingBuilder toWithFixedName(@Nullable String name, @NotNull Collection oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO}. */ @SuppressWarnings("unused") EmailPopulatingBuilder toWithDefaultName(@NotNull String name, @NotNull Collection oneOrMoreAddressesEach); - + /** * Alias for {@link #toAddressesWithFixedName(String, InternetAddress...)}. */ EmailPopulatingBuilder to(@Nullable String name, InternetAddress address); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO} and empty default name. */ @SuppressWarnings("UnusedReturnValue") EmailPopulatingBuilder to(@NotNull InternetAddress address); - + /** * Alias for {@link #toAddressesWithFixedName(String, InternetAddress...)}. */ EmailPopulatingBuilder to(@Nullable String name, @NotNull InternetAddress @NotNull ...addresses); - + /** * Alias for {@link #toAddressesWithFixedName(String, Collection)}. */ @SuppressWarnings("unused") EmailPopulatingBuilder toAddresses(@Nullable String name, @NotNull Collection addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder toMultiple(@NotNull InternetAddress @NotNull ...addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder toMultipleAddresses(@NotNull Collection addresses); - + /** * Delegates to {@link #withAddressesWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO}. */ EmailPopulatingBuilder toAddressesWithFixedName(@Nullable String name, @NotNull InternetAddress @NotNull ...addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO}. */ @SuppressWarnings("unused") EmailPopulatingBuilder toAddressesWithDefaultName(@NotNull String name, @NotNull InternetAddress @NotNull ...addresses); - + /** * Delegates to {@link #withAddressesWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO}. */ EmailPopulatingBuilder toAddressesWithFixedName(@Nullable String name, @NotNull Collection addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#TO}. */ @SuppressWarnings("unused") EmailPopulatingBuilder toAddressesWithDefaultName(@NotNull String name, @NotNull Collection addresses); - + /** * Delegates to {@link #withRecipients(Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC}. */ EmailPopulatingBuilder cc(@NotNull Recipient @NotNull ...recipients); - + /** * Delegates to {@link #withRecipients(Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC}. */ EmailPopulatingBuilder cc(@NotNull Collection recipients); - + /** * Delegates to {@link #withRecipients(String, boolean, Collection, Message.RecipientType)}, with recipientType={@link Message.RecipientType#CC} * and fixedName=true assigning or overwriting existing names with the provided name. @@ -589,7 +588,7 @@ public interface EmailPopulatingBuilder { * */ EmailPopulatingBuilder cc(@Nullable String name, String oneOrMoreAddresses); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC} and empty default name. * @@ -603,116 +602,116 @@ public interface EmailPopulatingBuilder { */ @Cli.ExcludeApi(reason = "API is subset of another API method") EmailPopulatingBuilder cc(@NotNull String oneOrMoreAddresses); - + /** * Alias for {@link #ccWithFixedName(String, String...)}. */ EmailPopulatingBuilder cc(@Nullable String name, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Alias for {@link #ccWithFixedName(String, Collection)}. */ EmailPopulatingBuilder cc(@Nullable String name, @NotNull Collection oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC} and empty default name. */ @SuppressWarnings("UnusedReturnValue") EmailPopulatingBuilder ccMultiple(@NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder ccAddresses(@NotNull Collection oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC}. */ EmailPopulatingBuilder ccWithFixedName(@Nullable String name, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC}. */ EmailPopulatingBuilder ccWithDefaultName(@NotNull String name, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC}. */ EmailPopulatingBuilder ccWithFixedName(@Nullable String name, @NotNull Collection oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC}. */ @SuppressWarnings("unused") EmailPopulatingBuilder ccWithDefaultName(@NotNull String name, @NotNull Collection oneOrMoreAddressesEach); - + /** * Alias for {@link #ccAddressesWithFixedName(String, InternetAddress...)}. */ EmailPopulatingBuilder cc(@Nullable String name, InternetAddress address); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC} and empty default name. */ @SuppressWarnings("UnusedReturnValue") EmailPopulatingBuilder cc(@NotNull InternetAddress address); - + /** * Alias for {@link #ccAddressesWithFixedName(String, InternetAddress...)}. */ EmailPopulatingBuilder cc(@Nullable String name, @NotNull InternetAddress @NotNull ...addresses); - + /** * Alias for {@link #ccAddressesWithFixedName(String, Collection)}. */ @SuppressWarnings("unused") EmailPopulatingBuilder ccAddresses(@Nullable String name, @NotNull Collection addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder ccMultiple(@NotNull InternetAddress @NotNull ...addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder ccMultipleAddresses(@NotNull Collection addresses); - + /** * Delegates to {@link #withAddressesWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC}. */ EmailPopulatingBuilder ccAddressesWithFixedName(@Nullable String name, @NotNull InternetAddress @NotNull ...addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC}. */ @SuppressWarnings("unused") EmailPopulatingBuilder ccAddressesWithDefaultName(@NotNull String name, @NotNull InternetAddress @NotNull ...addresses); - + /** * Delegates to {@link #withAddressesWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC}. */ EmailPopulatingBuilder ccAddressesWithFixedName(@Nullable String name, @NotNull Collection addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#CC}. */ @SuppressWarnings("unused") EmailPopulatingBuilder ccAddressesWithDefaultName(@NotNull String name, @NotNull Collection addresses); - + /** * Delegates to {@link #withRecipients(Collection, Message.RecipientType)} with fixedRecipientType={@link Message.RecipientType#BCC}. **/ EmailPopulatingBuilder bcc(@NotNull Recipient @NotNull ...recipients); - + /** * Delegates to {@link #withRecipients(Collection, Message.RecipientType)} with fixedRecipientType={@link Message.RecipientType#BCC}. **/ EmailPopulatingBuilder bcc(@NotNull Collection recipients); - + /** * Delegates to {@link #withRecipients(String, boolean, Collection, Message.RecipientType)}, with recipientType={@link Message.RecipientType#BCC} * and fixedName=true assigning or overwriting existing names with the provided name. @@ -729,7 +728,7 @@ public interface EmailPopulatingBuilder { * */ EmailPopulatingBuilder bcc(@Nullable String name, String oneOrMoreAddresses); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC} and empty default name. * @@ -743,140 +742,140 @@ public interface EmailPopulatingBuilder { */ @Cli.ExcludeApi(reason = "API is subset of another API") EmailPopulatingBuilder bcc(@NotNull String oneOrMoreAddresses); - + /** * Alias for {@link #bccWithFixedName(String, String...)}. */ EmailPopulatingBuilder bcc(@Nullable String name, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Alias for {@link #bccWithFixedName(String, Collection)}. */ EmailPopulatingBuilder bcc(@Nullable String name, @NotNull Collection oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder bccMultiple(@NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder bccAddresses(@NotNull Collection oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC}. */ EmailPopulatingBuilder bccWithFixedName(@Nullable String name, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC}. */ EmailPopulatingBuilder bccWithDefaultName(@NotNull String name, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC}. */ EmailPopulatingBuilder bccWithFixedName(@Nullable String name, @NotNull Collection oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipientsWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC}. */ @SuppressWarnings("unused") EmailPopulatingBuilder bccWithDefaultName(@NotNull String name, @NotNull Collection oneOrMoreAddressesEach); - + /** * Alias for {@link #bccAddressesWithFixedName(String, InternetAddress...)}. */ EmailPopulatingBuilder bcc(@Nullable String name, InternetAddress address); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC} and empty default name. */ @SuppressWarnings("UnusedReturnValue") EmailPopulatingBuilder bcc(@NotNull InternetAddress address); - + /** * Alias for {@link #bccAddressesWithFixedName(String, InternetAddress...)}. */ EmailPopulatingBuilder bcc(@Nullable String name, @NotNull InternetAddress @NotNull ...addresses); - + /** * Alias for {@link #bccAddressesWithFixedName(String, Collection)}. */ @SuppressWarnings("unused") EmailPopulatingBuilder bccAddresses(@Nullable String name, @NotNull Collection addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder bccMultiple(@NotNull InternetAddress @NotNull ...addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC} and empty default name. */ @SuppressWarnings("unused") EmailPopulatingBuilder bccMultipleAddresses(@NotNull Collection addresses); - + /** * Delegates to {@link #withAddressesWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC}. */ EmailPopulatingBuilder bccAddressesWithFixedName(@Nullable String name, @NotNull InternetAddress @NotNull ...addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC}. */ @SuppressWarnings("unused") EmailPopulatingBuilder bccAddressesWithDefaultName(@NotNull String name, @NotNull InternetAddress @NotNull ...addresses); - + /** * Delegates to {@link #withAddressesWithFixedName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC}. */ EmailPopulatingBuilder bccAddressesWithFixedName(@Nullable String name, @NotNull Collection addresses); - + /** * Delegates to {@link #withAddressesWithDefaultName(String, Collection, Message.RecipientType)} with recipientType={@link Message.RecipientType#BCC}. */ @SuppressWarnings("unused") EmailPopulatingBuilder bccAddressesWithDefaultName(@NotNull String name, @NotNull Collection addresses); - + /** * Delegates to {@link #withRecipients(String, boolean, Collection, Message.RecipientType)}, leaving existing names intact and defaulting when missing. */ @NotNull EmailPopulatingBuilder withRecipientsWithDefaultName(@Nullable String defaultName, @NotNull Collection oneOrMoreAddressesEach, @Nullable Message.RecipientType recipientType); - + /** * Delegates to {@link #withRecipients(String, boolean, Collection, Message.RecipientType)}, with fixedName=true * assigning or overwriting existing names with the provided name. */ @NotNull EmailPopulatingBuilder withRecipientsWithFixedName(@Nullable String fixedName, @NotNull Collection oneOrMoreAddressesEach, @Nullable Message.RecipientType recipientType); - + /** * Delegates to {@link #withRecipients(String, boolean, Collection, Message.RecipientType)}. */ @NotNull @SuppressWarnings("unused") EmailPopulatingBuilder withRecipientsWithDefaultName(@Nullable String name, @Nullable Message.RecipientType recipientType, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipients(String, boolean, Collection, Message.RecipientType)}. */ @NotNull @SuppressWarnings("unused") EmailPopulatingBuilder withRecipientsWithFixedName(@Nullable String name, @Nullable Message.RecipientType recipientType, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipients(String, boolean, Collection, Message.RecipientType)}. */ @NotNull @SuppressWarnings("unused") EmailPopulatingBuilder withRecipients(@Nullable String name, boolean fixedName, @Nullable Message.RecipientType recipientType, @NotNull String @NotNull ...oneOrMoreAddressesEach); - + /** * Delegates to {@link #withRecipient(Recipient)} for each address found in not just the collection, but also in every individual address string * that is in the collection. @@ -892,20 +891,20 @@ public interface EmailPopulatingBuilder { */ @NotNull EmailPopulatingBuilder withRecipients(@Nullable String name, boolean fixedName, @NotNull Collection oneOrMoreAddressesEach, @Nullable Message.RecipientType recipientType); - + /** * Delegates to {@link #withAddresses(String, boolean, Collection, Message.RecipientType)}, leaving existing names intact and defaulting when missing. */ @NotNull EmailPopulatingBuilder withAddressesWithDefaultName(@Nullable String defaultName, @NotNull Collection addresses, @Nullable Message.RecipientType recipientType); - + /** * Delegates to {@link #withAddresses(String, boolean, Collection, Message.RecipientType)}, with fixedName=true * assigning or overwriting existing names with the provided name. */ @NotNull EmailPopulatingBuilder withAddressesWithFixedName(@Nullable String fixedName, @NotNull Collection addresses, @Nullable Message.RecipientType recipientType); - + /** * Delegates to {@link #withRecipient(String, String, Message.RecipientType)} for each address in the provided collection. * @@ -913,19 +912,19 @@ public interface EmailPopulatingBuilder { */ @NotNull EmailPopulatingBuilder withAddresses(@Nullable String name, boolean fixedName, @NotNull Collection addresses, @Nullable Message.RecipientType recipientType); - + /** * Delegates to {@link #withRecipients(Collection, Message.RecipientType)} with {@link Message.RecipientType} left empty (so it will use the original values). */ @SuppressWarnings("UnusedReturnValue") EmailPopulatingBuilder withRecipients(@NotNull Collection recipients); - + /** * Delegates to {@link #withRecipients(Collection, Message.RecipientType)} with {@link Message.RecipientType} left empty (so it will use the original values). */ @SuppressWarnings("unused") EmailPopulatingBuilder withRecipients(@NotNull Recipient @NotNull ...recipients); - + /** * Delegates to {@link #withRecipient(String, String, Message.RecipientType)} for each recipient in the provided collection, optionally fixing the * recipientType for all recipients to the provided type. @@ -934,18 +933,18 @@ public interface EmailPopulatingBuilder { */ @NotNull EmailPopulatingBuilder withRecipients(@NotNull Collection recipients, @Nullable Message.RecipientType fixedRecipientType); - + /** * Delegates to {@link #withRecipient(String, String, Message.RecipientType)} with the name omitted. */ @SuppressWarnings("unused") EmailPopulatingBuilder withRecipient(@NotNull String singleAddress, @Nullable Message.RecipientType recipientType); - + /** * Delegates to {@link #withRecipient(String, boolean, String, Message.RecipientType)} with the name omitted and fixedName = true. */ EmailPopulatingBuilder withRecipient(@Nullable String name, @NotNull String singleAddress, @Nullable Message.RecipientType recipientType); - + /** * Adds a new {@link Recipient} instance with the given name, address and {@link Message.RecipientType}. *

@@ -959,7 +958,7 @@ public interface EmailPopulatingBuilder { * replyTo, from etc. */ EmailPopulatingBuilder withRecipient(@Nullable String name, boolean fixedName, @NotNull String singleAddress, @Nullable Message.RecipientType recipientType); - + /** * Adds a new {@link Recipient} instance as copy of the provided recipient (copying name, address and {@link Message.RecipientType}). *

@@ -1100,7 +1099,7 @@ public interface EmailPopulatingBuilder { * @param embeddedImageAutoResolutionMustBeSuccesful Whether auto resolution is enforced and bubbles up failure to do so. */ EmailPopulatingBuilder embeddedImageAutoResolutionMustBeSuccesful(final boolean embeddedImageAutoResolutionMustBeSuccesful); - + /** * Delegates to {@link #withEmbeddedImage(String, DataSource)}, with a named {@link ByteArrayDataSource} created using the provided name, data and * mimetype. @@ -1110,7 +1109,7 @@ public interface EmailPopulatingBuilder { * @param mimetype The content type of the given data (e.g. "image/gif" or "image/jpeg"). */ EmailPopulatingBuilder withEmbeddedImage(@NotNull String name, byte@NotNull[] data, @NotNull String mimetype); - + /** * Adds image data to this email that can be referred to from the email HTML body. For adding images as attachment, refer to {@link * #withAttachment(String, DataSource)} instead. @@ -1126,12 +1125,12 @@ public interface EmailPopulatingBuilder { * @see EmailPopulatingBuilder#withEmbeddedImages(List) */ EmailPopulatingBuilder withEmbeddedImage(@Nullable String name, @NotNull DataSource imagedata); - + /** * Delegates to {@link #withEmbeddedImage(String, DataSource)} for each embedded image. */ EmailPopulatingBuilder withEmbeddedImages(@NotNull List embeddedImages); - + /** * Delegates to {@link #withHeader(String, Object)} for each header in the provided {@code Map}. */ @@ -1181,7 +1180,7 @@ public interface EmailPopulatingBuilder { * @see #withAttachments(List) */ EmailPopulatingBuilder withAttachment(@Nullable String name, byte@NotNull[] data, @NotNull String mimetype, @Nullable String description, @Nullable ContentTransferEncoding contentTransferEncoding); - + /** * Delegates to {@link #withAttachment(String, DataSource, String, ContentTransferEncoding)} with null-description and no forced content transfer encoding. * @@ -1251,82 +1250,42 @@ public interface EmailPopulatingBuilder { @Cli.ExcludeApi(reason = "delegated method is an identical api from CLI point of view") @SuppressWarnings("unused") EmailPopulatingBuilder signWithDomainKey(@NotNull DkimConfig dkimConfig); - - /** - * Signs this email with an S/MIME signature, so the receiving client - * can verify whether the email content was tampered with. - *

- * Note: this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}.
- * Note: You can also configure your Mailer instance do sign all emails by default (also has better performance). - * - * @see S/MIME on Wikipedia - * @see Primer on S/MIME - */ - @Cli.ExcludeApi(reason = "delegated method contains CLI compatible arguments") - EmailPopulatingBuilder signWithSmime(@NotNull Pkcs12Config pkcs12Config); /** - * Delegates to {@link #signWithSmime(InputStream, String, String, String)}. + * Delegates to {@link #signWithSmime(SmimeSigningConfig)}. *

* Note: this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}. * * @param pkcs12StoreFile The key store file to use to find the indicated key * @param storePassword The store's password - * @param keyAlias The name of the certificate in the key store to use - * @param keyPassword The password of the certificate - */ - EmailPopulatingBuilder signWithSmime(@NotNull File pkcs12StoreFile, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword); - - /** - * Delegates to {@link #signWithSmime(byte[], String, String, String)}. - *

- * Note: this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}. - */ - @Cli.ExcludeApi(reason = "Is duplicate API from CLI point of view") - EmailPopulatingBuilder signWithSmime(@NotNull InputStream pkcs12StoreStream, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword); - - /** - * Delegates to {@link #signWithSmime(Pkcs12Config)}. - *

- * Note: this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}. - * - * @param pkcs12StoreData The key store file to use to find the indicated key - * @param storePassword The store's password - * @param keyAlias The name of the certificate in the key store to use - * @param keyPassword The password of the certificate - */ - @Cli.ExcludeApi(reason = "Is duplicate API from CLI point of view") - EmailPopulatingBuilder signWithSmime(byte@NotNull[] pkcs12StoreData, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword); + * @param keyAlias The name of the certificate in the key store to use + * @param keyPassword The password of the certificate + * @see SmimeSigningConfig + */ + EmailPopulatingBuilder signWithSmime(@NotNull File pkcs12StoreFile, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword, @Nullable String signatureAlgorithm); /** - * Delegates to {@link #encryptWithSmime(X509Certificate)} using the provided PEM file. - *

- * Note: this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}. - * - * @param pemStream A PEM encoded file that will be read as X509Certificate. - */ - @Cli.ExcludeApi(reason = "Is duplicate API from CLI point of view") - EmailPopulatingBuilder encryptWithSmime(@NotNull InputStream pemStream); - - /** - * Delegates to {@link #encryptWithSmime(InputStream)} using the provided PEM file. + * Signs this email with an S/MIME signature, so the receiving client + * can verify whether the email content was tampered with. *

- * Note: this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}. + * Note: this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}.
+ * Note: You can also configure your Mailer instance do sign all emails by default (also has better performance). * - * @param pemFile A PEM encoded file that will be read as X509Certificate. + * @see S/MIME on Wikipedia + * @see Primer on S/MIME + * @see SmimeSigningConfig */ - @Cli.ExcludeApi(reason = "Is duplicate API from CLI point of view") - EmailPopulatingBuilder encryptWithSmime(@NotNull String pemFile); + @Cli.ExcludeApi(reason = "delegated method contains CLI compatible arguments") + EmailPopulatingBuilder signWithSmime(@NotNull SmimeSigningConfig smimeSigningConfig); /** - * Delegates to {@link #encryptWithSmime(InputStream)} using the provided PEM file. + * Delegates to {@link #encryptWithSmime(SmimeEncryptionConfig)} using the provided PEM file. *

* Note: this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}. * - * @param pemFile A PEM encoded file that will be read as X509Certificate. + * @see SmimeEncryptionConfig */ - @Cli.ExcludeApi(reason = "Is duplicate API from CLI point of view") - EmailPopulatingBuilder encryptWithSmime(@NotNull File pemFile); + EmailPopulatingBuilder encryptWithSmime(@NotNull File pemFile, @Nullable String keyEncapsulationAlgorithm, @Nullable String cipherAlgorithm); /** * Encrypts this email with a X509 certificate according to the S/MIME spec @@ -1337,13 +1296,16 @@ public interface EmailPopulatingBuilder { *

* Note: this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}. * - * @param x509Certificate The recipient's public key to use for encryption. + * @param smimeEncryptionConfig The recipient's public key to use for encryption. * * @see S/MIME on Wikipedia * @see Primer on S/MIME * @see Underlying library's documentation + * + * @see SmimeEncryptionConfig */ - EmailPopulatingBuilder encryptWithSmime(@NotNull X509Certificate x509Certificate); + @Cli.ExcludeApi(reason = "delegated method contains CLI compatible arguments") + EmailPopulatingBuilder encryptWithSmime(@NotNull SmimeEncryptionConfig smimeEncryptionConfig); /** * When the S/MIME module is loaded, S/MIME signed / encrypted attachments are decrypted and kept in a separate list. However, @@ -1364,7 +1326,7 @@ public interface EmailPopulatingBuilder { */ @Cli.OptionNameOverride("withDispositionNotificationToEnabled") EmailPopulatingBuilder withDispositionNotificationTo(); - + /** * Delegates to {@link #withDispositionNotificationTo(Recipient)} with a new {@link Recipient} wrapped around the provided address. * @@ -1372,7 +1334,7 @@ public interface EmailPopulatingBuilder { */ @Cli.ExcludeApi(reason = "API is subset of another API") EmailPopulatingBuilder withDispositionNotificationTo(@NotNull String address); - + /** * Delegates to {@link #withDispositionNotificationTo(Recipient)} with a new {@link Recipient} wrapped around the provided name and address. * @@ -1381,19 +1343,19 @@ public interface EmailPopulatingBuilder { */ @SuppressWarnings("unused") EmailPopulatingBuilder withDispositionNotificationTo(@Nullable String name, @NotNull String address); - + /** * Delegates to {@link #withDispositionNotificationTo(Recipient)} with a new {@link Recipient} wrapped around the provided address. */ @SuppressWarnings("UnusedReturnValue") EmailPopulatingBuilder withDispositionNotificationTo(@NotNull InternetAddress address); - + /** * Delegates to {@link #withDispositionNotificationTo(Recipient)} with a new {@link Recipient} wrapped around the provided fixed name and address. */ @SuppressWarnings("unused") EmailPopulatingBuilder withDispositionNotificationTo(@Nullable String fixedName, @NotNull InternetAddress address); - + /** * Indicates this email should use the NPM flag "Disposition-Notification-To" with the given * preconfigred {@link Recipient}. This flag can be used to request a return receipt from the recipient to signal that the recipient has read the @@ -1406,7 +1368,7 @@ public interface EmailPopulatingBuilder { * @see #withDispositionNotificationTo(String, String) */ EmailPopulatingBuilder withDispositionNotificationTo(@NotNull Recipient recipient); - + /** * Indicates that we want to use the flag {@code returnReceiptTo}. The actual address will default to the {@code replyToRecipient} first if set * or else {@code fromRecipient} (the final address is determined when sending the email). @@ -1415,7 +1377,7 @@ public interface EmailPopulatingBuilder { */ @Cli.OptionNameOverride("withReturnReceiptToEnabled") EmailPopulatingBuilder withReturnReceiptTo(); - + /** * Delegates to {@link #withReturnReceiptTo(Recipient)} with a new {@link Recipient} wrapped around the provided address. * @@ -1423,7 +1385,7 @@ public interface EmailPopulatingBuilder { */ @Cli.ExcludeApi(reason = "API is subset of another API") EmailPopulatingBuilder withReturnReceiptTo(@NotNull String address); - + /** * Delegates to {@link #withReturnReceiptTo(Recipient)} with a new {@link Recipient} wrapped around the provided name and address. * @@ -1431,13 +1393,13 @@ public interface EmailPopulatingBuilder { * @param address The address of the receiver of the receipt notification */ EmailPopulatingBuilder withReturnReceiptTo(@Nullable String name, @NotNull String address); - + /** * Delegates to {@link #withReturnReceiptTo(Recipient)} with a new {@link Recipient} wrapped around the provided address. */ @SuppressWarnings("UnusedReturnValue") EmailPopulatingBuilder withReturnReceiptTo(@NotNull InternetAddress address); - + /** * Delegates to {@link #withReturnReceiptTo(Recipient)} with a new {@link Recipient} wrapped around the provided fixed name and address. */ @@ -1481,30 +1443,30 @@ public interface EmailPopulatingBuilder { */ @SuppressWarnings("unused") EmailPopulatingBuilder clearId(); - + /** * Resets fromRecipient to empty. */ @SuppressWarnings("unused") EmailPopulatingBuilder clearFromRecipient(); - + /** * Resets replyToRecipients to empty. */ @SuppressWarnings("unused") EmailPopulatingBuilder clearReplyTo(); - + /** * Resets bounceToRecipient to empty. */ @SuppressWarnings("UnusedReturnValue") EmailPopulatingBuilder clearBounceTo(); - + /** * Resets text to empty. */ EmailPopulatingBuilder clearPlainText(); - + /** * Resets textHTML to empty. */ @@ -1519,13 +1481,13 @@ public interface EmailPopulatingBuilder { * Resets contentTransferEncoding to {@link ContentTransferEncoding#QUOTED_PRINTABLE}. */ EmailPopulatingBuilder clearContentTransferEncoding(); - + /** * Resets subject to empty. */ @SuppressWarnings("unused") EmailPopulatingBuilder clearSubject(); - + /** * Resets recipients to empty. */ @@ -1559,13 +1521,13 @@ public interface EmailPopulatingBuilder { */ @SuppressWarnings("unused") EmailPopulatingBuilder clearEmbeddedImages(); - + /** * Resets attachments to empty. */ @SuppressWarnings("unused") EmailPopulatingBuilder clearAttachments(); - + /** * Resets headers to empty. */ @@ -1585,18 +1547,18 @@ public interface EmailPopulatingBuilder { *

* Note: this only works in combination with the {@value org.simplejavamail.internal.modules.SMIMEModule#NAME}. * - * @see #signWithSmime(Pkcs12Config) - * @see #encryptWithSmime(X509Certificate) + * @see #signWithSmime(SmimeSigningConfig) + * @see #encryptWithSmime(SmimeEncryptionConfig) */ @SuppressWarnings("unused") EmailPopulatingBuilder clearSmime(); - + /** * Resets dispositionNotificationTo to empty. */ @SuppressWarnings("unused") EmailPopulatingBuilder clearDispositionNotificationTo(); - + /** * Resets returnReceiptTo to empty. */ @@ -1646,37 +1608,37 @@ public interface EmailPopulatingBuilder { */ @Nullable String getId(); - + /** * @see #from(Recipient) */ @Nullable Recipient getFromRecipient(); - + /** * @see #withReplyTo(Recipient) */ @NotNull List getReplyToRecipients(); - + /** * @see #withBounceTo(Recipient) */ @Nullable Recipient getBounceToRecipient(); - + /** * @see #withPlainText(String) */ @Nullable String getText(); - + /** * @see #withHTMLText(String) */ @Nullable String getTextHTML(); - + /** * @see #withCalendarText(CalendarMethod, String) */ @@ -1695,13 +1657,13 @@ public interface EmailPopulatingBuilder { */ @Nullable ContentTransferEncoding getContentTransferEncoding(); - + /** * @see #withSubject(String) */ @Nullable String getSubject(); - + /** * @see #to(Recipient...) * @see #cc(Recipient...) @@ -1709,13 +1671,13 @@ public interface EmailPopulatingBuilder { */ @NotNull List getRecipients(); - + /** * @see #withEmbeddedImage(String, DataSource) */ @NotNull List getEmbeddedImages(); - + /** * @see #withAttachment(String, DataSource) */ @@ -1738,28 +1700,28 @@ public interface EmailPopulatingBuilder { */ @NotNull Map> getHeaders(); - + /** * @see #signWithDomainKey(DkimConfig) * @see #signWithDomainKey(byte[], String, String, Set) */ @Nullable DkimConfig getDkimConfig(); - + /** * @see #withDispositionNotificationTo() * @see #withDispositionNotificationTo(Recipient) */ @Nullable Boolean getUseDispositionNotificationTo(); - + /** * @see #withDispositionNotificationTo() * @see #withDispositionNotificationTo(Recipient) */ @Nullable Recipient getDispositionNotificationTo(); - + /** * @see #withReturnReceiptTo() * @see #withReturnReceiptTo(Recipient) @@ -1779,7 +1741,7 @@ public interface EmailPopulatingBuilder { */ @NotNull List getOverrideReceivers(); - + /** * @see EmailStartingBuilder#forwarding(MimeMessage) */ @@ -1815,18 +1777,18 @@ public interface EmailPopulatingBuilder { boolean isMergeSingleSMIMESignedAttachment(); /** - * @see EmailPopulatingBuilder#signWithSmime(Pkcs12Config) - * @see EmailPopulatingBuilder#signWithSmime(InputStream, String, String, String) + * @see EmailPopulatingBuilder#signWithSmime(SmimeSigningConfig) + * @see EmailPopulatingBuilder#signWithSmime(File, String, String, String, String) */ @Nullable - Pkcs12Config getPkcs12ConfigForSmimeSigning(); + SmimeSigningConfig getSmimeSigningConfig(); /** - * @see EmailPopulatingBuilder#encryptWithSmime(X509Certificate) - * @see EmailPopulatingBuilder#encryptWithSmime(InputStream) + * @see EmailPopulatingBuilder#encryptWithSmime(SmimeEncryptionConfig) + * @see EmailPopulatingBuilder#encryptWithSmime(File, String, String) */ @Nullable - X509Certificate getX509CertificateForSmimeEncryption(); + SmimeEncryptionConfig getSmimeEncryptionConfig(); /** * @see EmailPopulatingBuilder#fixingSentDate(Date) diff --git a/modules/core-module/src/main/java/org/simplejavamail/api/email/EqualsHelper.java b/modules/core-module/src/main/java/org/simplejavamail/api/email/EqualsHelper.java index 637fdefe9..2c3547691 100644 --- a/modules/core-module/src/main/java/org/simplejavamail/api/email/EqualsHelper.java +++ b/modules/core-module/src/main/java/org/simplejavamail/api/email/EqualsHelper.java @@ -89,10 +89,10 @@ public static boolean equalsEmail(final Email email1, final Email email2) { if (!fieldIsEqual(email1.getOriginalSmimeDetails(), email2.getOriginalSmimeDetails(), "originalSmimeDetails")) { return false; } - if (!fieldIsEqual(email1.getPkcs12ConfigForSmimeSigning(), email2.getPkcs12ConfigForSmimeSigning(), "pkcs12ConfigForSmimeSigning")) { + if (!fieldIsEqual(email1.getSmimeSigningConfig(), email2.getSmimeSigningConfig(), "smimeSigningConfig")) { return false; } - if (!fieldIsEqual(email1.getX509CertificateForSmimeEncryption(), email2.getX509CertificateForSmimeEncryption(), "x509CertificateForSmimeEncryption")) { + if (!fieldIsEqual(email1.getSmimeEncryptionConfig(), email2.getSmimeEncryptionConfig(), "smimeEncryptionConfig")) { return false; } return fieldIsEqual(email1.getReturnReceiptTo(), email2.getReturnReceiptTo(), "returnReceiptTo"); diff --git a/modules/core-module/src/main/java/org/simplejavamail/api/email/config/SmimeEncryptionConfig.java b/modules/core-module/src/main/java/org/simplejavamail/api/email/config/SmimeEncryptionConfig.java new file mode 100644 index 000000000..d0895a27b --- /dev/null +++ b/modules/core-module/src/main/java/org/simplejavamail/api/email/config/SmimeEncryptionConfig.java @@ -0,0 +1,172 @@ +package org.simplejavamail.api.email.config; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.simplejavamail.api.email.EmailPopulatingBuilder; +import org.simplejavamail.internal.util.CertificationUtil; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.Serializable; +import java.security.NoSuchProviderException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import static java.lang.String.format; + +@ToString +@Getter +@EqualsAndHashCode +@AllArgsConstructor +public class SmimeEncryptionConfig implements Serializable { + + private static final long serialVersionUID = 1234567L; + + @NotNull + final X509Certificate x509Certificate; + /** + * Configuration for S/MIME encryption, specifying the key encapsulation algorithm used for securing + * the encryption key. This setting is crucial for the security of the encrypted message, ensuring that + * the encryption key itself is transmitted securely and can only be accessed by the intended recipient. + * + *

Default Algorithm: RSA. Selected for broad compatibility and historical reasons, + * RSA without OAEP padding is the default. However, for enhanced security, it's recommended to use RSA + * with OAEP padding and SHA-256 or higher.

+ * + *

Recommended Algorithms: The use of RSA with OAEP padding is advised due to its + * improved security properties over plain RSA. Algorithms with SHA-256 or higher offer a stronger level + * of security and are recommended for most applications:

+ * + * + * + *

Refer to {@code org.simplejavamail.utils.mail.smime.KeyEncapsulationAlgorithm} for the most current + * list of supported algorithms.

+ * + *

Note: While the default RSA is widely compatible, the move towards RSA with OAEP padding + * is encouraged to ensure a higher level of security against modern cryptographic attacks. The choice of SHA-256 + * or higher as the hashing algorithm for OAEP provides a good balance between security and performance.

+ */ + @Nullable + final String keyEncapsulationAlgorithm; + + /** + * Configuration for S/MIME encryption, specifying the algorithm used for encrypting the email content. + * The choice of encryption algorithm impacts both the security of the encrypted message and its compatibility. + * + *

Default Algorithm: DES_EDE3_CBC. While this is provided for broad compatibility, + * it's recommended to use AES-based algorithms for enhanced security.

+ * + *

Recommended Encryption Algorithms: The following list focuses on secure and commonly + * used algorithms for S/MIME encryption. Note that AES is preferred due to its strong security features and + * performance efficiency. For a complete and updated list, consult the Bouncy Castle documentation. For a complete + * list of supported algorithms, refer to the Bouncy Castle's {@code see org.bouncycastle.cms.CMSAlgorithm} class.

+ * + * + * + *

Note: While DES_EDE3_CBC is supported for backward compatibility, AES (128, 192, 256) + * is strongly recommended for new applications due to its enhanced security and efficiency.

+ */ + @Nullable + final String cipherAlgorithm; + + public static SmimeEncryptionConfigBuilder builder() { + return new SmimeEncryptionConfigBuilder(); + } + + @ToString + public static class SmimeEncryptionConfigBuilder { + private X509Certificate x509Certificate; + private String keyEncapsulationAlgorithm; + private String cipherAlgorithm; + + /** + * @see EmailPopulatingBuilder#encryptWithSmime(SmimeEncryptionConfig) + * @see EmailPopulatingBuilder#encryptWithSmime(File, String, String) + */ + public SmimeEncryptionConfigBuilder x509Certificate(@NotNull final X509Certificate x509Certificate) { + this.x509Certificate = x509Certificate; + return this; + } + + /** + * Delegates to {@link #x509Certificate(InputStream)}. + */ + @SuppressFBWarnings(value = "OBL_UNSATISFIED_OBLIGATION", justification = "Input stream being created should not be closed here") + public SmimeEncryptionConfigBuilder x509Certificate(@NotNull final String pemFile) { + try { + return x509Certificate(new FileInputStream(pemFile)); + } catch (FileNotFoundException e) { + throw new IllegalStateException(format("Error reading from file: %s", pemFile), e); + } + } + + /** + * Delegates to {@link #x509Certificate(InputStream)}, + */ + @SuppressFBWarnings(value = "OBL_UNSATISFIED_OBLIGATION", justification = "Input stream being created should not be closed here") + public SmimeEncryptionConfigBuilder x509Certificate(@NotNull final File pemFile) { + try { + return x509Certificate(new FileInputStream(pemFile)); + } catch (FileNotFoundException e) { + throw new IllegalStateException(format("Error reading from file: %s", pemFile), e); + } + } + + /** + * Delegates to {@link #x509Certificate(X509Certificate)}. + */ + public SmimeEncryptionConfigBuilder x509Certificate(@NotNull final InputStream pemStream) { + try { + return x509Certificate(CertificationUtil.readFromPem(pemStream)); + } catch (CertificateException e) { + throw new IllegalStateException("Was unable to convert PEM data to X509 certificate", e); + } catch (NoSuchProviderException e) { + throw new IllegalStateException("Unable to load certificate (missing bouncy castle), is the S/MIME module on the class path?", e); + } + } + + /** + * For detailed information, see {@link SmimeEncryptionConfig#keyEncapsulationAlgorithm}. + * + * @see EmailPopulatingBuilder#encryptWithSmime(SmimeEncryptionConfig) + * @see EmailPopulatingBuilder#encryptWithSmime(File, String, String) + */ + public SmimeEncryptionConfigBuilder keyEncapsulationAlgorithm(@Nullable String keyEncapsulationAlgorithm) { + this.keyEncapsulationAlgorithm = keyEncapsulationAlgorithm; + return this; + } + + /** + * For detailed information, see {@link SmimeEncryptionConfig#cipherAlgorithm}. + * + * @see EmailPopulatingBuilder#encryptWithSmime(SmimeEncryptionConfig) + * @see EmailPopulatingBuilder#encryptWithSmime(File, String, String) + */ + public SmimeEncryptionConfigBuilder cipherAlgorithm(@Nullable String cipherAlgorithm) { + this.cipherAlgorithm = cipherAlgorithm; + return this; + } + + public SmimeEncryptionConfig build() { + return new SmimeEncryptionConfig(this.x509Certificate, this.keyEncapsulationAlgorithm, this.cipherAlgorithm); + } + } +} \ No newline at end of file diff --git a/modules/core-module/src/main/java/org/simplejavamail/api/email/config/SmimeSigningConfig.java b/modules/core-module/src/main/java/org/simplejavamail/api/email/config/SmimeSigningConfig.java new file mode 100644 index 000000000..81c62c32e --- /dev/null +++ b/modules/core-module/src/main/java/org/simplejavamail/api/email/config/SmimeSigningConfig.java @@ -0,0 +1,148 @@ +package org.simplejavamail.api.email.config; + +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.simplejavamail.api.email.EmailPopulatingBuilder; +import org.simplejavamail.api.mailer.config.Pkcs12Config; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +import static java.lang.String.format; +import static org.simplejavamail.internal.util.MiscUtil.readInputStreamToBytes; + +@ToString +@Getter +@EqualsAndHashCode +@AllArgsConstructor +public class SmimeSigningConfig { + + /** + * @see EmailPopulatingBuilder#signWithSmime(SmimeSigningConfig) + * @see EmailPopulatingBuilder#signWithSmime(File, String, String, String, String) + */ + @NotNull + private final Pkcs12Config pkcs12Config; + /** + *

Configuration for S/MIME signing, including the certificate chain and private key information, + * along with the signature algorithm. The choice of signature algorithm affects the security + * and compatibility of the S/MIME signature.

+ * + *

Default Algorithm: SHA256withRSA. This is widely supported and recommended + * for most use cases due to its balance of security and performance.

+ * + *

Allowed Signature Algorithms: This following list focuses on the most commonly used + * and secure algorithms. Algorithms like MD5 and SHA1 are not included due to their known security + * vulnerabilities and are not recommended for new applications. For a comprehensive and up-to-date + * list, including less common algorithms, refer to the Bouncy Castle's {@code DefaultSignatureAlgorithmIdentifierFinder} + * class to find an exhaustive list.

+ * + * + * + * @see EmailPopulatingBuilder#signWithSmime(SmimeSigningConfig) + * @see EmailPopulatingBuilder#signWithSmime(File, String, String, String, String) + */ + @Nullable + private final String signatureAlgorithm; + + public static SmimeSigningConfigBuilder builder() { + return new SmimeSigningConfigBuilder(); + } + + @ToString + public static class SmimeSigningConfigBuilder { + private Pkcs12Config pkcs12Config; + private String signatureAlgorithm; + + /** + * @see EmailPopulatingBuilder#signWithSmime(SmimeSigningConfig) + * @see EmailPopulatingBuilder#signWithSmime(File, String, String, String, String) + */ + public SmimeSigningConfigBuilder pkcs12Config(@NotNull Pkcs12Config pkcs12Config) { + this.pkcs12Config = pkcs12Config; + return this; + } + + /** + * Delegates to {@link #pkcs12Config(InputStream, String, String, String)}. + */ + @SuppressFBWarnings(value = "OBL_UNSATISFIED_OBLIGATION", justification = "Input stream being created should not be closed here") + public SmimeSigningConfigBuilder pkcs12Config(@NotNull File pkcs12StoreFile, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword) { + try { + return pkcs12Config(new FileInputStream(pkcs12StoreFile), storePassword, keyAlias, keyPassword); + } catch (IOException e) { + throw new IllegalStateException(format("Error reading from file: %s", pkcs12StoreFile), e); + } + } + + /** + * Delegates to {@link #pkcs12Config(byte[], String, String, String)}. + */ + public SmimeSigningConfigBuilder pkcs12Config(@NotNull InputStream pkcs12StoreStream, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword) { + final byte[] pkcs12StoreData; + try { + pkcs12StoreData = readInputStreamToBytes(pkcs12StoreStream); + } catch (IOException e) { + throw new IllegalStateException("Was unable to read S/MIME data from input stream", e); + } + return pkcs12Config(pkcs12StoreData, storePassword, keyAlias, keyPassword); + } + + /** + * Delegates to {@link #pkcs12Config(Pkcs12Config)}. + */ + public SmimeSigningConfigBuilder pkcs12Config(byte @NotNull [] pkcs12StoreData, @NotNull String storePassword, @NotNull String keyAlias, @NotNull String keyPassword) { + return pkcs12Config(Pkcs12Config.builder() + .pkcs12Store(pkcs12StoreData) + .storePassword(storePassword) + .keyAlias(keyAlias) + .keyPassword(keyPassword) + .build()); + } + + /** + * For detailed information, see {@link SmimeSigningConfig#signatureAlgorithm}. + * + * @see EmailPopulatingBuilder#signWithSmime(SmimeSigningConfig) + * @see EmailPopulatingBuilder#signWithSmime(File, String, String, String, String) + */ + public SmimeSigningConfigBuilder signatureAlgorithm(@Nullable String signatureAlgorithm) { + this.signatureAlgorithm = signatureAlgorithm; + return this; + } + + public SmimeSigningConfig build() { + return new SmimeSigningConfig(this.pkcs12Config, this.signatureAlgorithm); + } + } +} \ No newline at end of file diff --git a/modules/core-module/src/main/java/org/simplejavamail/internal/config/EmailProperty.java b/modules/core-module/src/main/java/org/simplejavamail/internal/config/EmailProperty.java index ed1863427..a600cd79b 100644 --- a/modules/core-module/src/main/java/org/simplejavamail/internal/config/EmailProperty.java +++ b/modules/core-module/src/main/java/org/simplejavamail/internal/config/EmailProperty.java @@ -37,8 +37,8 @@ public enum EmailProperty { CC_RECIPIENTS(Email::getCcRecipients, true), BCC_RECIPIENTS(Email::getBccRecipients, true), OVERRIDE_RECEIVERS(Email::getOverrideReceivers, true), - SMIME_SIGNING_CONFIG(Email::getPkcs12ConfigForSmimeSigning, false), - SMIME_ENCRYPTION_CONFIG(Email::getX509CertificateForSmimeEncryption, false), + SMIME_SIGNING_CONFIG(Email::getSmimeSigningConfig, false), + SMIME_ENCRYPTION_CONFIG(Email::getSmimeEncryptionConfig, false), DKIM_SIGNING_CONFIG(Email::getDkimConfig, false), SENT_DATE(Email::getSentDate, false), ID(Email::getId, false), diff --git a/modules/core-module/src/main/java/org/simplejavamail/internal/modules/SMIMEModule.java b/modules/core-module/src/main/java/org/simplejavamail/internal/modules/SMIMEModule.java index a5501fac2..4105c1afb 100644 --- a/modules/core-module/src/main/java/org/simplejavamail/internal/modules/SMIMEModule.java +++ b/modules/core-module/src/main/java/org/simplejavamail/internal/modules/SMIMEModule.java @@ -8,13 +8,14 @@ import org.simplejavamail.api.email.AttachmentResource; import org.simplejavamail.api.email.Email; import org.simplejavamail.api.email.OriginalSmimeDetails; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.api.internal.outlooksupport.model.OutlookMessage; import org.simplejavamail.api.internal.smimesupport.builder.SmimeParseResult; import org.simplejavamail.api.internal.smimesupport.model.AttachmentDecryptionResult; import org.simplejavamail.api.internal.smimesupport.model.SmimeDetails; import org.simplejavamail.api.mailer.config.Pkcs12Config; -import java.security.cert.X509Certificate; import java.util.List; /** @@ -70,10 +71,10 @@ public interface SMIMEModule { boolean verifyValidSignature(@NotNull MimeMessage mimeMessage, @NotNull OriginalSmimeDetails messageSmimeDetails); @NotNull - MimeMessage signMessageWithSmime(@NotNull Session session, @NotNull final Email email, @NotNull MimeMessage messageToProtect, @NotNull Pkcs12Config pkcs12Config); + MimeMessage signMessageWithSmime(@NotNull Session session, @NotNull final Email email, @NotNull MimeMessage messageToProtect, @NotNull SmimeSigningConfig smimeSigningConfig); @NotNull - MimeMessage encryptMessageWithSmime(@NotNull Session session, @NotNull final Email email, @NotNull MimeMessage messageToProtect, @NotNull X509Certificate x509Certificate); + MimeMessage encryptMessageWithSmime(@NotNull Session session, @NotNull final Email email, @NotNull MimeMessage messageToProtect, @NotNull SmimeEncryptionConfig smimeEncryptionConfig); /** * @return Whether the email has been properly wrapped in a MimeMessage subtype that overrides Message-ID. This is to diff --git a/modules/core-module/src/main/java/org/simplejavamail/internal/util/MiscUtil.java b/modules/core-module/src/main/java/org/simplejavamail/internal/util/MiscUtil.java index 920a8b947..cae174b5f 100644 --- a/modules/core-module/src/main/java/org/simplejavamail/internal/util/MiscUtil.java +++ b/modules/core-module/src/main/java/org/simplejavamail/internal/util/MiscUtil.java @@ -180,7 +180,7 @@ public static Recipient interpretRecipient(@Nullable final String name, boolean @Nullable public static T defaultTo(@Nullable final T value, @Nullable final T defaultValue) { - return value != null ? value : defaultValue; + return ofNullable(value).orElse(defaultValue); } public static boolean classAvailable(@NotNull String className) { diff --git a/modules/simple-java-mail/src/main/java/org/simplejavamail/converter/EmailConverter.java b/modules/simple-java-mail/src/main/java/org/simplejavamail/converter/EmailConverter.java index 7dcf2b0d9..32b02be30 100644 --- a/modules/simple-java-mail/src/main/java/org/simplejavamail/converter/EmailConverter.java +++ b/modules/simple-java-mail/src/main/java/org/simplejavamail/converter/EmailConverter.java @@ -7,7 +7,11 @@ import lombok.val; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.simplejavamail.api.email.*; +import org.simplejavamail.api.email.CalendarMethod; +import org.simplejavamail.api.email.ContentTransferEncoding; +import org.simplejavamail.api.email.Email; +import org.simplejavamail.api.email.EmailPopulatingBuilder; +import org.simplejavamail.api.email.OriginalSmimeDetails; import org.simplejavamail.api.email.OriginalSmimeDetails.SmimeMode; import org.simplejavamail.api.internal.general.HeadersToIgnoreWhenParsingExternalEmails; import org.simplejavamail.api.internal.outlooksupport.model.EmailFromOutlookMessage; @@ -27,7 +31,15 @@ import org.simplejavamail.internal.moduleloader.ModuleLoader; import org.simplejavamail.internal.smimesupport.model.OriginalSmimeDetailsImpl; -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; import java.util.Map; import java.util.Properties; @@ -35,7 +47,9 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.simplejavamail.api.email.OriginalSmimeDetails.SmimeMode.PLAIN; import static org.simplejavamail.internal.moduleloader.ModuleLoader.loadSmimeModule; -import static org.simplejavamail.internal.util.MiscUtil.*; +import static org.simplejavamail.internal.util.MiscUtil.extractCID; +import static org.simplejavamail.internal.util.MiscUtil.readInputStreamToString; +import static org.simplejavamail.internal.util.MiscUtil.valueNullOrEmpty; import static org.simplejavamail.internal.util.Preconditions.checkNonEmptyArgument; import static org.simplejavamail.internal.util.Preconditions.verifyNonnullOrEmpty; import static org.simplejavamail.mailer.internal.EmailGovernanceImpl.NO_GOVERNANCE; @@ -232,6 +246,7 @@ private static EmailPopulatingBuilder decryptAttachments(final EmailPopulatingBu return emailBuilder; } + @NotNull private static EmailPopulatingBuilder decryptAttachments(final EmailPopulatingBuilder emailBuilder, final MimeMessage mimeMessage, @Nullable final Pkcs12Config pkcs12Config) { if (ModuleLoader.smimeModuleAvailable()) { SmimeParseResult smimeParseResult = loadSmimeModule().decryptAttachments(emailBuilder.getAttachments(), mimeMessage, pkcs12Config); diff --git a/modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/SpecializedMimeMessageProducer.java b/modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/SpecializedMimeMessageProducer.java index 33dd585ee..46294ffa9 100644 --- a/modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/SpecializedMimeMessageProducer.java +++ b/modules/simple-java-mail/src/main/java/org/simplejavamail/converter/internal/mimemessage/SpecializedMimeMessageProducer.java @@ -62,12 +62,12 @@ final MimeMessage populateMimeMessage(@NotNull final Email email, @NotNull Sessi 3. DKIM signing */ - if (email.getPkcs12ConfigForSmimeSigning() != null) { - message = ModuleLoader.loadSmimeModule().signMessageWithSmime(session, email, message, email.getPkcs12ConfigForSmimeSigning()); + if (email.getSmimeSigningConfig() != null) { + message = ModuleLoader.loadSmimeModule().signMessageWithSmime(session, email, message, email.getSmimeSigningConfig()); } - if (email.getX509CertificateForSmimeEncryption() != null) { - message = ModuleLoader.loadSmimeModule().encryptMessageWithSmime(session, email, message, email.getX509CertificateForSmimeEncryption()); + if (email.getSmimeEncryptionConfig() != null) { + message = ModuleLoader.loadSmimeModule().encryptMessageWithSmime(session, email, message, email.getSmimeEncryptionConfig()); } if (email.getDkimConfig() != null) { diff --git a/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailException.java b/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailException.java index b270bc7f8..ea24fd451 100644 --- a/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailException.java +++ b/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailException.java @@ -7,20 +7,17 @@ */ @SuppressWarnings("serial") class EmailException extends MailException { - - static final String NAME_MISSING_FOR_EMBEDDED_IMAGE = "No name given for embedded image nor passed inside the data source"; - static final String ERROR_READING_FROM_FILE = "Error reading from file: %s"; - static final String ERROR_READING_SMIME_FROM_INPUTSTREAM = "Was unable to read S/MIME data from input stream"; - static final String ERROR_READING_FROM_PEM_INPUTSTREAM = "Was unable to convert PEM data to X509 certificate"; - static final String ERROR_LOADING_PROVIDER_FOR_SMIME_SUPPORT = "Unable to load certificate (missing bouncy castle), is the S/MIME module on the class path?"; - static final String ERROR_RESOLVING_IMAGE_DATASOURCE = "Unable to dynamically resolve data source for the following image src: %s"; - static final String ERROR_PARSING_URL = "Unable to parse URL: %s"; - EmailException(@SuppressWarnings("SameParameterValue") final String message) { - super(message); - } - - EmailException(@SuppressWarnings("SameParameterValue") final String message, final Exception cause) { - super(message, cause); - } + static final String NAME_MISSING_FOR_EMBEDDED_IMAGE = "No name given for embedded image nor passed inside the data source"; + static final String ERROR_READING_FROM_FILE = "Error reading from file: %s"; + static final String ERROR_RESOLVING_IMAGE_DATASOURCE = "Unable to dynamically resolve data source for the following image src: %s"; + static final String ERROR_PARSING_URL = "Unable to parse URL: %s"; + + EmailException(@SuppressWarnings("SameParameterValue") final String message) { + super(message); + } + + EmailException(@SuppressWarnings("SameParameterValue") final String message, final Exception cause) { + super(message, cause); + } } \ No newline at end of file diff --git a/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl.java b/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl.java index 0997a0795..96843b709 100644 --- a/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl.java +++ b/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl.java @@ -18,28 +18,22 @@ import org.simplejavamail.api.email.OriginalSmimeDetails; import org.simplejavamail.api.email.Recipient; import org.simplejavamail.api.email.config.DkimConfig; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.api.internal.clisupport.model.Cli; import org.simplejavamail.api.internal.smimesupport.model.PlainSmimeDetails; import org.simplejavamail.api.mailer.config.EmailGovernance; -import org.simplejavamail.api.mailer.config.Pkcs12Config; import org.simplejavamail.email.EmailBuilder; import org.simplejavamail.internal.config.EmailProperty; import org.simplejavamail.internal.moduleloader.ModuleLoader; -import org.simplejavamail.internal.util.CertificationUtil; import org.simplejavamail.internal.util.FileUtil; import org.simplejavamail.internal.util.MiscUtil; import org.simplejavamail.internal.util.NamedDataSource; import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; -import java.security.NoSuchProviderException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -71,18 +65,14 @@ import static org.simplejavamail.config.ConfigLoader.getBooleanProperty; import static org.simplejavamail.config.ConfigLoader.getStringProperty; import static org.simplejavamail.config.ConfigLoader.hasProperty; -import static org.simplejavamail.email.internal.EmailException.ERROR_LOADING_PROVIDER_FOR_SMIME_SUPPORT; import static org.simplejavamail.email.internal.EmailException.ERROR_PARSING_URL; import static org.simplejavamail.email.internal.EmailException.ERROR_READING_FROM_FILE; -import static org.simplejavamail.email.internal.EmailException.ERROR_READING_FROM_PEM_INPUTSTREAM; -import static org.simplejavamail.email.internal.EmailException.ERROR_READING_SMIME_FROM_INPUTSTREAM; import static org.simplejavamail.email.internal.EmailException.ERROR_RESOLVING_IMAGE_DATASOURCE; import static org.simplejavamail.email.internal.EmailException.NAME_MISSING_FOR_EMBEDDED_IMAGE; import static org.simplejavamail.internal.util.MiscUtil.defaultTo; import static org.simplejavamail.internal.util.MiscUtil.extractEmailAddresses; import static org.simplejavamail.internal.util.MiscUtil.interpretRecipient; import static org.simplejavamail.internal.util.MiscUtil.randomCid10; -import static org.simplejavamail.internal.util.MiscUtil.readInputStreamToBytes; import static org.simplejavamail.internal.util.MiscUtil.tryResolveFileDataSourceFromClassPath; import static org.simplejavamail.internal.util.MiscUtil.tryResolveImageFileDataSourceFromDisk; import static org.simplejavamail.internal.util.MiscUtil.tryResolveUrlDataSource; @@ -266,22 +256,22 @@ public class EmailPopulatingBuilderImpl implements InternalEmailPopulatingBuilde private DkimConfig dkimConfig; /** - * @see #signWithSmime(Pkcs12Config) - * @see #signWithSmime(InputStream, String, String, String) - * @see #encryptWithSmime(X509Certificate) - * @see #encryptWithSmime(InputStream) + * @see #signWithSmime(SmimeSigningConfig) + * @see #signWithSmime(File, String, String, String, String) + * @see #encryptWithSmime(SmimeEncryptionConfig) + * @see #encryptWithSmime(File, String, String) */ @Nullable - private Pkcs12Config pkcs12ConfigForSmimeSigning; + private SmimeSigningConfig smimeSigningConfig; /** - * @see #encryptWithSmime(X509Certificate) - * @see #encryptWithSmime(InputStream) - * @see #signWithSmime(Pkcs12Config) - * @see #signWithSmime(InputStream, String, String, String) + * @see #encryptWithSmime(SmimeEncryptionConfig) + * @see #encryptWithSmime(File, String, String) + * @see #signWithSmime(SmimeSigningConfig) + * @see #signWithSmime(File, String, String, String, String) */ @Nullable - private X509Certificate x509CertificateForSmimeEncryption; + private SmimeEncryptionConfig smimeEncryptionConfig; /** * @see #withDispositionNotificationTo() @@ -1864,110 +1854,45 @@ public EmailPopulatingBuilder signWithDomainKey(final byte@NotNull[] dkimPrivate * @param keyAlias The key we need for signing * @param keyPassword The password for the key * - * @see EmailPopulatingBuilder#signWithSmime(File, String, String, String) + * @see EmailPopulatingBuilder#signWithSmime(File, String, String, String, String) */ @Override @SuppressFBWarnings(value = "OBL_UNSATISFIED_OBLIGATION", justification = "Input stream being created should not be closed here") - public EmailPopulatingBuilder signWithSmime(@NotNull final File pkcs12StoreFile, @NotNull final String storePassword, @NotNull final String keyAlias, @NotNull final String keyPassword) { - try { - return signWithSmime(new FileInputStream(pkcs12StoreFile), storePassword, keyAlias, keyPassword); - } catch (IOException e) { - throw new EmailException(format(ERROR_READING_FROM_FILE, pkcs12StoreFile), e); - } - } - - /** - * @param pkcs12StoreStream The data (file) input stream containing the keystore - * @param storePassword The password to get keys from the store - * @param keyAlias The key we need for signing - * @param keyPassword The password for the key - * - * @see EmailPopulatingBuilder#signWithSmime(InputStream, String, String, String) - */ - @Override - public EmailPopulatingBuilder signWithSmime(@NotNull final InputStream pkcs12StoreStream, @NotNull final String storePassword, @NotNull final String keyAlias, @NotNull final String keyPassword) { - final byte[] pkcs12StoreData; - try { - pkcs12StoreData = readInputStreamToBytes(pkcs12StoreStream); - } catch (IOException e) { - throw new EmailException(ERROR_READING_SMIME_FROM_INPUTSTREAM, e); - } - return signWithSmime(pkcs12StoreData, storePassword, keyAlias, keyPassword); - } - - /** - * @param pkcs12StoreData The data (file) input stream containing the keystore - * @param storePassword The password to get keys from the store - * @param keyAlias The key we need for signing - * @param keyPassword The password for the key - * - * @see EmailPopulatingBuilder#signWithSmime(InputStream, String, String, String) - */ - @Override - public EmailPopulatingBuilder signWithSmime(final byte@NotNull[] pkcs12StoreData, @NotNull final String storePassword, @NotNull final String keyAlias, @NotNull final String keyPassword) { - return signWithSmime(Pkcs12Config.builder() - .pkcs12Store(pkcs12StoreData) - .storePassword(storePassword) - .keyAlias(keyAlias) - .keyPassword(keyPassword) + public EmailPopulatingBuilder signWithSmime(@NotNull final File pkcs12StoreFile, @NotNull final String storePassword, @NotNull final String keyAlias, @NotNull final String keyPassword, @Nullable final String signatureAlgorithm) { + return signWithSmime(SmimeSigningConfig.builder() + .pkcs12Config(pkcs12StoreFile, storePassword, keyAlias, keyPassword) + .signatureAlgorithm(signatureAlgorithm) .build()); } /** - * @see EmailPopulatingBuilder#signWithSmime(Pkcs12Config) + * @see EmailPopulatingBuilder#signWithSmime(SmimeSigningConfig) */ @Override - public EmailPopulatingBuilder signWithSmime(@NotNull final Pkcs12Config pkcs12Config) { - this.pkcs12ConfigForSmimeSigning = pkcs12Config; + public EmailPopulatingBuilder signWithSmime(@NotNull final SmimeSigningConfig smimeSigningConfig) { + this.smimeSigningConfig = smimeSigningConfig; return this; } /** - * @see EmailPopulatingBuilder#encryptWithSmime(String) - */ - @Override - @SuppressFBWarnings(value = "OBL_UNSATISFIED_OBLIGATION", justification = "Input stream being created should not be closed here") - public EmailPopulatingBuilder encryptWithSmime(@NotNull final String pemFile) { - try { - return encryptWithSmime(new FileInputStream(pemFile)); - } catch (FileNotFoundException e) { - throw new EmailException(format(ERROR_READING_FROM_FILE, pemFile), e); - } - } - - /** - * @see EmailPopulatingBuilder#encryptWithSmime(File) + * @see EmailPopulatingBuilder#encryptWithSmime(File, String, String) */ @Override @SuppressFBWarnings(value = "OBL_UNSATISFIED_OBLIGATION", justification = "Input stream being created should not be closed here") - public EmailPopulatingBuilder encryptWithSmime(@NotNull final File pemFile) { - try { - return encryptWithSmime(new FileInputStream(pemFile)); - } catch (FileNotFoundException e) { - throw new EmailException(format(ERROR_READING_FROM_FILE, pemFile), e); - } - } - - /** - * @see EmailPopulatingBuilder#encryptWithSmime(InputStream) - */ - @Override - public EmailPopulatingBuilder encryptWithSmime(@NotNull final InputStream pemStream) { - try { - return encryptWithSmime(CertificationUtil.readFromPem(pemStream)); - } catch (CertificateException e) { - throw new EmailException(ERROR_READING_FROM_PEM_INPUTSTREAM, e); - } catch (NoSuchProviderException e) { - throw new EmailException(ERROR_LOADING_PROVIDER_FOR_SMIME_SUPPORT, e); - } + public EmailPopulatingBuilder encryptWithSmime(@NotNull final File pemFile, @Nullable final String keyEncapsulationAlgorithm, @Nullable final String cipherAlgorithm) { + return encryptWithSmime(SmimeEncryptionConfig.builder() + .x509Certificate(pemFile) + .keyEncapsulationAlgorithm(keyEncapsulationAlgorithm) + .cipherAlgorithm(cipherAlgorithm) + .build()); } /** - * @see EmailPopulatingBuilder#encryptWithSmime(X509Certificate) + * @see EmailPopulatingBuilder#encryptWithSmime(SmimeEncryptionConfig) */ @Override - public EmailPopulatingBuilder encryptWithSmime(@NotNull final X509Certificate x509Certificate) { - this.x509CertificateForSmimeEncryption = x509Certificate; + public EmailPopulatingBuilder encryptWithSmime(@NotNull final SmimeEncryptionConfig smimeEncryptionConfig) { + this.smimeEncryptionConfig = smimeEncryptionConfig; return this; } @@ -2311,8 +2236,8 @@ public EmailPopulatingBuilder clearDkim() { */ @Override public EmailPopulatingBuilder clearSmime() { - this.pkcs12ConfigForSmimeSigning = null; - this.x509CertificateForSmimeEncryption = null; + this.smimeSigningConfig = null; + this.smimeEncryptionConfig = null; return this; } @@ -2617,21 +2542,21 @@ public boolean isMergeSingleSMIMESignedAttachment() { } /** - * @see EmailPopulatingBuilder#getPkcs12ConfigForSmimeSigning() + * @see EmailPopulatingBuilder#getSmimeSigningConfig() */ @Override @Nullable - public Pkcs12Config getPkcs12ConfigForSmimeSigning() { - return pkcs12ConfigForSmimeSigning; + public SmimeSigningConfig getSmimeSigningConfig() { + return smimeSigningConfig; } /** - * @see EmailPopulatingBuilder#getX509CertificateForSmimeEncryption() + * @see EmailPopulatingBuilder#getSmimeEncryptionConfig() */ @Override @Nullable - public X509Certificate getX509CertificateForSmimeEncryption() { - return x509CertificateForSmimeEncryption; + public SmimeEncryptionConfig getSmimeEncryptionConfig() { + return smimeEncryptionConfig; } /** diff --git a/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailStartingBuilderImpl.java b/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailStartingBuilderImpl.java index 650c222ac..eca5b3673 100644 --- a/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailStartingBuilderImpl.java +++ b/modules/simple-java-mail/src/main/java/org/simplejavamail/email/internal/EmailStartingBuilderImpl.java @@ -230,11 +230,11 @@ public EmailPopulatingBuilder copying(@NotNull final Email email) { if (email.getSentDate() != null) { builder.fixingSentDate(email.getSentDate()); } - if (email.getPkcs12ConfigForSmimeSigning() != null) { - builder.signWithSmime(email.getPkcs12ConfigForSmimeSigning()); + if (email.getSmimeSigningConfig() != null) { + builder.signWithSmime(email.getSmimeSigningConfig()); } - if (email.getX509CertificateForSmimeEncryption() != null) { - builder.encryptWithSmime(email.getX509CertificateForSmimeEncryption()); + if (email.getSmimeEncryptionConfig() != null) { + builder.encryptWithSmime(email.getSmimeEncryptionConfig()); } if (email.getDkimConfig() != null) { builder.signWithDomainKey(email.getDkimConfig()); diff --git a/modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/MailerHelper.java b/modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/MailerHelper.java index 2f4eb78aa..de666b969 100644 --- a/modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/MailerHelper.java +++ b/modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/MailerHelper.java @@ -12,11 +12,11 @@ import org.simplejavamail.api.email.Email; import org.simplejavamail.api.email.Recipient; import org.simplejavamail.api.email.config.DkimConfig; -import org.simplejavamail.api.mailer.config.Pkcs12Config; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.internal.moduleloader.ModuleLoader; import org.slf4j.Logger; -import java.security.cert.X509Certificate; import java.util.Collection; import java.util.Map; @@ -255,14 +255,14 @@ public static MimeMessage signMessageWithDKIM(@NotNull final MimeMessage message /** * Depending on the Email configuration, signs and then encrypts message (both steps optional), using the S/MIME module. * - * @see org.simplejavamail.internal.modules.SMIMEModule#signMessageWithSmime(Session, Email, MimeMessage, Pkcs12Config) - * @see org.simplejavamail.internal.modules.SMIMEModule#encryptMessageWithSmime(Session, Email, MimeMessage, X509Certificate) + * @see org.simplejavamail.internal.modules.SMIMEModule#signMessageWithSmime(Session, Email, MimeMessage, SmimeSigningConfig) + * @see org.simplejavamail.internal.modules.SMIMEModule#encryptMessageWithSmime(Session, Email, MimeMessage, SmimeEncryptionConfig) */ @SuppressWarnings("unused") public static MimeMessage signAndOrEncryptMessageWithSmime(@NotNull final Session session, @NotNull final MimeMessage messageToProtect, @NotNull final Email emailContainingSmimeDetails) { MimeMessage message = messageToProtect; - message = ModuleLoader.loadSmimeModule().signMessageWithSmime(session, emailContainingSmimeDetails, message, requireNonNull(emailContainingSmimeDetails.getPkcs12ConfigForSmimeSigning(), "Pkcs12Config")); - message = ModuleLoader.loadSmimeModule().encryptMessageWithSmime(session, emailContainingSmimeDetails, message, requireNonNull(emailContainingSmimeDetails.getX509CertificateForSmimeEncryption(), "X509Certificate")); + message = ModuleLoader.loadSmimeModule().signMessageWithSmime(session, emailContainingSmimeDetails, message, requireNonNull(emailContainingSmimeDetails.getSmimeSigningConfig(), "SmimeSigningConfig")); + message = ModuleLoader.loadSmimeModule().encryptMessageWithSmime(session, emailContainingSmimeDetails, message, requireNonNull(emailContainingSmimeDetails.getSmimeEncryptionConfig(), "SmimeEncryptionConfig")); return message; } } \ No newline at end of file diff --git a/modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/internal/EmailGovernanceImpl.java b/modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/internal/EmailGovernanceImpl.java index 4d2304b80..e00c9229c 100644 --- a/modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/internal/EmailGovernanceImpl.java +++ b/modules/simple-java-mail/src/main/java/org/simplejavamail/mailer/internal/EmailGovernanceImpl.java @@ -13,6 +13,8 @@ import org.simplejavamail.api.email.EmailPopulatingBuilder; import org.simplejavamail.api.email.Recipient; import org.simplejavamail.api.email.config.DkimConfig; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.api.mailer.MailerGenericBuilder; import org.simplejavamail.api.mailer.config.EmailGovernance; import org.simplejavamail.api.mailer.config.Pkcs12Config; @@ -21,7 +23,6 @@ import org.simplejavamail.internal.config.EmailProperty; import java.io.File; -import java.security.cert.X509Certificate; import java.util.Collection; import java.util.Date; import java.util.List; @@ -49,6 +50,9 @@ import static org.simplejavamail.config.ConfigLoader.Property.DKIM_SELECTOR; import static org.simplejavamail.config.ConfigLoader.Property.DKIM_SIGNING_DOMAIN; import static org.simplejavamail.config.ConfigLoader.Property.SMIME_ENCRYPTION_CERTIFICATE; +import static org.simplejavamail.config.ConfigLoader.Property.SMIME_ENCRYPTION_CIPHER; +import static org.simplejavamail.config.ConfigLoader.Property.SMIME_ENCRYPTION_KEY_ENCAPSULATION_ALGORITHM; +import static org.simplejavamail.config.ConfigLoader.Property.SMIME_SIGNING_ALGORITHM; import static org.simplejavamail.config.ConfigLoader.Property.SMIME_SIGNING_KEYSTORE; import static org.simplejavamail.config.ConfigLoader.Property.SMIME_SIGNING_KEYSTORE_PASSWORD; import static org.simplejavamail.config.ConfigLoader.Property.SMIME_SIGNING_KEY_ALIAS; @@ -158,16 +162,23 @@ private Email newDefaultsEmailWithDefaultDefaults() { allDefaults.withSubject(getProperty(DEFAULT_SUBJECT)); } - if (allDefaults.getPkcs12ConfigForSmimeSigning() == null && hasProperty(SMIME_SIGNING_KEYSTORE)) { - allDefaults.signWithSmime(Pkcs12Config.builder() - .pkcs12Store(verifyNonnullOrEmpty(getStringProperty(SMIME_SIGNING_KEYSTORE))) - .storePassword(checkNonEmptyArgument(getStringProperty(SMIME_SIGNING_KEYSTORE_PASSWORD), "Keystore password property")) - .keyAlias(checkNonEmptyArgument(getStringProperty(SMIME_SIGNING_KEY_ALIAS), "Key alias property")) - .keyPassword(checkNonEmptyArgument(getStringProperty(SMIME_SIGNING_KEY_PASSWORD), "Key password property")) + if (allDefaults.getSmimeSignedEmail() == null && hasProperty(SMIME_SIGNING_KEYSTORE)) { + allDefaults.signWithSmime(SmimeSigningConfig.builder() + .pkcs12Config(Pkcs12Config.builder() + .pkcs12Store(verifyNonnullOrEmpty(getStringProperty(SMIME_SIGNING_KEYSTORE))) + .storePassword(checkNonEmptyArgument(getStringProperty(SMIME_SIGNING_KEYSTORE_PASSWORD), "Keystore password property")) + .keyAlias(checkNonEmptyArgument(getStringProperty(SMIME_SIGNING_KEY_ALIAS), "Key alias property")) + .keyPassword(checkNonEmptyArgument(getStringProperty(SMIME_SIGNING_KEY_PASSWORD), "Key password property")) + .build()) + .signatureAlgorithm(hasProperty(SMIME_SIGNING_ALGORITHM) ? getStringProperty(SMIME_SIGNING_ALGORITHM) : null) .build()); } - if (allDefaults.getX509CertificateForSmimeEncryption() == null && hasProperty(SMIME_ENCRYPTION_CERTIFICATE)) { - allDefaults.encryptWithSmime(verifyNonnullOrEmpty(getStringProperty(SMIME_ENCRYPTION_CERTIFICATE))); + if (allDefaults.getSmimeEncryptionConfig() == null && hasProperty(SMIME_ENCRYPTION_CERTIFICATE)) { + allDefaults.encryptWithSmime(SmimeEncryptionConfig.builder() + .x509Certificate(verifyNonnullOrEmpty(getStringProperty(SMIME_ENCRYPTION_CERTIFICATE))) + .keyEncapsulationAlgorithm(hasProperty(SMIME_ENCRYPTION_KEY_ENCAPSULATION_ALGORITHM) ? getStringProperty(SMIME_ENCRYPTION_KEY_ENCAPSULATION_ALGORITHM) : null) + .cipherAlgorithm(hasProperty(SMIME_ENCRYPTION_CIPHER) ? getStringProperty(SMIME_ENCRYPTION_CIPHER) : null) + .build()); } if (allDefaults.getDkimConfig() == null && hasProperty(DKIM_PRIVATE_KEY_FILE_OR_DATA)) { val dkimConfigBuilder = DkimConfig.builder() @@ -245,8 +256,8 @@ public Email produceEmailApplyingDefaultsAndOverrides(@Nullable Email provided) builder.withOverrideReceivers(overrideReceivers); } ofNullable(this.resolveEmailProperty(provided, EmailProperty.CONTENT_TRANSFER_ENCODING)).ifPresent(builder::withContentTransferEncoding); - ofNullable(this.resolveEmailProperty(provided, EmailProperty.SMIME_SIGNING_CONFIG)).ifPresent(builder::signWithSmime); - ofNullable(this.resolveEmailProperty(provided, EmailProperty.SMIME_ENCRYPTION_CONFIG)).ifPresent(builder::encryptWithSmime); + ofNullable(this.resolveEmailProperty(provided, EmailProperty.SMIME_SIGNING_CONFIG)).ifPresent(builder::signWithSmime); + ofNullable(this.resolveEmailProperty(provided, EmailProperty.SMIME_ENCRYPTION_CONFIG)).ifPresent(builder::encryptWithSmime); ofNullable(this.resolveEmailProperty(provided, EmailProperty.DKIM_SIGNING_CONFIG)).ifPresent(builder::signWithDomainKey); builder.withBounceTo(this.resolveEmailProperty(provided, EmailProperty.BOUNCETO_RECIPIENT)); ofNullable(this.resolveEmailProperty(provided, EmailProperty.SENT_DATE)).ifPresent(builder::fixingSentDate); diff --git a/modules/simple-java-mail/src/test/java/org/simplejavamail/api/email/EmailTest.java b/modules/simple-java-mail/src/test/java/org/simplejavamail/api/email/EmailTest.java index a97fe8d2b..3adc254a8 100644 --- a/modules/simple-java-mail/src/test/java/org/simplejavamail/api/email/EmailTest.java +++ b/modules/simple-java-mail/src/test/java/org/simplejavamail/api/email/EmailTest.java @@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull; import org.junit.Before; import org.junit.Test; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.api.mailer.config.Pkcs12Config; import org.simplejavamail.email.EmailBuilder; import org.simplejavamail.internal.util.NamedDataSource; @@ -301,12 +302,12 @@ public void testEqualsEmail_EqualityAttachments() throws IOException { @Test public void testEqualsEmail_EqualityPkcs12Config() { - final Pkcs12Config pkcs12KeyStore = loadPkcs12KeyStore(); - final Pkcs12Config pkcs12KeyStoreOther = Pkcs12Config.builder() + final SmimeSigningConfig pkcs12KeyStore = SmimeSigningConfig.builder().pkcs12Config(loadPkcs12KeyStore()).build(); + final SmimeSigningConfig pkcs12KeyStoreOther = SmimeSigningConfig.builder().pkcs12Config(Pkcs12Config.builder() .pkcs12Store("src/test/resources/pkcs12/smime_keystore.pkcs12") .storePassword("password") .keyAlias("alias") - .keyPassword("password").build(); + .keyPassword("password").build()).build();; assertEmailEqual(b().signWithSmime(pkcs12KeyStore).buildEmail(), b().signWithSmime(pkcs12KeyStore).buildEmail(), true); assertEmailEqual(b().signWithSmime(pkcs12KeyStore).buildEmail(), b().signWithSmime(pkcs12KeyStoreOther).buildEmail(), false); assertEmailEqual(b().signWithSmime(pkcs12KeyStore).buildEmail(), b().buildEmail(), false); diff --git a/modules/simple-java-mail/src/test/java/org/simplejavamail/config/ConfigLoaderTest.java b/modules/simple-java-mail/src/test/java/org/simplejavamail/config/ConfigLoaderTest.java index 377ea8eff..6cd3ebfad 100644 --- a/modules/simple-java-mail/src/test/java/org/simplejavamail/config/ConfigLoaderTest.java +++ b/modules/simple-java-mail/src/test/java/org/simplejavamail/config/ConfigLoaderTest.java @@ -204,7 +204,7 @@ public void loadPropertiesFromFileClassPath() { assertThat(ConfigLoader.getProperty(SMIME_SIGNING_KEYSTORE)).isEqualTo("src/test/resources/pkcs12/smime_keystore.pkcs12"); assertThat(ConfigLoader.getProperty(SMIME_SIGNING_KEYSTORE_PASSWORD)).isEqualTo("letmein"); - assertThat(ConfigLoader.getProperty(SMIME_SIGNING_KEY_ALIAS)).isEqualTo("smime_test_user_alias"); + assertThat(ConfigLoader.getProperty(SMIME_SIGNING_KEY_ALIAS)).isEqualTo("smime_test_user_alias_rsa"); assertThat(ConfigLoader.getProperty(SMIME_SIGNING_KEY_PASSWORD)).isEqualTo("letmein"); assertThat(ConfigLoader.getProperty(SMIME_ENCRYPTION_CERTIFICATE)).isEqualTo("src/test/resources/pkcs12/smime_test_user.pem.standard.crt"); diff --git a/modules/simple-java-mail/src/test/java/org/simplejavamail/converter/EmailConverterTest.java b/modules/simple-java-mail/src/test/java/org/simplejavamail/converter/EmailConverterTest.java index b6f8b867a..47b340634 100644 --- a/modules/simple-java-mail/src/test/java/org/simplejavamail/converter/EmailConverterTest.java +++ b/modules/simple-java-mail/src/test/java/org/simplejavamail/converter/EmailConverterTest.java @@ -362,8 +362,8 @@ public void testGithub486_InvalidSignedOutlookMessage() { assertThat(emailMime.getUseDispositionNotificationTo()).isEqualTo(emailOutlook.getUseDispositionNotificationTo()); assertThat(emailMime.getUseReturnReceiptTo()).isEqualTo(emailOutlook.getUseReturnReceiptTo()); assertThat(emailMime.getDispositionNotificationTo()).isEqualTo(emailOutlook.getDispositionNotificationTo()); - assertThat(emailMime.getPkcs12ConfigForSmimeSigning()).isEqualTo(emailOutlook.getPkcs12ConfigForSmimeSigning()); - assertThat(emailMime.getX509CertificateForSmimeEncryption()).isEqualTo(emailOutlook.getX509CertificateForSmimeEncryption()); + assertThat(emailMime.getSmimeSigningConfig()).isEqualTo(emailOutlook.getSmimeSigningConfig()); + assertThat(emailMime.getSmimeEncryptionConfig()).isEqualTo(emailOutlook.getSmimeEncryptionConfig()); assertThat(emailMime.getReturnReceiptTo()).isEqualTo(emailOutlook.getReturnReceiptTo()); } diff --git a/modules/simple-java-mail/src/test/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl1Test.java b/modules/simple-java-mail/src/test/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl1Test.java index 74b7887f3..013a5de00 100644 --- a/modules/simple-java-mail/src/test/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl1Test.java +++ b/modules/simple-java-mail/src/test/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl1Test.java @@ -13,6 +13,8 @@ import org.simplejavamail.api.email.EmailPopulatingBuilder; import org.simplejavamail.api.email.Recipient; import org.simplejavamail.api.email.config.DkimConfig; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.email.EmailBuilder; import testutil.ConfigLoaderTestHelper; import testutil.EmailHelper; @@ -25,11 +27,8 @@ import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; -import java.security.cert.X509Certificate; -import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.Arrays; -import java.util.HashMap; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -1213,7 +1212,7 @@ private void verifyEmbeddedImage(final Email email, String expectedContainsWithC } @Test - public void testClearingValues() throws IOException { + public void testClearingValues() { EmailPopulatingBuilder emailBuilder = EmailHelper.createDummyEmailBuilder("", true, false, true, true, true, false, false) .notMergingSingleSMIMESignedAttachment() .signWithDomainKey(DkimConfig.builder() @@ -1221,8 +1220,10 @@ public void testClearingValues() throws IOException { .dkimSigningDomain("dkim_domain") .dkimSelector("dkim_selector") .build()) - .signWithSmime(new ByteArrayInputStream(new byte[]{}), "storePassword", "keyAlias", "keyPassword") - .encryptWithSmime(mock(X509Certificate.class)); + .signWithSmime(SmimeSigningConfig.builder() + .pkcs12Config(new ByteArrayInputStream(new byte[]{}), "storePassword", "keyAlias", "keyPassword") + .build()) + .encryptWithSmime(mock(SmimeEncryptionConfig.class)); assertThat(emailBuilder.isMergeSingleSMIMESignedAttachment()).isFalse(); @@ -1246,8 +1247,8 @@ public void testClearingValues() throws IOException { assertThat(emailNormal.getReplyToRecipients()).isNotEmpty(); assertThat(emailNormal.getReturnReceiptTo()).isNotNull(); assertThat(emailNormal.getSentDate()).isNotNull(); - assertThat(emailNormal.getPkcs12ConfigForSmimeSigning()).isNotNull(); - assertThat(emailNormal.getX509CertificateForSmimeEncryption()).isNotNull(); + assertThat(emailNormal.getSmimeSigningConfig()).isNotNull(); + assertThat(emailNormal.getSmimeEncryptionConfig()).isNotNull(); emailBuilder .clearId() @@ -1287,8 +1288,8 @@ public void testClearingValues() throws IOException { assertThat(emailCleared.getReplyToRecipients()).isEmpty(); assertThat(emailCleared.getReturnReceiptTo()).isNull(); assertThat(emailCleared.getSentDate()).isNull(); - assertThat(emailCleared.getPkcs12ConfigForSmimeSigning()).isNull(); - assertThat(emailCleared.getX509CertificateForSmimeEncryption()).isNull(); + assertThat(emailCleared.getSmimeSigningConfig()).isNull(); + assertThat(emailCleared.getSmimeEncryptionConfig()).isNull(); } @Test diff --git a/modules/simple-java-mail/src/test/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl2Test.java b/modules/simple-java-mail/src/test/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl2Test.java index 9d5663f71..9a599c60c 100644 --- a/modules/simple-java-mail/src/test/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl2Test.java +++ b/modules/simple-java-mail/src/test/java/org/simplejavamail/email/internal/EmailPopulatingBuilderImpl2Test.java @@ -8,6 +8,8 @@ import org.simplejavamail.api.email.EmailPopulatingBuilder; import org.simplejavamail.api.email.Recipient; import org.simplejavamail.api.email.config.DkimConfig; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.config.ConfigLoader.Property; import org.simplejavamail.email.EmailBuilder; import org.simplejavamail.internal.util.CertificationUtil; @@ -88,7 +90,7 @@ public void testConstructorApplyingPreconfiguredDefaults1() throws Exception { value.put(DEFAULT_CONTENT_TRANSFER_ENCODING, BASE_64); value.put(SMIME_SIGNING_KEYSTORE, "src/test/resources/pkcs12/smime_keystore.pkcs12"); value.put(SMIME_SIGNING_KEYSTORE_PASSWORD, "letmein"); - value.put(SMIME_SIGNING_KEY_ALIAS, "smime_test_user_alias"); + value.put(SMIME_SIGNING_KEY_ALIAS, "smime_test_user_alias_rsa"); value.put(SMIME_SIGNING_KEY_PASSWORD, "letmein"); value.put(SMIME_ENCRYPTION_CERTIFICATE, "src/test/resources/pkcs12/smime_test_user.pem.standard.crt"); value.put(DKIM_PRIVATE_KEY_FILE_OR_DATA, "src/test/resources/dkim/dkim_dummy_key.der"); @@ -104,8 +106,8 @@ public void testConstructorApplyingPreconfiguredDefaults1() throws Exception { .hasBounceToRecipient(null) .hasNoRecipients() .hasSubject(null) - .hasPkcs12ConfigForSmimeSigning(null) - .hasX509CertificateForSmimeEncryption(null) + .hasSmimeSigningConfig(null) + .hasSmimeEncryptionConfig(null) .hasDkimConfig(null); EmailAssert.assertThat(EmailBuilder.startingBlank().buildEmailCompletedWithDefaultsAndOverrides()) @@ -118,8 +120,12 @@ public void testConstructorApplyingPreconfiguredDefaults1() throws Exception { new Recipient("test BCC name", "test_bcc1@domain.com", BCC), new Recipient("test BCC name", "test_bcc2@domain.com", BCC) ) .hasSubject("test subject") - .hasPkcs12ConfigForSmimeSigning(loadPkcs12KeyStore()) - .hasX509CertificateForSmimeEncryption(CertificationUtil.readFromPem(new File(RESOURCES_PATH + "/pkcs12/smime_test_user.pem.standard.crt"))) + .hasSmimeSigningConfig(SmimeSigningConfig.builder() + .pkcs12Config(loadPkcs12KeyStore()) + .build()) + .hasSmimeEncryptionConfig(SmimeEncryptionConfig.builder() + .x509Certificate(CertificationUtil.readFromPem(new File(RESOURCES_PATH + "/pkcs12/smime_test_user.pem.standard.crt"))) + .build()) .hasDkimConfig(DkimConfig.builder() .dkimPrivateKeyPath(RESOURCES_PATH + "/dkim/dkim_dummy_key.der") .dkimSigningDomain("ignore.com") @@ -146,10 +152,12 @@ public void testConstructorApplyingPreconfiguredDefaults2() throws Exception { .hasNoReplyToRecipients() .hasBounceToRecipient(null) .hasNoRecipients() - .hasX509CertificateForSmimeEncryption(null); + .hasSmimeEncryptionConfig(null); - assertThat(NO_GOVERNANCE().produceEmailApplyingDefaultsAndOverrides(null).getX509CertificateForSmimeEncryption()) - .isEqualTo(CertificationUtil.readFromPem(new File(RESOURCES_PATH + "/pkcs12/smime_test_user.pem.standard.crt"))); + assertThat(NO_GOVERNANCE().produceEmailApplyingDefaultsAndOverrides(null).getSmimeEncryptionConfig()) + .isEqualTo(SmimeEncryptionConfig.builder() + .x509Certificate(CertificationUtil.readFromPem(new File(RESOURCES_PATH + "/pkcs12/smime_test_user.pem.standard.crt"))) + .build()); EmailAssert.assertThat(EmailBuilder.startingBlank().buildEmailCompletedWithDefaultsAndOverrides()) .hasFromRecipient(new Recipient(null, "test_from@domain.com", null)) @@ -160,7 +168,9 @@ public void testConstructorApplyingPreconfiguredDefaults2() throws Exception { new Recipient(null, "test_cc1@domain.com", CC), new Recipient(null, "test_cc2@domain.com", CC), new Recipient(null, "test_bcc1@domain.com", BCC), new Recipient(null, "test_bcc2@domain.com", BCC) ) - .hasX509CertificateForSmimeEncryption(CertificationUtil.readFromPem(new File(RESOURCES_PATH + "/pkcs12/smime_test_user.pem.standard.crt"))); + .hasSmimeEncryptionConfig(SmimeEncryptionConfig.builder() + .x509Certificate(CertificationUtil.readFromPem(new File(RESOURCES_PATH + "/pkcs12/smime_test_user.pem.standard.crt"))) + .build()); } @Test diff --git a/modules/simple-java-mail/src/test/java/org/simplejavamail/internal/smimesupport/SmimeSignAndEncryptTest.java b/modules/simple-java-mail/src/test/java/org/simplejavamail/internal/smimesupport/SmimeSignAndEncryptTest.java index 92dfb2770..d3a642c8c 100644 --- a/modules/simple-java-mail/src/test/java/org/simplejavamail/internal/smimesupport/SmimeSignAndEncryptTest.java +++ b/modules/simple-java-mail/src/test/java/org/simplejavamail/internal/smimesupport/SmimeSignAndEncryptTest.java @@ -6,6 +6,8 @@ import org.junit.Test; import org.simplejavamail.api.email.Email; import org.simplejavamail.api.email.EmailPopulatingBuilder; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.email.EmailBuilder; import org.simplejavamail.internal.util.CertificationUtil; import testutil.ConfigLoaderTestHelper; @@ -32,42 +34,69 @@ public void setup() { builder = EmailBuilder.startingBlank(); } - - @Test public void testSignWithSmime_WithConfigObject() { - builder.signWithSmime(loadPkcs12KeyStore()); + builder.signWithSmime(SmimeSigningConfig.builder() + .pkcs12Config(loadPkcs12KeyStore()) + .build()); final Email email = builder.buildEmail(); - assertThat(email.getPkcs12ConfigForSmimeSigning()).isNotNull(); - assertThat(email.getPkcs12ConfigForSmimeSigning().getPkcs12StoreData()).isNotNull(); - assertThat(email.getPkcs12ConfigForSmimeSigning().getStorePassword()).isEqualTo("letmein".toCharArray()); - assertThat(email.getPkcs12ConfigForSmimeSigning().getKeyAlias()).isEqualTo("smime_test_user_alias"); - assertThat(email.getPkcs12ConfigForSmimeSigning().getKeyPassword()).isEqualTo("letmein".toCharArray()); + assertThat(email.getSmimeSigningConfig()).isNotNull(); + assertThat(email.getSmimeSigningConfig().getPkcs12Config()).isNotNull(); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getPkcs12StoreData()).isNotNull(); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getStorePassword()).isEqualTo("letmein".toCharArray()); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getKeyAlias()).isEqualTo("smime_test_user_alias_rsa"); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getKeyPassword()).isEqualTo("letmein".toCharArray()); } @Test public void testSignWithSmime_WithConfigParameters() { - builder.signWithSmime(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias", "letmein"); + builder.signWithSmime(SmimeSigningConfig.builder() + .pkcs12Config(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias_rsa", "letmein") + .build()); + + final Email email = builder.buildEmail(); + + assertThat(email.getSmimeSigningConfig()).isNotNull(); + assertThat(email.getSmimeSigningConfig().getPkcs12Config()).isNotNull(); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getPkcs12StoreData()).isNotNull(); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getStorePassword()).isEqualTo("letmein".toCharArray()); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getKeyAlias()).isEqualTo("smime_test_user_alias_rsa"); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getKeyPassword()).isEqualTo("letmein".toCharArray()); + assertThat(email.getSmimeSigningConfig().getSignatureAlgorithm()).isNull(); + } + + @Test + public void testSignWithSmime_WithConfigObject_AlternativeSignatureAlgorithm() { + builder.signWithSmime(SmimeSigningConfig.builder() + .pkcs12Config(loadPkcs12KeyStore()) + .signatureAlgorithm("SHA384withDSA") + .build()); final Email email = builder.buildEmail(); - assertThat(email.getPkcs12ConfigForSmimeSigning()).isNotNull(); - assertThat(email.getPkcs12ConfigForSmimeSigning().getPkcs12StoreData()).isNotNull(); - assertThat(email.getPkcs12ConfigForSmimeSigning().getStorePassword()).isEqualTo("letmein".toCharArray()); - assertThat(email.getPkcs12ConfigForSmimeSigning().getKeyAlias()).isEqualTo("smime_test_user_alias"); - assertThat(email.getPkcs12ConfigForSmimeSigning().getKeyPassword()).isEqualTo("letmein".toCharArray()); + assertThat(email.getSmimeSigningConfig()).isNotNull(); + assertThat(email.getSmimeSigningConfig().getPkcs12Config()).isNotNull(); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getPkcs12StoreData()).isNotNull(); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getStorePassword()).isEqualTo("letmein".toCharArray()); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getKeyAlias()).isEqualTo("smime_test_user_alias_rsa"); + assertThat(email.getSmimeSigningConfig().getPkcs12Config().getKeyPassword()).isEqualTo("letmein".toCharArray()); + assertThat(email.getSmimeSigningConfig().getSignatureAlgorithm()).isEqualTo("SHA384withDSA"); } @Test public void testEncryptWithSmime_FromFile() throws Exception { Security.addProvider(new BouncyCastleProvider()); - builder.encryptWithSmime(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")); + builder.encryptWithSmime(SmimeEncryptionConfig.builder() + .x509Certificate(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")) + .build()); - final X509Certificate certificateOut = builder.buildEmail().getX509CertificateForSmimeEncryption(); + final SmimeEncryptionConfig smimeEncryptionConfig = builder.buildEmail().getSmimeEncryptionConfig(); + assertThat(smimeEncryptionConfig).isNotNull(); + final X509Certificate certificateOut = smimeEncryptionConfig.getX509Certificate(); assertThat(certificateOut).isNotNull(); assertSignedBy(certificateOut, "Benny Bottema"); } @@ -76,10 +105,14 @@ public void testEncryptWithSmime_FromFile() throws Exception { public void testEncryptWithSmime_FromFilePath() throws Exception { Security.addProvider(new BouncyCastleProvider()); - builder.encryptWithSmime(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt"); + builder.encryptWithSmime(SmimeEncryptionConfig.builder() + .x509Certificate(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt") + .build()); - final X509Certificate certificateOut = builder.buildEmail().getX509CertificateForSmimeEncryption(); + final SmimeEncryptionConfig smimeEncryptionConfig = builder.buildEmail().getSmimeEncryptionConfig(); + assertThat(smimeEncryptionConfig).isNotNull(); + final X509Certificate certificateOut = smimeEncryptionConfig.getX509Certificate(); assertThat(certificateOut).isNotNull(); assertSignedBy(certificateOut, "Benny Bottema"); } @@ -90,10 +123,14 @@ public void testEncryptWithSmime_FromCertificate() throws Exception { X509Certificate certificateIn = CertificationUtil.readFromPem(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")); - builder.encryptWithSmime(certificateIn); + builder.encryptWithSmime(SmimeEncryptionConfig.builder() + .x509Certificate(certificateIn) + .build()); - final X509Certificate certificateOut = builder.buildEmail().getX509CertificateForSmimeEncryption(); + final SmimeEncryptionConfig smimeEncryptionConfig = builder.buildEmail().getSmimeEncryptionConfig(); + assertThat(smimeEncryptionConfig).isNotNull(); + final X509Certificate certificateOut = smimeEncryptionConfig.getX509Certificate(); assertThat(certificateOut).isNotNull(); assertSignedBy(certificateOut, "Benny Bottema"); } diff --git a/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/MailerLiveTest.java b/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/MailerLiveTest.java index 1d5b06020..e66e8e12e 100644 --- a/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/MailerLiveTest.java +++ b/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/MailerLiveTest.java @@ -15,6 +15,7 @@ import org.simplejavamail.api.email.EmailPopulatingBuilder; import org.simplejavamail.api.email.OriginalSmimeDetails.SmimeMode; import org.simplejavamail.api.email.Recipient; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; import org.simplejavamail.api.internal.smimesupport.model.PlainSmimeDetails; import org.simplejavamail.api.mailer.CustomMailer; import org.simplejavamail.api.mailer.EmailTooBigException; @@ -158,7 +159,7 @@ public void createMailSession_OutlookMessageTest() public void createMailSession_OutlookMessageSmimeSignTest() throws IOException, MessagingException, ExecutionException, InterruptedException { EmailPopulatingBuilder builder = readOutlookMessage("test-messages/HTML mail with replyto and attachment and embedded image.msg") - .signWithSmime(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias", "letmein"); + .signWithSmime(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias_rsa", "letmein", null); Email email = assertSendingEmail(builder, false, true, false, true, false); verifyReceivedOutlookEmail(email, true, false); @@ -175,6 +176,27 @@ public void createMailSession_OutlookMessageSmimeSignTest() .build()); } + @Test + public void createMailSession_OutlookMessageSmimeSignTest_AlternativeSignatureAlgorithm() + throws IOException, MessagingException, ExecutionException, InterruptedException { + EmailPopulatingBuilder builder = readOutlookMessage("test-messages/HTML mail with replyto and attachment and embedded image.msg") + .signWithSmime(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias_dsa", "letmein", "SHA384withDSA"); + Email email = assertSendingEmail(builder, false, true, false, true, false); + verifyReceivedOutlookEmail(email, true, false); + + //noinspection deprecation + assertThat(((InternalEmail) email).wasMergedWithSmimeSignedMessage()).isFalse(); + + EmailAssert.assertThat(email).hasOriginalSmimeDetails(OriginalSmimeDetailsImpl.builder() + .smimeMode(SmimeMode.SIGNED) + .smimeMime("multipart/signed") + .smimeProtocol("application/pkcs7-signature") + .smimeMicalg("sha-384") + .smimeSignedBy("Benny Bottema") + .smimeSignatureValid(true) + .build()); + } + @Test public void createMailSession_OutlookMessageDefaultSmimeSignTest() throws IOException, MessagingException, ExecutionException, InterruptedException { @@ -182,7 +204,7 @@ public void createMailSession_OutlookMessageDefaultSmimeSignTest() mailer = MailerBuilder .withSMTPServer("localhost", SERVER_PORT, USERNAME, PASSWORD) .withEmailDefaults(EMAIL_DEFAULTS() - .signWithSmime(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias", "letmein") + .signWithSmime(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias_rsa", "letmein", null) .buildEmail()) .withEmailOverrides(EMAIL_OVERRIDES() .buildEmail()) @@ -192,9 +214,9 @@ public void createMailSession_OutlookMessageDefaultSmimeSignTest() Email email = assertSendingEmail(builder, false, true, false, true, false); // verify that S/MIME was indeed only configured on the mailer instance - assertThat(mailer.getEmailGovernance().produceEmailApplyingDefaultsAndOverrides(email).getPkcs12ConfigForSmimeSigning()).isNotNull(); - assertThat(builder.getPkcs12ConfigForSmimeSigning()).isNull(); - assertThat(email.getPkcs12ConfigForSmimeSigning()).isNull(); + assertThat(mailer.getEmailGovernance().produceEmailApplyingDefaultsAndOverrides(email).getSmimeSigningConfig()).isNotNull(); + assertThat(builder.getSmimeSigningConfig()).isNull(); + assertThat(email.getSmimeEncryptionConfig()).isNull(); verifyReceivedOutlookEmail(email, true, false); @@ -252,7 +274,32 @@ public void testOutlookMessageWithNestedOutlookMessageAttachmentThatHasItsOwnNes public void createMailSession_OutlookMessageSmimeEncryptTest() throws IOException, MessagingException, ExecutionException, InterruptedException { EmailPopulatingBuilder builder = readOutlookMessage("test-messages/HTML mail with replyto and attachment and embedded image.msg") - .encryptWithSmime(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")); + .encryptWithSmime(SmimeEncryptionConfig.builder() + .x509Certificate(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")) + .build()); + Email email = assertSendingEmail(builder, false, true, false, true, false); + verifyReceivedOutlookEmail(email, false, true); + + //noinspection deprecation + assertThat(((InternalEmail) email).wasMergedWithSmimeSignedMessage()).isTrue(); + + EmailAssert.assertThat(email).hasOriginalSmimeDetails(OriginalSmimeDetailsImpl.builder() + .smimeMode(SmimeMode.ENCRYPTED) + .smimeMime("application/pkcs7-mime") + .smimeType("enveloped-data") + .smimeName("smime.p7m") + .build()); + } + + @Test + public void createMailSession_OutlookMessageSmimeEncryptTest_AlternativeAlgorithms() + throws IOException, MessagingException, ExecutionException, InterruptedException { + EmailPopulatingBuilder builder = readOutlookMessage("test-messages/HTML mail with replyto and attachment and embedded image.msg") + .encryptWithSmime(SmimeEncryptionConfig.builder() + .x509Certificate(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")) + .keyEncapsulationAlgorithm("RSA_OAEP_SHA384") + .cipherAlgorithm("AES192_CBC") + .build()); Email email = assertSendingEmail(builder, false, true, false, true, false); verifyReceivedOutlookEmail(email, false, true); @@ -271,8 +318,10 @@ public void createMailSession_OutlookMessageSmimeEncryptTest() public void createMailSession_OutlookMessageSmimeSignEncryptTest() throws IOException, MessagingException, ExecutionException, InterruptedException { EmailPopulatingBuilder builder = readOutlookMessage("test-messages/HTML mail with replyto and attachment and embedded image.msg") - .signWithSmime(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias", "letmein") - .encryptWithSmime(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")); + .signWithSmime(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias_rsa", "letmein", null) + .encryptWithSmime(SmimeEncryptionConfig.builder() + .x509Certificate(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")) + .build()); Email email = assertSendingEmail(builder, false, true, false, true, false); verifyReceivedOutlookEmail(email, true, true); @@ -299,7 +348,9 @@ public void createMailSession_OutlookMessageSmimeSignEncryptTest() public void testEncryptSendAndReceiveDecrypt() throws MessagingException, ExecutionException, InterruptedException { val builder = EmailHelper.createDummyEmailBuilder(null, true, true, true, false, false, false, false) - .encryptWithSmime(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")); + .encryptWithSmime(SmimeEncryptionConfig.builder() + .x509Certificate(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")) + .build()); Email email = assertSendingEmail(builder, false, true, false, false, false); diff --git a/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/MailerTest.java b/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/MailerTest.java index 5b1bfea25..465ddc760 100644 --- a/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/MailerTest.java +++ b/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/MailerTest.java @@ -404,8 +404,8 @@ public void testDKIMPrimingAndSmimeCombo() .dkimSigningDomain("somemail.com") .dkimSelector("select") .build()); - emailPopulatingBuilder.signWithSmime(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias", "letmein"); - emailPopulatingBuilder.encryptWithSmime(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt")); + emailPopulatingBuilder.signWithSmime(new File(RESOURCES_PKCS + "/smime_keystore.pkcs12"), "letmein", "smime_test_user_alias_rsa", "letmein", null); + emailPopulatingBuilder.encryptWithSmime(new File(RESOURCES_PKCS + "/smime_test_user.pem.standard.crt"), null, null); MimeMessage mimeMessage = EmailConverter.emailToMimeMessage(emailPopulatingBuilder.buildEmail()); // success, signing did not produce an error diff --git a/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/internal/MailerImplTest.java b/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/internal/MailerImplTest.java index cf701f798..d03fdd5d0 100644 --- a/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/internal/MailerImplTest.java +++ b/modules/simple-java-mail/src/test/java/org/simplejavamail/mailer/internal/MailerImplTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import org.simplejavamail.MailException; import org.simplejavamail.api.email.Email; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.api.mailer.Mailer; import org.simplejavamail.api.mailer.config.EmailGovernance; import org.simplejavamail.api.mailer.config.ProxyConfig; @@ -116,19 +117,22 @@ public void trustHosts() { @Test public void testSignWithSmime_WithConfigObject() { final Email emailWithDefaultPkcs12KeyStoreDefault = EmailBuilder.startingBlank() - .signWithSmime(loadPkcs12KeyStore()) + .signWithSmime(SmimeSigningConfig.builder() + .pkcs12Config(loadPkcs12KeyStore()) + .build()) .buildEmail(); final EmailGovernance emailGovernance = new EmailGovernanceImpl(null, emailWithDefaultPkcs12KeyStoreDefault, null, null); final Mailer mailer = new MailerImpl(null, SMTP, emailGovernance, createEmptyProxyConfig(), session, createDummyOperationalConfig(EMPTY_LIST, true, false)); - val actual = mailer.getEmailGovernance().produceEmailApplyingDefaultsAndOverrides(null).getPkcs12ConfigForSmimeSigning(); + val actual = mailer.getEmailGovernance().produceEmailApplyingDefaultsAndOverrides(null).getSmimeSigningConfig(); assertThat(actual).isNotNull(); - assertThat(actual.getPkcs12StoreData()).isNotNull(); - assertThat(actual.getStorePassword()).isEqualTo("letmein".toCharArray()); - assertThat(actual.getKeyAlias()).isEqualTo("smime_test_user_alias"); - assertThat(actual.getKeyPassword()).isEqualTo("letmein".toCharArray()); + assertThat(actual.getPkcs12Config()).isNotNull(); + assertThat(actual.getPkcs12Config().getPkcs12StoreData()).isNotNull(); + assertThat(actual.getPkcs12Config().getStorePassword()).isEqualTo("letmein".toCharArray()); + assertThat(actual.getPkcs12Config().getKeyAlias()).isEqualTo("smime_test_user_alias_rsa"); + assertThat(actual.getPkcs12Config().getKeyPassword()).isEqualTo("letmein".toCharArray()); } @NotNull diff --git a/modules/simple-java-mail/src/test/java/org/simplejavamail/util/TestDataHelper.java b/modules/simple-java-mail/src/test/java/org/simplejavamail/util/TestDataHelper.java index c062dc630..7e0179753 100644 --- a/modules/simple-java-mail/src/test/java/org/simplejavamail/util/TestDataHelper.java +++ b/modules/simple-java-mail/src/test/java/org/simplejavamail/util/TestDataHelper.java @@ -46,7 +46,7 @@ public static Pkcs12Config loadPkcs12KeyStore() { return Pkcs12Config.builder() .pkcs12Store(RESOURCES_PKCS + "/smime_keystore.pkcs12") .storePassword("letmein") - .keyAlias("smime_test_user_alias") + .keyAlias("smime_test_user_alias_rsa") .keyPassword("letmein") .build(); } diff --git a/modules/simple-java-mail/src/test/resources/pkcs12/about all this.txt b/modules/simple-java-mail/src/test/resources/pkcs12/about all this.txt index 1372d12fe..17a3a515e 100644 --- a/modules/simple-java-mail/src/test/resources/pkcs12/about all this.txt +++ b/modules/simple-java-mail/src/test/resources/pkcs12/about all this.txt @@ -5,9 +5,12 @@ https://knowledge.digicert.com/solution/SO26449.html smime.cnf -> openssl config file from the how-to.html -smime_keystore.pkcs12 with key "smime_test_user_alias" +smime_keystore.pkcs12 with key "smime_test_user_alias_rsa" -> created following https://stackoverflow.com/a/22647106/441662: - - openssl pkcs12 -export -in smime_test_user.pem.crt -inkey smime_test_user.key -out smime_keystore.pkcs12 -name smime_test_user_alias -noiter -nomaciter + - openssl pkcs12 -export -in smime_test_user.pem.crt -inkey smime_test_user.key -out smime_keystore.pkcs12 -name smime_test_user_alias_rsa -noiter -nomaciter +Also with key "smime_test_user_alias_dsa", created with help from ChatGPT, using a command like this: + -> keytool -genkeypair -alias smime_test_user_alias_dsa -keyalg DSA -keysize 2048 -keystore new-temporary-keystore.p12 -storetype PKCS12 -storepass letmein -validity 3650 -dname "EMAILADDRESS=emailaddress, CN=Some Name, O=Simple Java Mail, ST=Province, C=NL" -ext san=dns:simplejavamail.org,dns:www.simplejavamail.org + - then with KeyStore Explorer, copy/paste this key from new-temporary-keystore.p12 to smime_keystore.pkcs12 smime_test_user.pem.openssl.crt is the openssl nonstandard format - https://stackoverflow.com/questions/55550299/java-can-not-load-begin-trusted-certificate-format-certificate diff --git a/modules/simple-java-mail/src/test/resources/pkcs12/smime_keystore.pkcs12 b/modules/simple-java-mail/src/test/resources/pkcs12/smime_keystore.pkcs12 index 621868f342fcdcd8ddd62a32a70fba050ef75fee..3148c4ae24d35d5b91d5038d890b8dfe19418232 100644 GIT binary patch literal 6875 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 literal 4418 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 diff --git a/modules/simple-java-mail/src/test/resources/simplejavamail.properties b/modules/simple-java-mail/src/test/resources/simplejavamail.properties index ae3ba22d7..1646212bc 100644 --- a/modules/simple-java-mail/src/test/resources/simplejavamail.properties +++ b/modules/simple-java-mail/src/test/resources/simplejavamail.properties @@ -28,7 +28,7 @@ simplejavamail.defaults.bcc.address=bcc@default.com simplejavamail.opportunistic.tls=true simplejavamail.smime.signing.keystore=src/test/resources/pkcs12/smime_keystore.pkcs12 simplejavamail.smime.signing.keystore_password=letmein -simplejavamail.smime.signing.key_alias=smime_test_user_alias +simplejavamail.smime.signing.key_alias=smime_test_user_alias_rsa simplejavamail.smime.signing.key_password=letmein simplejavamail.smime.encryption.certificate=src/test/resources/pkcs12/smime_test_user.pem.standard.crt simplejavamail.smime.signing.algorithm= diff --git a/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/CMSAlgorithmResolver.java b/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/CMSAlgorithmResolver.java new file mode 100644 index 000000000..3d5c136e8 --- /dev/null +++ b/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/CMSAlgorithmResolver.java @@ -0,0 +1,38 @@ +package org.simplejavamail.internal.smimesupport; + +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.cms.CMSAlgorithm; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +/** + * This class is used to resolve the algorithm name to the corresponding ASN1ObjectIdentifier. + *

This is used to support the algorithm names in the S/MIME configuration, and is needed because + * the Bouncy Castle CMSAlgorithm class does not provide a method to resolve the algorithm name to + * (and it's not an enum, either)

+ */ +class CMSAlgorithmResolver { + + private static final Map algorithmMap = new HashMap<>(); + + static { + Field[] fields = CMSAlgorithm.class.getDeclaredFields(); + for (Field field : fields) { + if (field.getType().equals(ASN1ObjectIdentifier.class)) { + try { + algorithmMap.put(field.getName(), (ASN1ObjectIdentifier) field.get(null)); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to access CMSAlgorithm field: " + field.getName(), e); + } + } + } + } + + @Nullable + static ASN1ObjectIdentifier resolve(String algorithmName) { + return algorithmMap.get(algorithmName); + } +} diff --git a/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/SMIMESupport.java b/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/SMIMESupport.java index eca1a838d..9f7af1edb 100644 --- a/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/SMIMESupport.java +++ b/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/SMIMESupport.java @@ -32,6 +32,8 @@ import org.simplejavamail.api.email.Email; import org.simplejavamail.api.email.OriginalSmimeDetails; import org.simplejavamail.api.email.OriginalSmimeDetails.SmimeMode; +import org.simplejavamail.api.email.config.SmimeEncryptionConfig; +import org.simplejavamail.api.email.config.SmimeSigningConfig; import org.simplejavamail.api.internal.outlooksupport.model.OutlookMessage; import org.simplejavamail.api.internal.outlooksupport.model.OutlookSmime.OutlookSmimeApplicationSmime; import org.simplejavamail.api.internal.outlooksupport.model.OutlookSmime.OutlookSmimeMultipartSigned; @@ -42,6 +44,7 @@ import org.simplejavamail.internal.smimesupport.builder.SmimeParseResultBuilder; import org.simplejavamail.internal.smimesupport.model.OriginalSmimeDetailsImpl; import org.simplejavamail.internal.smimesupport.model.SmimeDetailsImpl; +import org.simplejavamail.utils.mail.smime.KeyEncapsulationAlgorithm; import org.simplejavamail.utils.mail.smime.SmimeKey; import org.simplejavamail.utils.mail.smime.SmimeKeyStore; import org.simplejavamail.utils.mail.smime.SmimeMessageIdFixingMimeMessage; @@ -64,7 +67,15 @@ import static java.lang.String.format; import static java.util.Arrays.asList; -import static org.simplejavamail.internal.smimesupport.SmimeException.*; +import static java.util.Optional.ofNullable; +import static org.simplejavamail.internal.smimesupport.SmimeException.ERROR_DECRYPTING_SMIME_SIGNED_ATTACHMENT; +import static org.simplejavamail.internal.smimesupport.SmimeException.ERROR_DETERMINING_SMIME_SIGNER; +import static org.simplejavamail.internal.smimesupport.SmimeException.ERROR_EXTRACTING_SIGNEDBY_FROM_SMIME_SIGNED_ATTACHMENT; +import static org.simplejavamail.internal.smimesupport.SmimeException.ERROR_EXTRACTING_SUBJECT_FROM_CERTIFICATE; +import static org.simplejavamail.internal.smimesupport.SmimeException.ERROR_OBTAINING_SMIME_KEY; +import static org.simplejavamail.internal.smimesupport.SmimeException.ERROR_READING_SMIME_CONTENT_TYPE; +import static org.simplejavamail.internal.smimesupport.SmimeException.MIMEPART_ASSUMED_SIGNED_ACTUALLY_NOT_SIGNED; +import static org.simplejavamail.internal.util.MiscUtil.defaultTo; /** @@ -246,7 +257,7 @@ private AttachmentDecryptionResult decryptAndUnsignAttachment( } else if (smimeState == SmimeState.SIGNED) { liberatedContent = getSignedContent(mimeBodyPart); } else if (smimeState == SmimeState.PROBABLY_SIGNED) { - liberatedContent = tryGetSignedContent(liberatedContent, mimeBodyPart); + liberatedContent = tryGetSignedContent(mimeBodyPart); } return liberatedContent != null ? liberatedContent : new AttachmentDecryptionResultImpl(SmimeMode.PLAIN, attachment); @@ -285,7 +296,7 @@ private AttachmentDecryptionResult getSignedContent(final MimeBodyPart mimeBodyP } @Nullable - private AttachmentDecryptionResult tryGetSignedContent(AttachmentDecryptionResult possiblySignedContent, final MimeBodyPart mimeBodyPart) + private AttachmentDecryptionResult tryGetSignedContent(final MimeBodyPart mimeBodyPart) throws MessagingException, IOException { try { if (SmimeUtil.checkSignature(mimeBodyPart)) { @@ -296,7 +307,7 @@ private AttachmentDecryptionResult tryGetSignedContent(AttachmentDecryptionResul // ignore, apparently not S/SMIME after all } LOGGER.warn("Content classified as signed, but apparently not using S/MIME (or it was and the signature was not valid); skipping S/MIME interpeter..."); - return possiblySignedContent; + return null; } private String restoreSmimeContentType(@NotNull final AttachmentResource attachment, final OriginalSmimeDetails originalSmimeDetails) { @@ -447,17 +458,21 @@ private static SignerInformationVerifier getVerifier(X509Certificate certificate @NotNull @Override - public MimeMessage signMessageWithSmime(@Nullable final Session session, @NotNull final Email email, @NotNull final MimeMessage messageToProtect, @NotNull final Pkcs12Config pkcs12Config) { - return SmimeUtil.sign(session, email.getId(), messageToProtect, retrieveSmimeKeyFromPkcs12Keystore(pkcs12Config), - SmimeUtil.DEFAULT_SIGNATURE_ALGORITHM_NAME); + public MimeMessage signMessageWithSmime(@Nullable final Session session, @NotNull final Email email, @NotNull final MimeMessage messageToProtect, @NotNull final SmimeSigningConfig smimeSigningConfig) { + return SmimeUtil.sign(session, email.getId(), messageToProtect, retrieveSmimeKeyFromPkcs12Keystore(smimeSigningConfig.getPkcs12Config()), + defaultTo(smimeSigningConfig.getSignatureAlgorithm(), SmimeUtil.DEFAULT_SIGNATURE_ALGORITHM_NAME)); } @NotNull @Override - public MimeMessage encryptMessageWithSmime(@Nullable final Session session, @NotNull final Email email, @NotNull final MimeMessage messageToProtect, @NotNull final X509Certificate x509Certificate) { - return SmimeUtil.encrypt(session, messageToProtect, email.getId(), x509Certificate, - SmimeUtil.DEFAULT_KEY_ENCAPSULATION_ALGORITHM, - SmimeUtil.DEFAULT_CIPHER); + public MimeMessage encryptMessageWithSmime(@Nullable final Session session, @NotNull final Email email, @NotNull final MimeMessage messageToProtect, @NotNull final SmimeEncryptionConfig smimeEncryptionConfige) { + return SmimeUtil.encrypt(session, messageToProtect, email.getId(), smimeEncryptionConfige.getX509Certificate(), + ofNullable(smimeEncryptionConfige.getKeyEncapsulationAlgorithm()) + .map(KeyEncapsulationAlgorithm::valueOf) + .orElse(SmimeUtil.DEFAULT_KEY_ENCAPSULATION_ALGORITHM), + ofNullable(smimeEncryptionConfige.getCipherAlgorithm()) + .map(CMSAlgorithmResolver::resolve) + .orElse(SmimeUtil.DEFAULT_CIPHER)); } @Override diff --git a/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/model/SmimeDetailsImpl.java b/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/model/SmimeDetailsImpl.java index d737821d5..e5895135d 100644 --- a/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/model/SmimeDetailsImpl.java +++ b/modules/smime-module/src/main/java/org/simplejavamail/internal/smimesupport/model/SmimeDetailsImpl.java @@ -1,27 +1,14 @@ package org.simplejavamail.internal.smimesupport.model; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.simplejavamail.api.internal.smimesupport.model.SmimeDetails; +@Getter +@RequiredArgsConstructor public class SmimeDetailsImpl implements SmimeDetails { - @NotNull private final String smimeMime; - @Nullable private final String signedBy; - - public SmimeDetailsImpl(@NotNull final String smimeMime, @Nullable final String signedBy) { - this.smimeMime = smimeMime; - this.signedBy = signedBy; - } - - @NotNull - @Override - public String getSmimeMime() { - return smimeMime; - } - - @Nullable - @Override - public String getSignedBy() { - return signedBy; - } + @NotNull private final String smimeMime; + @Nullable private final String signedBy; } diff --git a/modules/spring-module/src/main/java/org/simplejavamail/springbootsupport/SimpleJavaMailProperties.java b/modules/spring-module/src/main/java/org/simplejavamail/springbootsupport/SimpleJavaMailProperties.java index b654a1bc3..7e2bf278a 100644 --- a/modules/spring-module/src/main/java/org/simplejavamail/springbootsupport/SimpleJavaMailProperties.java +++ b/modules/spring-module/src/main/java/org/simplejavamail/springbootsupport/SimpleJavaMailProperties.java @@ -202,6 +202,7 @@ public static class Signing { private String keystorePassword; private String keyAlias; private String keyPassword; + private String algorithm; } /** @@ -211,6 +212,8 @@ public static class Signing { @Setter public static class Encryption { private String certificate; + private String keyEncapsulationAlgorithm; + private String cipher; } } diff --git a/modules/spring-module/src/test/resources/pkcs12/smime_keystore.pkcs12 b/modules/spring-module/src/test/resources/pkcs12/smime_keystore.pkcs12 index 621868f342fcdcd8ddd62a32a70fba050ef75fee..8b329f6be79b2b43126b8cf7ae1f68915e4fd2a1 100644 GIT binary patch literal 4542 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 diff --git a/modules/spring-module/src/test/resources/simplejavamail.properties b/modules/spring-module/src/test/resources/simplejavamail.properties index cbe1afa47..a193ae3ee 100644 --- a/modules/spring-module/src/test/resources/simplejavamail.properties +++ b/modules/spring-module/src/test/resources/simplejavamail.properties @@ -28,7 +28,7 @@ simplejavamail.defaults.bcc.address=bcc@default.com simplejavamail.opportunistic.tls=true simplejavamail.smime.signing.keystore=src/test/resources/pkcs12/smime_keystore.pkcs12 simplejavamail.smime.signing.keystore_password=letmein -simplejavamail.smime.signing.key_alias=smime_test_user_alias +simplejavamail.smime.signing.key_alias=smime_test_user_alias_rsa simplejavamail.smime.signing.key_password=letmein simplejavamail.smime.encryption.certificate= simplejavamail.smime.signing.algorithm=