22
33import net .markenwerk .utils .mail .smime .SmimeKey ;
44import net .markenwerk .utils .mail .smime .SmimeKeyStore ;
5- import net .markenwerk .utils .mail .smime .SmimeState ;
65import net .markenwerk .utils .mail .smime .SmimeUtil ;
76import org .bouncycastle .asn1 .x500 .RDN ;
87import org .bouncycastle .asn1 .x500 .X500Name ;
2928import org .simplejavamail .api .internal .outlooksupport .model .OutlookMessage ;
3029import org .simplejavamail .api .internal .outlooksupport .model .OutlookSmime .OutlookSmimeApplicationSmime ;
3130import org .simplejavamail .api .internal .outlooksupport .model .OutlookSmime .OutlookSmimeMultipartSigned ;
31+ import org .simplejavamail .api .internal .smimesupport .model .AttachmentDecryptionResult ;
3232import org .simplejavamail .api .internal .smimesupport .model .SmimeDetails ;
3333import org .simplejavamail .api .mailer .config .Pkcs12Config ;
3434import org .simplejavamail .internal .modules .SMIMEModule ;
35+ import org .simplejavamail .internal .smimesupport .SmimeUtilFixed .SmimeStateFixed ;
3536import org .simplejavamail .internal .smimesupport .builder .SmimeParseResultBuilder ;
3637import org .simplejavamail .internal .smimesupport .model .OriginalSmimeDetailsImpl ;
3738import org .simplejavamail .internal .smimesupport .model .SmimeDetailsImpl ;
5960
6061import static java .lang .String .format ;
6162import static java .util .Arrays .asList ;
62- import static net .markenwerk .utils .mail .smime .SmimeState .ENCRYPTED ;
63- import static net .markenwerk .utils .mail .smime .SmimeState .SIGNED ;
6463import static org .simplejavamail .internal .smimesupport .SmimeException .ERROR_DECRYPTING_SMIME_SIGNED_ATTACHMENT ;
6564import static org .simplejavamail .internal .smimesupport .SmimeException .ERROR_DETERMINING_SMIME_SIGNER ;
6665import static org .simplejavamail .internal .smimesupport .SmimeException .ERROR_EXTRACTING_SIGNEDBY_FROM_SMIME_SIGNED_ATTACHMENT ;
@@ -171,15 +170,15 @@ private boolean checkSignature(@NotNull final MimeMessage mimeMessage, @Nullable
171170 private void decryptAttachments (@ NotNull final SmimeParseResultBuilder smimeBuilder , @ NotNull final List <AttachmentResource > attachments ,
172171 @ Nullable final Pkcs12Config pkcs12Config ) {
173172 LOGGER .debug ("checking for S/MIME signed / encrypted attachments..." );
174- List <AttachmentResource > decryptedAttachments = decryptAttachments (attachments , pkcs12Config , smimeBuilder .getOriginalSmimeDetails ());
173+ List <AttachmentDecryptionResult > decryptedAttachments = decryptAttachments (attachments , pkcs12Config , smimeBuilder .getOriginalSmimeDetails ());
175174 smimeBuilder .addDecryptedAttachments (decryptedAttachments );
176175
177176 if (attachments .size () == 1 ) {
178177 final AttachmentResource onlyAttachment = attachments .get (0 );
179- final AttachmentResource onlyAttachmentDecrypted = smimeBuilder .getDecryptedAttachments ().get (0 );
180- if (isSmimeAttachment (onlyAttachment ) && isMimeMessageAttachment (onlyAttachmentDecrypted )) {
178+ final AttachmentDecryptionResult onlyAttachmentDecrypted = smimeBuilder .getDecryptedAttachmentResults ().get (0 );
179+ if (isSmimeAttachment (onlyAttachment ) && isMimeMessageAttachment (onlyAttachmentDecrypted . getAttachmentResource () )) {
181180 smimeBuilder .getOriginalSmimeDetails ().completeWith (determineSmimeDetails (onlyAttachment ));
182- smimeBuilder .setSmimeSignedEmailToProcess (onlyAttachmentDecrypted );
181+ smimeBuilder .setSmimeSignedEmailToProcess (onlyAttachmentDecrypted . getAttachmentResource () );
183182 }
184183 }
185184 }
@@ -204,24 +203,24 @@ private OriginalSmimeDetailsImpl determineSmimeDetails(final AttachmentResource
204203 */
205204 @ NotNull
206205 @ Override
207- public List <AttachmentResource > decryptAttachments (
206+ public List <AttachmentDecryptionResult > decryptAttachments (
208207 @ NotNull final List <AttachmentResource > attachments ,
209208 @ Nullable final Pkcs12Config pkcs12Config ,
210209 @ NotNull final OriginalSmimeDetails messageSmimeDetails ) {
211- final List <AttachmentResource > decryptedAttachments ;
212- decryptedAttachments = new ArrayList <>(attachments );
213-
214- for (int i = 0 ; i < decryptedAttachments .size (); i ++) {
215- final AttachmentResource attachment = decryptedAttachments .get (i );
210+ final List <AttachmentDecryptionResult > decryptedAttachments = new ArrayList <>();
211+ for (final AttachmentResource attachment : attachments ) {
216212 if (isSmimeAttachment (attachment )) {
217213 try {
218214 LOGGER .debug ("decrypting S/MIME signed attachment '{}'..." , attachment .getName ());
219- decryptedAttachments .set ( i , decryptAndUnsignAttachment (attachment , pkcs12Config , messageSmimeDetails ));
215+ decryptedAttachments .add ( decryptAndUnsignAttachment (attachment , pkcs12Config , messageSmimeDetails ));
220216 } catch (Exception e ) {
221217 throw new SmimeException (format (ERROR_DECRYPTING_SMIME_SIGNED_ATTACHMENT , attachment ), e );
222218 }
219+ } else {
220+ decryptedAttachments .add (new AttachmentDecryptionResultImpl (SmimeMode .PLAIN , attachment ));
223221 }
224222 }
223+
225224 return decryptedAttachments ;
226225 }
227226
@@ -233,42 +232,58 @@ public boolean isSmimeAttachment(@NotNull final AttachmentResource attachment) {
233232 return SMIME_MIMETYPES .contains (attachment .getDataSource ().getContentType ());
234233 }
235234
236- private AttachmentResource decryptAndUnsignAttachment (
235+ private AttachmentDecryptionResult decryptAndUnsignAttachment (
237236 @ NotNull final AttachmentResource attachment ,
238237 @ Nullable final Pkcs12Config pkcs12Config ,
239238 @ NotNull final OriginalSmimeDetails messageSmimeDetails ) {
240239 try {
241- final InternetHeaders internetHeaders = new InternetHeaders ();
242- internetHeaders .addHeader ("Content-Type" , restoreSmimeContentType (attachment , messageSmimeDetails ));
243- final MimeBodyPart mimeBodyPart = new MimeBodyPart (internetHeaders , attachment .readAllBytes ());
244-
245- AttachmentResource liberatedContent = null ;
246-
247- SmimeState smimeState = determineStatus (mimeBodyPart , messageSmimeDetails );
248- if (smimeState == SIGNED ) {
249- if (SmimeUtil .checkSignature (mimeBodyPart )) {
250- MimeBodyPart liberatedBodyPart = SmimeUtil .getSignedContent (mimeBodyPart );
251- liberatedContent = handleLiberatedContent (liberatedBodyPart .getContent ());
252- } else {
253- LOGGER .warn ("Content is S/MIME signed, but signature is not valid; skipping S/MIME interpeter..." );
254- }
255- } else if (smimeState == ENCRYPTED ) {
256- if (pkcs12Config != null ) {
257- LOGGER .warn ("Message was encrypted, but no Pkcs12Config was given to decrypt it with, skipping attachment..." );
258- SmimeKey smimeKey = retrieveSmimeKeyFromPkcs12Keystore (pkcs12Config );
259- MimeBodyPart liberatedBodyPart = SmimeUtil .decrypt (mimeBodyPart , smimeKey );
260- liberatedContent = handleLiberatedContent (liberatedBodyPart .getContent ());
261- }
240+ final MimeBodyPart mimeBodyPart = new MimeBodyPart (new InternetHeaders (), attachment .readAllBytes ());
241+ mimeBodyPart .addHeader ("Content-Type" , restoreSmimeContentType (attachment , messageSmimeDetails ));
242+
243+ AttachmentDecryptionResult liberatedContent = null ;
244+
245+ final SmimeStateFixed smimeState = determineStatus (mimeBodyPart , messageSmimeDetails );
246+ if (smimeState == SmimeStateFixed .ENCRYPTED ) {
247+ liberatedContent = getEncryptedContent (pkcs12Config , mimeBodyPart );
248+ } else if (smimeState == SmimeStateFixed .SIGNED ) {
249+ liberatedContent = getSignedContent (mimeBodyPart );
262250 }
263251
264- return liberatedContent != null
265- ? decryptAndUnsignAttachment (liberatedContent , pkcs12Config , messageSmimeDetails )
266- : attachment ;
252+ return liberatedContent != null ? liberatedContent : new AttachmentDecryptionResultImpl (SmimeMode .PLAIN , attachment );
267253 } catch (MessagingException | IOException e ) {
268254 throw new SmimeException (format (ERROR_DECRYPTING_SMIME_SIGNED_ATTACHMENT , attachment ), e );
269255 }
270256 }
271257
258+ @ Nullable
259+ private AttachmentDecryptionResult getEncryptedContent (final @ Nullable Pkcs12Config pkcs12Config , final MimeBodyPart mimeBodyPart )
260+ throws MessagingException , IOException {
261+ if (pkcs12Config != null ) {
262+ MimeBodyPart liberatedBodyPart = SmimeUtil .decrypt (mimeBodyPart , retrieveSmimeKeyFromPkcs12Keystore (pkcs12Config ));
263+ if (SmimeUtilFixed .getStatus (liberatedBodyPart ) == SmimeStateFixed .SIGNED_ENVELOPED ) {
264+ final AttachmentDecryptionResult signedContent = getSignedContent (liberatedBodyPart );
265+ if (signedContent != null ) {
266+ return new AttachmentDecryptionResultImpl (SmimeMode .SIGNED_ENCRYPTED , signedContent .getAttachmentResource ());
267+ }
268+ // apparently the sign was invalid, so ignore and continue with the decrypted attachment instead
269+ }
270+ return new AttachmentDecryptionResultImpl (SmimeMode .ENCRYPTED , handleLiberatedContent (liberatedBodyPart .getContent ()));
271+ }
272+ LOGGER .warn ("Message was encrypted, but no Pkcs12Config was given to decrypt it with, skipping attachment..." );
273+ return null ;
274+ }
275+
276+ @ Nullable
277+ private AttachmentDecryptionResult getSignedContent (final MimeBodyPart mimeBodyPart )
278+ throws MessagingException , IOException {
279+ if (SmimeUtil .checkSignature (mimeBodyPart )) {
280+ MimeBodyPart liberatedBodyPart = SmimeUtil .getSignedContent (mimeBodyPart );
281+ return new AttachmentDecryptionResultImpl (SmimeMode .SIGNED , handleLiberatedContent (liberatedBodyPart .getContent ()));
282+ }
283+ LOGGER .warn ("Content is S/MIME signed, but signature is not valid; skipping S/MIME interpeter..." );
284+ return null ;
285+ }
286+
272287 private String restoreSmimeContentType (@ NotNull final AttachmentResource attachment , final OriginalSmimeDetails originalSmimeDetails ) {
273288 String contentType = attachment .getDataSource ().getContentType ();
274289 if (contentType .contains ("multipart/signed" ) && !contentType .contains ("protocol" ) && originalSmimeDetails .getSmimeProtocol () != null ) {
@@ -299,10 +314,13 @@ protected void updateMessageID() throws MessagingException {
299314 return null ;
300315 }
301316
302- private SmimeState determineStatus (@ NotNull final MimePart mimeBodyPart , @ NotNull final OriginalSmimeDetails messageSmimeDetails ) {
303- SmimeState status = SmimeUtil .getStatus (mimeBodyPart );
304- boolean trustStatus = status != ENCRYPTED || messageSmimeDetails .getSmimeMode () == SmimeMode .PLAIN ;
305- return trustStatus ? status : "signed-data" .equals (messageSmimeDetails .getSmimeType ()) ? SIGNED : ENCRYPTED ;
317+ private SmimeStateFixed determineStatus (@ NotNull final MimePart mimeBodyPart , @ NotNull final OriginalSmimeDetails messageSmimeDetails ) {
318+ SmimeStateFixed status = SmimeUtilFixed .getStatus (mimeBodyPart );
319+ boolean trustStatus = status != SmimeStateFixed .ENCRYPTED || messageSmimeDetails .getSmimeMode () == SmimeMode .PLAIN ;
320+ if (trustStatus ) {
321+ return status ;
322+ }
323+ return "signed-data" .equals (messageSmimeDetails .getSmimeType ()) ? SmimeStateFixed .SIGNED : SmimeStateFixed .ENCRYPTED ;
306324 }
307325
308326 /**
@@ -346,7 +364,7 @@ public String getSignedByAddress(@NotNull MimePart mimePart) {
346364 }
347365
348366 public boolean verifyValidSignature (@ NotNull MimeMessage mimeMessage , @ NotNull OriginalSmimeDetails messageSmimeDetails ) {
349- return determineStatus (mimeMessage , messageSmimeDetails ) != SIGNED || SmimeUtil .checkSignature (mimeMessage );
367+ return determineStatus (mimeMessage , messageSmimeDetails ) != SmimeStateFixed . SIGNED || SmimeUtil .checkSignature (mimeMessage );
350368 }
351369
352370 @ NotNull
0 commit comments