Skip to content

Commit

Permalink
Minor optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
shred committed Nov 25, 2022
1 parent 06e0388 commit ef5ca28
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,16 @@ public static EmailProcessor smimeMessage(Message message, Session mailSession,
boolean hasMatch = false;
for (SignerInformation signer : signed.getSignerInfos().getSigners()) {
hasMatch |= signer.verify(verifier);
if (hasMatch) {
break;
}
}
if (!hasMatch) {
throw new AcmeInvalidMessageException("The S/MIME signature is invalid");
}

MimeMessage content = signed.getContentAsMimeMessage(mailSession);
if (!content.getContentType().equalsIgnoreCase("message/rfc822; forwarded=no")) {
if (!"message/rfc822; forwarded=no".equalsIgnoreCase(content.getContentType())) {
throw new AcmeInvalidMessageException("Message does not contain protected headers");
}

Expand Down Expand Up @@ -214,16 +217,15 @@ private EmailProcessor(Message message, @Nullable MimeMessage signedMessage,
if (from == null) {
throw new AcmeInvalidMessageException("Message has no 'From' header");
}
if (from.length != 1) {
if (from.length != 1 || from[0] == null) {
throw new AcmeInvalidMessageException("Message must have exactly one sender, but has " + from.length);
}
if (validFromAddresses != null && !validFromAddresses.contains(from[0])) {
throw new AcmeInvalidMessageException("Sender '" + from[0] + "' was not found in signing certificate");
}
if (strict && signedMessage != null) {
Address[] outerFrom = message.getFrom();
if ((outerFrom.length > 1) || (outerFrom.length == 1 && outerFrom[0] != null
&& !outerFrom[0].equals(from[0]))) {
if (outerFrom == null || outerFrom.length != 1 || !from[0].equals(outerFrom[0])) {
throw new AcmeInvalidMessageException("Protected 'From' header does not match envelope header");
}
}
Expand All @@ -233,13 +235,12 @@ private EmailProcessor(Message message, @Nullable MimeMessage signedMessage,
if (to == null) {
throw new AcmeInvalidMessageException("Message has no 'To' header");
}
if (to.length != 1) {
if (to.length != 1 || to[0] == null) {
throw new AcmeProtocolException("Message must have exactly one recipient, but has " + to.length);
}
if (strict && signedMessage != null) {
Address[] outerTo = message.getRecipients(TO);
if ((outerTo.length > 1) || (outerTo.length == 1 && outerTo[0] != null
&& !outerTo[0].equals(to[0]))) {
if (outerTo == null || outerTo.length != 1 || !to[0].equals(outerTo[0])) {
throw new AcmeInvalidMessageException("Protected 'To' header does not match envelope header");
}
}
Expand All @@ -249,9 +250,8 @@ private EmailProcessor(Message message, @Nullable MimeMessage signedMessage,
if (subject == null) {
throw new AcmeInvalidMessageException("Message has no 'Subject' header");
}
if (strict && signedMessage != null
&& message.getSubject() != null
&& !message.getSubject().equals(signedMessage.getSubject())) {
if (strict && signedMessage != null &&
(message.getSubject() == null || !message.getSubject().equals(signedMessage.getSubject()))) {
throw new AcmeInvalidMessageException("Protected 'Subject' header does not match envelope header");
}
Matcher m = SUBJECT_PATTERN.matcher(subject);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ protected InternetAddress email(String address) {
*
* @param name
* Name of the mock message to be read from the test resources.
* @return Mock {@link Message} that was created
* @return Mock {@link MimeMessage} that was created
*/
protected Message mockMessage(String name) {
protected MimeMessage mockMessage(String name) {
try (InputStream in = SMIMETests.class.getResourceAsStream("/email/" + name + ".eml")) {
return new MimeMessage(mailSession, in);
} catch (IOException ex) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,19 +67,21 @@ public void testEmailParser() throws AcmeInvalidMessageException {
}

@Test
public void testValidSignature() throws AcmeInvalidMessageException, IOException {
MimeMessage message = (MimeMessage) mockMessage("valid-mail");
X509Certificate certificate = readCertificate("valid-signer");
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
public void testValidSignature() {
assertThatNoException().isThrownBy(() -> {
MimeMessage message = mockMessage("valid-mail");
X509Certificate certificate = readCertificate("valid-signer");
EmailProcessor.smimeMessage(message, mailSession, certificate, true);
});
}

@Test
public void testInvalidSignature() {
assertThatExceptionOfType(AcmeInvalidMessageException.class)
.isThrownBy(() -> {
MimeMessage message = (MimeMessage) mockMessage("invalid-signed-mail");
MimeMessage message = mockMessage("invalid-signed-mail");
X509Certificate certificate = readCertificate("valid-signer");
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
EmailProcessor.smimeMessage(message, mailSession, certificate, true);
})
.withMessage("The S/MIME signature is invalid");
}
Expand All @@ -88,9 +90,9 @@ public void testInvalidSignature() {
public void testValidSignatureButNoSAN() {
assertThatExceptionOfType(AcmeInvalidMessageException.class)
.isThrownBy(() -> {
MimeMessage message = (MimeMessage) mockMessage("invalid-nosan");
MimeMessage message = mockMessage("invalid-nosan");
X509Certificate certificate = readCertificate("valid-signer-nosan");
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
EmailProcessor.smimeMessage(message, mailSession, certificate, true);
})
.withMessage("Signing certificate does not provide a rfc822Name subjectAltName");
}
Expand All @@ -99,9 +101,9 @@ public void testValidSignatureButNoSAN() {
public void testSANDoesNotMatchFrom() {
assertThatExceptionOfType(AcmeInvalidMessageException.class)
.isThrownBy(() -> {
MimeMessage message = (MimeMessage) mockMessage("invalid-cert-mismatch");
MimeMessage message = mockMessage("invalid-cert-mismatch");
X509Certificate certificate = readCertificate("valid-signer");
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
EmailProcessor.smimeMessage(message, mailSession, certificate, true);
})
.withMessage("Sender '[email protected]' was not found in signing certificate");
}
Expand All @@ -110,9 +112,9 @@ public void testSANDoesNotMatchFrom() {
public void testInvalidProtectedFromHeader() {
assertThatExceptionOfType(AcmeInvalidMessageException.class)
.isThrownBy(() -> {
MimeMessage message = (MimeMessage) mockMessage("invalid-protected-mail-from");
MimeMessage message = mockMessage("invalid-protected-mail-from");
X509Certificate certificate = readCertificate("valid-signer");
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
EmailProcessor.smimeMessage(message, mailSession, certificate, true);
})
.withMessage("Protected 'From' header does not match envelope header");
}
Expand All @@ -121,9 +123,9 @@ public void testInvalidProtectedFromHeader() {
public void testInvalidProtectedToHeader() {
assertThatExceptionOfType(AcmeInvalidMessageException.class)
.isThrownBy(() -> {
MimeMessage message = (MimeMessage) mockMessage("invalid-protected-mail-to");
MimeMessage message = mockMessage("invalid-protected-mail-to");
X509Certificate certificate = readCertificate("valid-signer");
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
EmailProcessor.smimeMessage(message, mailSession, certificate, true);
})
.withMessage("Protected 'To' header does not match envelope header");
}
Expand All @@ -132,9 +134,9 @@ public void testInvalidProtectedToHeader() {
public void testInvalidProtectedSubjectHeader() {
assertThatExceptionOfType(AcmeInvalidMessageException.class)
.isThrownBy(() -> {
MimeMessage message = (MimeMessage) mockMessage("invalid-protected-mail-subject");
MimeMessage message = mockMessage("invalid-protected-mail-subject");
X509Certificate certificate = readCertificate("valid-signer");
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
EmailProcessor.smimeMessage(message, mailSession, certificate, true);
})
.withMessage("Protected 'Subject' header does not match envelope header");
}
Expand All @@ -143,66 +145,80 @@ public void testInvalidProtectedSubjectHeader() {
public void testNonStrictInvalidProtectedSubjectHeader() {
assertThatNoException()
.isThrownBy(() -> {
MimeMessage message = (MimeMessage) mockMessage("invalid-protected-mail-subject");
MimeMessage message = mockMessage("invalid-protected-mail-subject");
X509Certificate certificate = readCertificate("valid-signer");
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, false);
EmailProcessor.smimeMessage(message, mailSession, certificate, false);
});
}

@Test
public void textExpectedFromFails() {
assertThrows(AcmeProtocolException.class, () -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.expectedFrom(expectedTo);
});
assertThatExceptionOfType(AcmeProtocolException.class)
.isThrownBy(() -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.expectedFrom(expectedTo);
})
.withMessage("Message is not sent by the expected sender");
}

@Test
public void textExpectedToFails() {
assertThrows(AcmeProtocolException.class, () -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.expectedTo(expectedFrom);
});
assertThatExceptionOfType(AcmeProtocolException.class)
.isThrownBy(() -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.expectedTo(expectedFrom);
})
.withMessage("Message is not addressed to expected recipient");
}

@Test
public void textExpectedIdentifierFails1() {
assertThrows(AcmeProtocolException.class, () -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.expectedIdentifier(EmailIdentifier.email(expectedFrom));
});
assertThatExceptionOfType(AcmeProtocolException.class)
.isThrownBy(() -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.expectedIdentifier(EmailIdentifier.email(expectedFrom));
})
.withMessage("Message is not addressed to expected recipient");
}

@Test
public void textExpectedIdentifierFails2() {
assertThrows(AcmeProtocolException.class, () -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.expectedIdentifier(Identifier.ip("192.168.0.1"));
});
assertThatExceptionOfType(AcmeProtocolException.class)
.isThrownBy(() -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.expectedIdentifier(Identifier.ip("192.168.0.1"));
})
.withMessage("Wrong identifier type: ip");
}

@Test
public void textNoChallengeFails1() {
assertThrows(IllegalStateException.class, () -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.getToken();
});
assertThatExceptionOfType(IllegalStateException.class)
.isThrownBy(() -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.getToken();
})
.withMessage("No challenge has been set yet");
}

@Test
public void textNoChallengeFails2() {
assertThrows(IllegalStateException.class, () -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.getAuthorization();
});
assertThatExceptionOfType(IllegalStateException.class)
.isThrownBy(() -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.getAuthorization();
})
.withMessage("No challenge has been set yet");
}

@Test
public void textNoChallengeFails3() {
assertThrows(IllegalStateException.class, () -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.respond();
});
assertThatExceptionOfType(IllegalStateException.class)
.isThrownBy(() -> {
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.respond();
})
.withMessage("No challenge has been set yet");
}

@Test
Expand All @@ -218,11 +234,13 @@ public void testChallenge() throws AcmeInvalidMessageException {

@Test
public void testChallengeMismatch() {
assertThrows(AcmeProtocolException.class, () -> {
EmailReply00Challenge challenge = mockChallenge("emailReplyChallengeMismatch");
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.withChallenge(challenge);
});
assertThatExceptionOfType(AcmeProtocolException.class)
.isThrownBy(() -> {
EmailReply00Challenge challenge = mockChallenge("emailReplyChallengeMismatch");
EmailProcessor processor = EmailProcessor.plainMessage(message);
processor.withChallenge(challenge);
})
.withMessage("Message is not sent by the expected sender");
}

@Test
Expand Down

0 comments on commit ef5ca28

Please sign in to comment.