Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import org.simplejavamail.outlookmessageparser.model.OutlookMsgAttachment;
import org.simplejavamail.outlookmessageparser.model.OutlookRecipient;
import org.simplejavamail.outlookmessageparser.model.OutlookSmime.OutlookSmimeApplicationSmime;
import org.simplejavamail.outlookmessageparser.model.OutlookSmime.OutlookSmimeMultipartSigned;
import org.simplejavamail.outlookmessageparser.model.OutlookSmime.OutlookSmimeApplicationOctetStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -70,11 +72,10 @@ public class OutlookMessageParser {
private static final String PROPS_KEY = "__properties_version1.0";

private static final String PROPERTY_STREAM_PREFIX = "__substg1.0_";

private static final Pattern SMIME_CONTENT_TYPE_PATTERN = compile(format("^Content-Type: (?<contenttype>%s)(?:; name=\"(?<name>smime.p7m)\")?(?:; smime-type=(?<smimetype>enveloped-data))?$",
"application\\/pkcs7-mime|multipart\\/signed|application\\/octet-stream|application\\/pkcs7-signature"),
Pattern.MULTILINE);

private static final Pattern SMIME_APPLICATION_PCKS_TYPE_PATTERN = compile("^Content-Type: (?<contenttype>application\\/pkcs7-mime.*?)(?:; name=(\")?(?<name>.*?)(\")?)?(?:; smime-type=(?<smimetype>enveloped-data))?$",Pattern.MULTILINE);
private static final Pattern SMIME_MULTIPART_SIGNED_TYPE_PATTERN = compile("^Content-Type: (?<contenttype>multipart\\/signed.*?)(?:; protocol=(\")?(?<protocol>application\\/(x-)?pkcs7-signature.*?)(\")?)(?:; micalg=(?<micalg>.*?))?(?:;(?<rest>.*?))?$",Pattern.MULTILINE);
private static final Pattern SMIME_APPLICATION_OCTET_TYPE_PATTERN = compile("^Content-Type: (?<contenttype>application\\/octet-stream.*?)(?:; protocol=(?<protocol>.*?))?(?:; name=(?<name>(.*p7z|.*p7c|.*p7s|.*p7m).*?))(?:;(?<rest>.*?))?$",Pattern.MULTILINE);

private static final Pattern XML_CHARSET_PATTERN = compile("charset=(\"|)(?<charset>[\\w\\-]+)\\1", CASE_INSENSITIVE);

private RTF2HTMLConverter rtf2htmlConverter = RTF2HTMLConverterRFCCompliant.INSTANCE;
Expand Down Expand Up @@ -177,12 +178,38 @@ static void extractReplyToHeader(@NotNull final OutlookMessage msg, @NotNull fin
}
}

static void extractSMimeHeader(@NotNull final OutlookMessage msg, @NotNull final String allHeaders) {
static void extractSMimeHeader(@NotNull final OutlookMessage msg, @NotNull String allHeaders) {
if (msg.getSmime() == null) {
// https://regex101.com/r/AE0Uys/1
final Matcher m = SMIME_CONTENT_TYPE_PATTERN.matcher(allHeaders);
if (m.find()) {
msg.setSmime(new OutlookSmimeApplicationSmime(m.group("contenttype"), m.group("smimetype"), m.group("name")));
// https://regex101.com/r/pbMYd2/1
final Matcher applicationPkcs = SMIME_APPLICATION_PCKS_TYPE_PATTERN.matcher(allHeaders);
// https://regex101.com/r/5iAxbs/1
final Matcher multipartSigned = SMIME_MULTIPART_SIGNED_TYPE_PATTERN.matcher(allHeaders);
// https://regex101.com/r/sa4Rp2/1
final Matcher octetType = SMIME_APPLICATION_OCTET_TYPE_PATTERN.matcher(allHeaders);
if (applicationPkcs.find()) {
msg.setSmime(new OutlookSmimeApplicationSmime(applicationPkcs.group("contenttype"), applicationPkcs.group("smimetype"), applicationPkcs.group("name")));
}
if(multipartSigned.find()){
msg.setSmime(new OutlookSmimeMultipartSigned(multipartSigned.group("contenttype"), multipartSigned.group("protocol").replace("\"", ""), multipartSigned.group("micalg")));
}
if(octetType.find()){
msg.setSmime(new OutlookSmimeApplicationOctetStream(octetType.group("contenttype"), octetType.group("protocol"), octetType.group("name")));
}
if (msg.getSmime() == null && (msg.getMessageClass().equals("IPM.Note.SMIME") || msg.getMessageClass().equals("IPM.Note.SMIME.MultipartSigned"))) {
for (OutlookFileAttachment att : msg.fetchTrueAttachments()) {
if(att.getMimeTag().equals("application/pkcs-mime")){
msg.setSmime(new OutlookSmimeApplicationSmime(att.getMimeTag(), null, att.getFilename()));
return;
}
if(att.getMimeTag().matches("multipart/signed|application/(x-)?pkcs7-signature") && att.getExtension().matches(".*p7z|.*p7c|.*p7s|.*p7m")){
msg.setSmime(new OutlookSmimeMultipartSigned(att.getMimeTag(), null, att.getFilename()));
return;
}
if(att.getMimeTag().equals("application/octet-stream") && att.getExtension().matches(".*p7z|.*p7c|.*p7s|.*p7m")){
msg.setSmime(new OutlookSmimeMultipartSigned(att.getMimeTag(), null, att.getFilename()));
return;
}
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.simplejavamail.outlookmessageparser.model;

import javax.annotation.Nullable;
import java.util.Objects;

// https://tools.ietf.org/html/rfc5751#page-32 (Identifying an S/MIME Message)
Expand All @@ -10,7 +11,7 @@ public static class OutlookSmimeApplicationSmime extends OutlookSmime {
private final String smimeType;
private final String smimeName;

public OutlookSmimeApplicationSmime(String smimeMime, String smimeType, String smimeName) {
public OutlookSmimeApplicationSmime(String smimeMime, @Nullable String smimeType, @Nullable String smimeName) {
this.smimeMime = smimeMime;
this.smimeType = smimeType;
this.smimeName = smimeName;
Expand Down Expand Up @@ -88,6 +89,43 @@ public String toString() {
}

public static class OutlookSmimeApplicationOctetStream extends OutlookSmime {

private final String smimeMime;
private final String smimeProtocol;
private final String smimeName;

public OutlookSmimeApplicationOctetStream(String smimeMime, @Nullable String smimeProtocol, @Nullable String smimeName) {
this.smimeMime = smimeMime;
this.smimeProtocol = smimeProtocol;
this.smimeName = smimeName;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OutlookSmimeApplicationOctetStream that = (OutlookSmimeApplicationOctetStream) o;
return Objects.equals(smimeMime, that.smimeMime) &&
Objects.equals(smimeProtocol, that.smimeProtocol) &&
Objects.equals(smimeName, that.smimeName);
}

@Override
public int hashCode() {
return Objects.hash(smimeMime, smimeProtocol, smimeName);
}

@Override
public String toString() {
final StringBuilder sb = new StringBuilder("OutlookSmimeApplicationOctetStream{");
sb.append("smimeMime='").append(smimeMime).append('\'');
sb.append(", smimeProtocol='").append(smimeProtocol).append('\'');
sb.append(", smimeName='").append(smimeName).append('\'');
sb.append('}');
return sb.toString();
}

public String getSmimeMime() { return smimeMime; }
public String getSmimeProtocol() { return smimeProtocol; }
public String getSmimeMicalg() { return smimeName; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,71 @@ public void extractReplyToHeaderMalformed2() {
assertThat(msg.getReplyToName()).isEqualTo("lo.pop.r");
assertThat(msg.getReplyToEmail()).isEqualTo("[email protected]>tg");
}
}

@Test
public void extractSmimePropertiesOctetStream() {

/* application/octet-stream and file-suffix p7m, p7s, p7c, p7z */
String header = "Content-Type: application/octet-stream; name=\"smime.p7m\"";
OutlookMessage msg = new OutlookMessage();
OutlookMessageParser.extractSMimeHeader(msg, header);
assertThat(msg.getSmime()).isNotNull();

header = "Content-Type: application/octet-stream; name=\"smime.p7s\"";
msg = new OutlookMessage();
OutlookMessageParser.extractSMimeHeader(msg, header);
assertThat(msg.getSmime()).isNotNull();

header = "Content-Type: application/octet-stream; name=\"smime.p7c\"";
msg = new OutlookMessage();
OutlookMessageParser.extractSMimeHeader(msg, header);
assertThat(msg.getSmime()).isNotNull();

header = "Content-Type: application/octet-stream; name=\"smime.p7z\"";
msg = new OutlookMessage();
OutlookMessageParser.extractSMimeHeader(msg, header);
assertThat(msg.getSmime()).isNotNull();

/* application/octet-stream and file-suffix NOT p7m, p7s, p7c, p7z */
header = "Content-Type: application/octet-stream; name=\"smime.zip\"";
msg = new OutlookMessage();
OutlookMessageParser.extractSMimeHeader(msg, header);
assertThat(msg.getSmime()).isNull();

}

@Test
public void extractSmimePropertiesMultipartSigned() {
/*multipart/signed and protocol=pkcs7-signature*/
String header = "Content-Type: multipart/signed; protocol=\"application/pkcs7-signature\"; micalg=sha-512; boundary=\"------------ms060207010804070005060507\"";
OutlookMessage msg = new OutlookMessage();
OutlookMessageParser.extractSMimeHeader(msg, header);
assertThat(msg.getSmime()).isNotNull();

/*multipart/signed and protocol=x-pkcs7-signature*/
header = "Content-Type: multipart/signed; protocol=\"application/x-pkcs7-signature\"; micalg=sha-256; boundary=\"------------ms060207010804070005060507\"";
msg = new OutlookMessage();
OutlookMessageParser.extractSMimeHeader(msg, header);
assertThat(msg.getSmime()).isNotNull();

/*multipart/signed and some other protocol*/
header = "Content-Type: multipart/signed; protocol=\"application/plain\"; micalg=sha-512";
msg = new OutlookMessage();
OutlookMessageParser.extractSMimeHeader(msg, header);
assertThat(msg.getSmime()).isNull();
}

@Test
public void extractSmimePropertiesPkcsMime() {
/* application/pkcs7-mime name and smime-type is optional */
String header = "Content-Type: application/pkcs7-mime; name=\"smime.p7m\"; smime-type=enveloped-data";
OutlookMessage msg = new OutlookMessage();
OutlookMessageParser.extractSMimeHeader(msg, header);
assertThat(msg.getSmime()).isNotNull();

header = "Content-Type: application/pkcs7-mime";
msg = new OutlookMessage();
OutlookMessageParser.extractSMimeHeader(msg, header);
assertThat(msg.getSmime()).isNotNull();
}
}