Skip to content

Commit

Permalink
issue bbottema#51: align S/MIME header evaluation with rfc5751/3.9
Browse files Browse the repository at this point in the history
  • Loading branch information
Symphily committed Feb 2, 2022
1 parent dbcde0a commit ee7c11e
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 13 deletions.
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("eplyto@somemail.com>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();
}
}

0 comments on commit ee7c11e

Please sign in to comment.