mirror of https://github.com/shred/acme4j
Add support for S/MIME signature validation
parent
1ee68e1e09
commit
636ccc37e0
|
@ -27,7 +27,7 @@ It is an independent open source implementation that is not affiliated with or e
|
|||
* [jose4j](https://bitbucket.org/b_c/jose4j/wiki/Home)
|
||||
* [slf4j](http://www.slf4j.org/)
|
||||
* For `acme4j-utils`: [Bouncy Castle](https://www.bouncycastle.org/)
|
||||
* For `acme4j-smime`: [Jakarta Mail](https://eclipse-ee4j.github.io/mail/)
|
||||
* For `acme4j-smime`: [Jakarta Mail](https://eclipse-ee4j.github.io/mail/), [Bouncy Castle](https://www.bouncycastle.org/)
|
||||
|
||||
## Usage
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
*.eml text eol=crlf
|
|
@ -49,6 +49,11 @@
|
|||
<artifactId>bcpkix-jdk18on</artifactId>
|
||||
<version>${bouncycastle.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.bouncycastle</groupId>
|
||||
<artifactId>bcjmail-jdk18on</artifactId>
|
||||
<version>${bouncycastle.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
|
|
|
@ -18,13 +18,17 @@ module org.shredzone.acme4j.smime {
|
|||
|
||||
requires transitive jakarta.mail;
|
||||
requires static com.github.spotbugs.annotations;
|
||||
requires org.bouncycastle.util;
|
||||
requires org.bouncycastle.mail;
|
||||
requires org.bouncycastle.pkix;
|
||||
requires org.bouncycastle.provider;
|
||||
requires org.slf4j;
|
||||
|
||||
exports org.shredzone.acme4j.smime;
|
||||
exports org.shredzone.acme4j.smime.challenge;
|
||||
exports org.shredzone.acme4j.smime.csr;
|
||||
exports org.shredzone.acme4j.smime.email;
|
||||
exports org.shredzone.acme4j.smime.exception;
|
||||
|
||||
provides org.shredzone.acme4j.provider.ChallengeProvider
|
||||
with org.shredzone.acme4j.smime.challenge.EmailReply00ChallengeProvider;
|
||||
|
|
|
@ -16,38 +16,56 @@ package org.shredzone.acme4j.smime.email;
|
|||
import static java.util.Objects.requireNonNull;
|
||||
import static jakarta.mail.Message.RecipientType.TO;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.security.cert.CertificateParsingException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.CheckForNull;
|
||||
import edu.umd.cs.findbugs.annotations.Nullable;
|
||||
import jakarta.mail.Address;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.Session;
|
||||
import jakarta.mail.internet.AddressException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import jakarta.mail.internet.MimeMultipart;
|
||||
import org.bouncycastle.cms.CMSException;
|
||||
import org.bouncycastle.cms.SignerInformation;
|
||||
import org.bouncycastle.cms.SignerInformationVerifier;
|
||||
import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
|
||||
import org.bouncycastle.mail.smime.SMIMESigned;
|
||||
import org.bouncycastle.operator.OperatorCreationException;
|
||||
import org.shredzone.acme4j.Identifier;
|
||||
import org.shredzone.acme4j.Login;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.smime.challenge.EmailReply00Challenge;
|
||||
import org.shredzone.acme4j.smime.exception.AcmeInvalidMessageException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A processor for incoming "Challenge" emails.
|
||||
* <p>
|
||||
* Note that according to RFC-8823, the incoming mail must be DKIM or S/MIME signed, and
|
||||
* the signature must be validated. This is <em>not</em> done by this processor, because
|
||||
* it is usually checked by the inbound MTA.
|
||||
*
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8823">RFC 8823</a>
|
||||
* @since 2.12
|
||||
*/
|
||||
public final class EmailProcessor {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(EmailProcessor.class);
|
||||
private static final Pattern SUBJECT_PATTERN = Pattern.compile("ACME:\\s+([0-9A-Za-z_\\s-]+=?)\\s*");
|
||||
private static final int RFC822NAME = 1;
|
||||
|
||||
private final String token1;
|
||||
private final Optional<String> messageId;
|
||||
|
@ -56,42 +74,186 @@ public final class EmailProcessor {
|
|||
private final Collection<InternetAddress> replyTo;
|
||||
private final AtomicReference<EmailReply00Challenge> challengeRef = new AtomicReference<>();
|
||||
|
||||
/**
|
||||
* Processes the given e-mail message.
|
||||
* <p>
|
||||
* Note that according to RFC-8823, the challenge message must be signed using either
|
||||
* DKIM or S/MIME. This method does not do any DKIM or S/MIME validation, and assumes
|
||||
* that this has already been done by the inbound MTA.
|
||||
*
|
||||
* @param message
|
||||
* E-mail that was received from the CA. The inbound MTA has already taken
|
||||
* care of DKIM and/or S/MIME validation.
|
||||
* @return EmailProcessor for this e-mail
|
||||
* @throws AcmeInvalidMessageException
|
||||
* if a validation failed, and the message <em>must</em> be rejected.
|
||||
* @since 2.15
|
||||
*/
|
||||
public static EmailProcessor plainMessage(Message message)
|
||||
throws AcmeInvalidMessageException {
|
||||
return new EmailProcessor(message, null, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an S/MIME validation and processes the given e-mail message.
|
||||
* <p>
|
||||
* The owner of the given certificate must be the sender of that email.
|
||||
*
|
||||
* @param message
|
||||
* E-mail that was received from the CA.
|
||||
* @param mailSession
|
||||
* A {@link Session} that can be used for processing inner e-mails.
|
||||
* @param signCert
|
||||
* The signing certificate of the sender.
|
||||
* @param strict
|
||||
* If {@code true}, the S/MIME protected headers "From", "To", and "Subject"
|
||||
* <em>must</em> match the headers of the received message. If {@code false},
|
||||
* only the S/MIME protected headers are used, and the headers of the received
|
||||
* message are ignored.
|
||||
* @return EmailProcessor for this e-mail
|
||||
* @throws AcmeInvalidMessageException
|
||||
* if a validation failed, and the message <em>must</em> be rejected.
|
||||
* @since 2.15
|
||||
*/
|
||||
public static EmailProcessor smimeMessage(Message message, Session mailSession,
|
||||
X509Certificate signCert, boolean strict)
|
||||
throws AcmeInvalidMessageException {
|
||||
try {
|
||||
if (!(message instanceof MimeMessage)) {
|
||||
throw new AcmeInvalidMessageException("Not a S/MIME message");
|
||||
}
|
||||
MimeMessage mimeMessage = (MimeMessage) message;
|
||||
|
||||
if (!(mimeMessage.getContent() instanceof MimeMultipart)) {
|
||||
throw new AcmeProtocolException("S/MIME signed email must contain MimeMultipart");
|
||||
}
|
||||
MimeMultipart mp = (MimeMultipart) message.getContent();
|
||||
|
||||
SMIMESigned signed = new SMIMESigned(mp);
|
||||
|
||||
SignerInformationVerifier verifier = new JcaSimpleSignerInfoVerifierBuilder().build(signCert);
|
||||
boolean hasMatch = false;
|
||||
for (SignerInformation signer : signed.getSignerInfos().getSigners()) {
|
||||
hasMatch |= signer.verify(verifier);
|
||||
}
|
||||
if (!hasMatch) {
|
||||
throw new AcmeInvalidMessageException("The S/MIME signature is invalid");
|
||||
}
|
||||
|
||||
MimeMessage content = signed.getContentAsMimeMessage(mailSession);
|
||||
if (!content.getContentType().equalsIgnoreCase("message/rfc822; forwarded=no")) {
|
||||
throw new AcmeInvalidMessageException("Message does not contain protected headers");
|
||||
}
|
||||
|
||||
MimeMessage body = new MimeMessage(mailSession, content.getInputStream());
|
||||
|
||||
List<Address> validFromAddresses = Optional.ofNullable(signCert.getSubjectAlternativeNames())
|
||||
.orElseGet(Collections::emptyList)
|
||||
.stream()
|
||||
.filter(l -> ((Number) l.get(0)).intValue() == RFC822NAME)
|
||||
.map(l -> l.get(1).toString())
|
||||
.map(l -> {
|
||||
try {
|
||||
return new InternetAddress(l);
|
||||
} catch (AddressException ex) {
|
||||
// Ignore invalid email addresses
|
||||
LOG.debug("Certificate contains invalid e-mail address {}", l, ex);
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (validFromAddresses.isEmpty()) {
|
||||
throw new AcmeInvalidMessageException("Signing certificate does not provide a rfc822Name subjectAltName");
|
||||
}
|
||||
|
||||
return new EmailProcessor(message, body, strict, validFromAddresses);
|
||||
} catch (IOException | MessagingException | CMSException | OperatorCreationException |
|
||||
CertificateParsingException ex) {
|
||||
throw new AcmeInvalidMessageException("Invalid S/MIME mail", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link EmailProcessor} for the incoming "Challenge" message.
|
||||
* <p>
|
||||
* The incoming message is validated against the requirements of RFC-8823. An {@link
|
||||
* AcmeProtocolException} is thrown if the validation fails. DKIM or S/MIME signature
|
||||
* is <em>not</em> checked by the processor, and must be checked elsewhere (usually by
|
||||
* the inbound MTA).
|
||||
* The incoming message is validated against the requirements of RFC-8823.
|
||||
*
|
||||
* @param message
|
||||
* "Challenge" message as it was sent by the CA.
|
||||
* @throws AcmeProtocolException
|
||||
* if the incoming message is not a valid "challenge" message according to
|
||||
* RFC-8823.
|
||||
* @param signedMessage
|
||||
* The signed part of the challenge message if present, or {@code null}. The
|
||||
* signature is assumed to be valid, and must be validated in a previous
|
||||
* step.
|
||||
* @param strict
|
||||
* If {@code true}, the S/MIME protected headers "From", "To", and "Subject"
|
||||
* <em>must</em> match the headers of the received message. If {@code false},
|
||||
* only the S/MIME protected headers are used, and the headers of the received
|
||||
* message are ignored.
|
||||
* @param validFromAddresses
|
||||
* A {@link List} of {@link Address} that were found in the certificate's
|
||||
* rfc822Name subjectAltName extension. The mail's From address <em>must</em>
|
||||
* be found in this list, otherwise the signed message will be rejected.
|
||||
* {@code null} to disable this validation step.
|
||||
* @throws AcmeInvalidMessageException
|
||||
* if a validation failed, and the message <em>must</em> be rejected.
|
||||
*/
|
||||
public EmailProcessor(Message message) {
|
||||
private EmailProcessor(Message message, @Nullable MimeMessage signedMessage,
|
||||
boolean strict, @Nullable List<Address> validFromAddresses)
|
||||
throws AcmeInvalidMessageException {
|
||||
requireNonNull(message, "message");
|
||||
|
||||
// Validate challenge and extract token 1
|
||||
try {
|
||||
if (!isAutoGenerated(message)) {
|
||||
throw new AcmeProtocolException("Message is not auto-generated");
|
||||
if (!isAutoGenerated(getOptional(m -> m.getHeader("Auto-Submitted"), message, signedMessage))) {
|
||||
throw new AcmeInvalidMessageException("Message is not auto-generated");
|
||||
}
|
||||
|
||||
Address[] from = message.getFrom();
|
||||
Address[] from = getMandatory(Message::getFrom, message, signedMessage, "From");
|
||||
if (from == null) {
|
||||
throw new AcmeInvalidMessageException("Message has no 'From' header");
|
||||
}
|
||||
if (from.length != 1) {
|
||||
throw new AcmeProtocolException("Message must have exactly one sender, but has " + from.length);
|
||||
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]))) {
|
||||
throw new AcmeInvalidMessageException("Protected 'From' header does not match envelope header");
|
||||
}
|
||||
}
|
||||
sender = new InternetAddress(from[0].toString());
|
||||
|
||||
Address[] to = message.getRecipients(TO);
|
||||
Address[] to = getMandatory(m -> m.getRecipients(TO), message, signedMessage, "To");
|
||||
if (to == null) {
|
||||
throw new AcmeInvalidMessageException("Message has no 'To' header");
|
||||
}
|
||||
if (to.length != 1) {
|
||||
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]))) {
|
||||
throw new AcmeInvalidMessageException("Protected 'To' header does not match envelope header");
|
||||
}
|
||||
}
|
||||
recipient = new InternetAddress(to[0].toString());
|
||||
|
||||
String subject = message.getSubject();
|
||||
String subject = getMandatory(Message::getSubject, message, signedMessage, "Subject");
|
||||
if (subject == null) {
|
||||
throw new AcmeInvalidMessageException("Message has no 'Subject' header");
|
||||
}
|
||||
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);
|
||||
if (!m.matches()) {
|
||||
throw new AcmeProtocolException("Invalid subject: " + subject);
|
||||
|
@ -99,7 +261,7 @@ public final class EmailProcessor {
|
|||
// white spaces within the token part must be ignored
|
||||
this.token1 = m.group(1).replaceAll("\\s+", "");
|
||||
|
||||
Address[] rto = message.getReplyTo();
|
||||
Address[] rto = getOptional(Message::getReplyTo, message, signedMessage);
|
||||
if (rto != null) {
|
||||
replyTo = Collections.unmodifiableList(Arrays.stream(rto)
|
||||
.filter(InternetAddress.class::isInstance)
|
||||
|
@ -109,7 +271,7 @@ public final class EmailProcessor {
|
|||
replyTo = Collections.emptyList();
|
||||
}
|
||||
|
||||
String[] mid = message.getHeader("Message-ID");
|
||||
String[] mid = getOptional(n -> n.getHeader("Message-ID"), message, signedMessage);
|
||||
if (mid != null && mid.length > 0) {
|
||||
messageId = Optional.of(mid[0]);
|
||||
} else {
|
||||
|
@ -297,16 +459,78 @@ public final class EmailProcessor {
|
|||
return new ResponseGenerator(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an optional property from the message.
|
||||
* <p>
|
||||
* Optional property means: If there is a signed message, try to fetch the property
|
||||
* from there. If the property is not present, fetch it from the unsigned message
|
||||
* instead. If it's also not there, return {@code null}.
|
||||
*
|
||||
* @param getter
|
||||
* The getter method of {@link Message} to be invoked
|
||||
* @param message
|
||||
* The outer (unsigned) {@link Message} that serves as fallback
|
||||
* @param signedMessage
|
||||
* The signed (inner) {@link Message} where the property is looked up first
|
||||
* @param <T>
|
||||
* The expected result type
|
||||
* @return The mail property, or {@code null} if not found
|
||||
*/
|
||||
@CheckForNull
|
||||
private <T> T getOptional(MessageFunction<Message, T> getter, Message message, @Nullable Message signedMessage)
|
||||
throws MessagingException {
|
||||
if (signedMessage != null) {
|
||||
T result = getter.apply(signedMessage);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return getter.apply(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a mandatory property from the message.
|
||||
* <p>
|
||||
* Mandatory means: If there is a signed message, the property <em>must</em> be
|
||||
* present there. The unsigned message is only queried as fallback if there is no
|
||||
* signed message at all.
|
||||
*
|
||||
* @param getter
|
||||
* The getter method of {@link Message} to be invoked
|
||||
* @param message
|
||||
* The outer (unsigned) {@link Message} that serves as fallback if there is
|
||||
* no signed message.
|
||||
* @param signedMessage
|
||||
* The signed (inner) {@link Message} where the property is expected, or
|
||||
* {@code null} if there is no signed message.
|
||||
* @param header
|
||||
* Name of the expected header
|
||||
* @param <T>
|
||||
* The expected result type
|
||||
* @return The mail property, or {@code null} if not found
|
||||
*/
|
||||
@CheckForNull
|
||||
private <T> T getMandatory(MessageFunction<Message, T> getter, Message message, @Nullable Message signedMessage, String header)
|
||||
throws MessagingException, AcmeInvalidMessageException {
|
||||
if (signedMessage != null) {
|
||||
T value = getter.apply(signedMessage);
|
||||
if (value == null) {
|
||||
throw new AcmeInvalidMessageException("Protected header '" + header + "' expected, but missing.");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
return getter.apply(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this message is "auto-generated".
|
||||
*
|
||||
* @param message
|
||||
* Message to check.
|
||||
* @param autoSubmitted
|
||||
* Auto-Submitted header content
|
||||
* @return {@code true} if the mail was auto-generated.
|
||||
*/
|
||||
private boolean isAutoGenerated(Message message) throws MessagingException {
|
||||
String[] autoSubmitted = message.getHeader("Auto-Submitted");
|
||||
if (autoSubmitted == null) {
|
||||
private boolean isAutoGenerated(@Nullable String[] autoSubmitted) throws MessagingException {
|
||||
if (autoSubmitted == null || autoSubmitted.length == 0) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.stream(autoSubmitted)
|
||||
|
@ -323,4 +547,10 @@ public final class EmailProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
private interface MessageFunction<M extends Message, R> {
|
||||
@CheckForNull
|
||||
R apply(M message) throws MessagingException;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,9 +28,8 @@ import jakarta.mail.internet.MimeMessage;
|
|||
/**
|
||||
* A helper for creating an email response to the "challenge" email.
|
||||
* <p>
|
||||
* According to RFC-8823, the response email must have a DKIM or S/MIME signature. This is
|
||||
* <em>not</em> done by the response generator, because it is usually performed by the
|
||||
* outbound MTA.
|
||||
* According to RFC-8823, the response email <em>must</em> be DKIM signed. This is
|
||||
* <em>not</em> done by the response generator, but must be done by the outbound MTA.
|
||||
*
|
||||
* @see <a href="https://datatracker.ietf.org/doc/html/rfc8823">RFC 8823</a>
|
||||
* @since 2.12
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* acme4j - Java ACME client
|
||||
*
|
||||
* Copyright (C) 2022 Richard "Shred" Körber
|
||||
* http://acme4j.shredzone.org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
package org.shredzone.acme4j.smime.exception;
|
||||
|
||||
import org.shredzone.acme4j.exception.AcmeException;
|
||||
|
||||
/**
|
||||
* This exception is thrown when the challenge message is invalid.
|
||||
* <p>
|
||||
* If this exception is thrown, the challenge message does not match the actual challenge,
|
||||
* and <em>must</em> be rejected.
|
||||
* <p>
|
||||
* Reasons may be:
|
||||
* <ul>
|
||||
* <li>Unexpected sender address</li>
|
||||
* <li>Bad S/MIME signature</li>
|
||||
* </ul>
|
||||
*
|
||||
* @since 2.15
|
||||
*/
|
||||
public class AcmeInvalidMessageException extends AcmeException {
|
||||
private static final long serialVersionUID = 5607857024718309330L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link AcmeInvalidMessageException}.
|
||||
*
|
||||
* @param msg
|
||||
* Reason of the exception
|
||||
*/
|
||||
public AcmeInvalidMessageException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AcmeInvalidMessageException}.
|
||||
*
|
||||
* @param msg
|
||||
* Reason of the exception
|
||||
* @param cause
|
||||
* Cause
|
||||
*/
|
||||
public AcmeInvalidMessageException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* acme4j - Java ACME client
|
||||
*
|
||||
* Copyright (C) 2022 Richard "Shred" Körber
|
||||
* http://acme4j.shredzone.org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
@ReturnValuesAreNonnullByDefault
|
||||
@DefaultAnnotationForParameters(NonNull.class)
|
||||
@DefaultAnnotationForFields(NonNull.class)
|
||||
package org.shredzone.acme4j.smime.exception;
|
||||
|
||||
import edu.umd.cs.findbugs.annotations.DefaultAnnotationForFields;
|
||||
import edu.umd.cs.findbugs.annotations.DefaultAnnotationForParameters;
|
||||
import edu.umd.cs.findbugs.annotations.NonNull;
|
||||
import edu.umd.cs.findbugs.annotations.ReturnValuesAreNonnullByDefault;
|
|
@ -23,6 +23,9 @@ import java.io.Reader;
|
|||
import java.io.UncheckedIOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.KeyPair;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Properties;
|
||||
|
||||
import jakarta.mail.Message;
|
||||
|
@ -125,4 +128,20 @@ public abstract class SMIMETests {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a certificate from the given resource.
|
||||
*
|
||||
* @param name
|
||||
* Resource name of the certificate
|
||||
* @return X509Certificate that was read
|
||||
*/
|
||||
protected X509Certificate readCertificate(String name) throws IOException {
|
||||
try (InputStream in = SMIMETests.class.getResourceAsStream("/" + name + ".pem")) {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
return (X509Certificate) cf.generateCertificate(in);
|
||||
} catch (CertificateException ex) {
|
||||
throw new IOException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -14,21 +14,27 @@
|
|||
package org.shredzone.acme4j.smime.email;
|
||||
|
||||
import static jakarta.mail.Message.RecipientType.TO;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.Security;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Optional;
|
||||
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.InternetAddress;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.shredzone.acme4j.Identifier;
|
||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||
import org.shredzone.acme4j.smime.EmailIdentifier;
|
||||
import org.shredzone.acme4j.smime.SMIMETests;
|
||||
import org.shredzone.acme4j.smime.challenge.EmailReply00Challenge;
|
||||
import org.shredzone.acme4j.smime.exception.AcmeInvalidMessageException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link EmailProcessor} and {@link ResponseGenerator}.
|
||||
|
@ -40,9 +46,14 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
private final InternetAddress expectedReplyTo = email("acme-validator@example.org");
|
||||
private final Message message = mockMessage("challenge");
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
Security.addProvider(new BouncyCastleProvider());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmailParser() throws MessagingException {
|
||||
EmailProcessor processor = new EmailProcessor(message);
|
||||
public void testEmailParser() throws AcmeInvalidMessageException {
|
||||
EmailProcessor processor = EmailProcessor.plainMessage(message);
|
||||
processor.expectedFrom(expectedFrom);
|
||||
processor.expectedTo(expectedTo);
|
||||
processor.expectedIdentifier(EmailIdentifier.email(expectedTo));
|
||||
|
@ -55,10 +66,93 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
assertThat(processor.getReplyTo()).contains(email("acme-validator@example.org"));
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidSignature() {
|
||||
assertThatExceptionOfType(AcmeInvalidMessageException.class)
|
||||
.isThrownBy(() -> {
|
||||
MimeMessage message = (MimeMessage) mockMessage("invalid-signed-mail");
|
||||
X509Certificate certificate = readCertificate("valid-signer");
|
||||
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
|
||||
})
|
||||
.withMessage("The S/MIME signature is invalid");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidSignatureButNoSAN() {
|
||||
assertThatExceptionOfType(AcmeInvalidMessageException.class)
|
||||
.isThrownBy(() -> {
|
||||
MimeMessage message = (MimeMessage) mockMessage("invalid-nosan");
|
||||
X509Certificate certificate = readCertificate("valid-signer-nosan");
|
||||
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
|
||||
})
|
||||
.withMessage("Signing certificate does not provide a rfc822Name subjectAltName");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSANDoesNotMatchFrom() {
|
||||
assertThatExceptionOfType(AcmeInvalidMessageException.class)
|
||||
.isThrownBy(() -> {
|
||||
MimeMessage message = (MimeMessage) mockMessage("invalid-cert-mismatch");
|
||||
X509Certificate certificate = readCertificate("valid-signer");
|
||||
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
|
||||
})
|
||||
.withMessage("Sender 'different-ca@example.com' was not found in signing certificate");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidProtectedFromHeader() {
|
||||
assertThatExceptionOfType(AcmeInvalidMessageException.class)
|
||||
.isThrownBy(() -> {
|
||||
MimeMessage message = (MimeMessage) mockMessage("invalid-protected-mail-from");
|
||||
X509Certificate certificate = readCertificate("valid-signer");
|
||||
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
|
||||
})
|
||||
.withMessage("Protected 'From' header does not match envelope header");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidProtectedToHeader() {
|
||||
assertThatExceptionOfType(AcmeInvalidMessageException.class)
|
||||
.isThrownBy(() -> {
|
||||
MimeMessage message = (MimeMessage) mockMessage("invalid-protected-mail-to");
|
||||
X509Certificate certificate = readCertificate("valid-signer");
|
||||
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
|
||||
})
|
||||
.withMessage("Protected 'To' header does not match envelope header");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvalidProtectedSubjectHeader() {
|
||||
assertThatExceptionOfType(AcmeInvalidMessageException.class)
|
||||
.isThrownBy(() -> {
|
||||
MimeMessage message = (MimeMessage) mockMessage("invalid-protected-mail-subject");
|
||||
X509Certificate certificate = readCertificate("valid-signer");
|
||||
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, true);
|
||||
})
|
||||
.withMessage("Protected 'Subject' header does not match envelope header");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonStrictInvalidProtectedSubjectHeader() {
|
||||
assertThatNoException()
|
||||
.isThrownBy(() -> {
|
||||
MimeMessage message = (MimeMessage) mockMessage("invalid-protected-mail-subject");
|
||||
X509Certificate certificate = readCertificate("valid-signer");
|
||||
EmailProcessor processor = EmailProcessor.smimeMessage(message, mailSession, certificate, false);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void textExpectedFromFails() {
|
||||
assertThrows(AcmeProtocolException.class, () -> {
|
||||
EmailProcessor processor = new EmailProcessor(message);
|
||||
EmailProcessor processor = EmailProcessor.plainMessage(message);
|
||||
processor.expectedFrom(expectedTo);
|
||||
});
|
||||
}
|
||||
|
@ -66,7 +160,7 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
@Test
|
||||
public void textExpectedToFails() {
|
||||
assertThrows(AcmeProtocolException.class, () -> {
|
||||
EmailProcessor processor = new EmailProcessor(message);
|
||||
EmailProcessor processor = EmailProcessor.plainMessage(message);
|
||||
processor.expectedTo(expectedFrom);
|
||||
});
|
||||
}
|
||||
|
@ -74,7 +168,7 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
@Test
|
||||
public void textExpectedIdentifierFails1() {
|
||||
assertThrows(AcmeProtocolException.class, () -> {
|
||||
EmailProcessor processor = new EmailProcessor(message);
|
||||
EmailProcessor processor = EmailProcessor.plainMessage(message);
|
||||
processor.expectedIdentifier(EmailIdentifier.email(expectedFrom));
|
||||
});
|
||||
}
|
||||
|
@ -82,7 +176,7 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
@Test
|
||||
public void textExpectedIdentifierFails2() {
|
||||
assertThrows(AcmeProtocolException.class, () -> {
|
||||
EmailProcessor processor = new EmailProcessor(message);
|
||||
EmailProcessor processor = EmailProcessor.plainMessage(message);
|
||||
processor.expectedIdentifier(Identifier.ip("192.168.0.1"));
|
||||
});
|
||||
}
|
||||
|
@ -90,7 +184,7 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
@Test
|
||||
public void textNoChallengeFails1() {
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
EmailProcessor processor = new EmailProcessor(message);
|
||||
EmailProcessor processor = EmailProcessor.plainMessage(message);
|
||||
processor.getToken();
|
||||
});
|
||||
}
|
||||
|
@ -98,7 +192,7 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
@Test
|
||||
public void textNoChallengeFails2() {
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
EmailProcessor processor = new EmailProcessor(message);
|
||||
EmailProcessor processor = EmailProcessor.plainMessage(message);
|
||||
processor.getAuthorization();
|
||||
});
|
||||
}
|
||||
|
@ -106,16 +200,16 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
@Test
|
||||
public void textNoChallengeFails3() {
|
||||
assertThrows(IllegalStateException.class, () -> {
|
||||
EmailProcessor processor = new EmailProcessor(message);
|
||||
EmailProcessor processor = EmailProcessor.plainMessage(message);
|
||||
processor.respond();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChallenge() {
|
||||
public void testChallenge() throws AcmeInvalidMessageException {
|
||||
EmailReply00Challenge challenge = mockChallenge("emailReplyChallenge");
|
||||
|
||||
EmailProcessor processor = new EmailProcessor(message);
|
||||
EmailProcessor processor = EmailProcessor.plainMessage(message);
|
||||
processor.withChallenge(challenge);
|
||||
assertThat(processor.getToken()).isEqualTo(TOKEN);
|
||||
assertThat(processor.getAuthorization()).isEqualTo(KEY_AUTHORIZATION);
|
||||
|
@ -126,16 +220,16 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
public void testChallengeMismatch() {
|
||||
assertThrows(AcmeProtocolException.class, () -> {
|
||||
EmailReply00Challenge challenge = mockChallenge("emailReplyChallengeMismatch");
|
||||
EmailProcessor processor = new EmailProcessor(message);
|
||||
EmailProcessor processor = EmailProcessor.plainMessage(message);
|
||||
processor.withChallenge(challenge);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponse() throws IOException, MessagingException {
|
||||
public void testResponse() throws IOException, MessagingException, AcmeInvalidMessageException {
|
||||
EmailReply00Challenge challenge = mockChallenge("emailReplyChallenge");
|
||||
|
||||
Message response = new EmailProcessor(message)
|
||||
Message response = EmailProcessor.plainMessage(message)
|
||||
.withChallenge(challenge)
|
||||
.respond()
|
||||
.generateResponse(mailSession);
|
||||
|
@ -144,10 +238,10 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testResponseWithHeaderFooter() throws IOException, MessagingException {
|
||||
public void testResponseWithHeaderFooter() throws IOException, MessagingException, AcmeInvalidMessageException {
|
||||
EmailReply00Challenge challenge = mockChallenge("emailReplyChallenge");
|
||||
|
||||
Message response = new EmailProcessor(message)
|
||||
Message response = EmailProcessor.plainMessage(message)
|
||||
.withChallenge(challenge)
|
||||
.respond()
|
||||
.withHeader("This is an introduction.")
|
||||
|
@ -161,10 +255,10 @@ public class EmailProcessorTest extends SMIMETests {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testResponseWithCallback() throws IOException, MessagingException {
|
||||
public void testResponseWithCallback() throws IOException, MessagingException, AcmeInvalidMessageException {
|
||||
EmailReply00Challenge challenge = mockChallenge("emailReplyChallenge");
|
||||
|
||||
Message response = new EmailProcessor(message)
|
||||
Message response = EmailProcessor.plainMessage(message)
|
||||
.withChallenge(challenge)
|
||||
.respond()
|
||||
.withGenerator((msg, body) -> msg.setContent("Head\r\n" + body + "Foot", "text/plain"))
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
From: different-ca@example.org
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Auto-Submitted: auto-generated; type=acme
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha1"; boundary="----6B6A5C5DBC60D7D16B6C08BF092D4185"
|
||||
|
||||
This is an S/MIME signed message
|
||||
|
||||
------6B6A5C5DBC60D7D16B6C08BF092D4185
|
||||
Content-Type: message/RFC822; forwarded=no
|
||||
|
||||
From: different-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
This is an automatically generated ACME challenge.
|
||||
|
||||
------6B6A5C5DBC60D7D16B6C08BF092D4185
|
||||
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="smime.p7s"
|
||||
|
||||
MIIGzQYJKoZIhvcNAQcCoIIGvjCCBroCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3
|
||||
DQEHAaCCA/4wggP6MIIC4qADAgECAhQoC/xUcLhcK13sGSiYxuUPf758tDANBgkq
|
||||
hkiG9w0BAQsFADB8MQswCQYDVQQGEwJYWDESMBAGA1UEBwwJQWNtZSBDaXR5MR4w
|
||||
HAYDVQQKDBVBY21lIENlcnRpZmljYXRlcyBMdGQxFDASBgNVBAMMC2V4YW1wbGUu
|
||||
Y29tMSMwIQYJKoZIhvcNAQkBFhR2YWxpZC1jYUBleGFtcGxlLmNvbTAeFw0yMjEx
|
||||
MDQxMjU1MzlaFw0zMjExMDExMjU1MzlaMHwxCzAJBgNVBAYTAlhYMRIwEAYDVQQH
|
||||
DAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNhdGVzIEx0ZDEUMBIG
|
||||
A1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZhbGlkLWNhQGV4YW1w
|
||||
bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzTyW1VRm+mQH
|
||||
YU5hZWgzgrPRkRzMLlLoCamlRs5DjGf3zIpo9a/17m60YfIXBJruImUBXxa5lp0Z
|
||||
qaayty+nZOpS0wBZSqTLuslZ0WuyyyW2DEBNO7jLW58cMn8MfAwMYjDcxtubNb7M
|
||||
AG9iZRj6wn6tKCsXtYUgAIpNhyPPtDuEZ5df1ecOnvlW2vO+MwytM8DLLtwolET/
|
||||
tPzOXPHDiyKjij02jyJ1DlZxptKudiKaBeY1WY/W/PpS6fGskTJQc/bZPgE3OP/9
|
||||
Y9Y1uzZTulkO3R6MlLNdLam32/ehpJvSWyfSbToyC2ejvaXoRChPFcAmTpqA0HPg
|
||||
h8sudiS14QIDAQABo3QwcjAdBgNVHQ4EFgQUR0gRYoOCPJYqFiPGwB141VTCXuIw
|
||||
HwYDVR0jBBgwFoAUR0gRYoOCPJYqFiPGwB141VTCXuIwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAfBgNVHREEGDAWgRR2YWxpZC1jYUBleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAJDQsNTWxVLNHBrVl6p6IetzeBt64GoWp6OP5C8/HY3dlznfbrn6ZvWBr
|
||||
Vsnc7VZ49r8r/QvRKRrljkIQuNwaW/LmRxJ1AVGGiorspmrdz0Lf2WOXnLH/+4lR
|
||||
q5dar5YmGqi9Mo2j5ALg/2MiO1PonuKs1eX9tLZCCeanXFexU0qaeFZelunJ6UUm
|
||||
BXpaGO1QfECcNnvarudosbe1ve6YGABn8MpAY+8zdYnYHPB8Pojhzvk7/8PMHoPu
|
||||
njDb3lZT+b8BDmNz+GISCUSHYkdK2rWh+8wqD3T5rOtzTqAPuSNeDNocUF6wzxem
|
||||
HWqvP7yM3VoXYvn7FA4NCa9mE3k8MzGCApcwggKTAgEBMIGUMHwxCzAJBgNVBAYT
|
||||
AlhYMRIwEAYDVQQHDAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNh
|
||||
dGVzIEx0ZDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZh
|
||||
bGlkLWNhQGV4YW1wbGUuY29tAhQoC/xUcLhcK13sGSiYxuUPf758tDAJBgUrDgMC
|
||||
GgUAoIHYMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X
|
||||
DTIyMTEwNDEzMzE1NVowIwYJKoZIhvcNAQkEMRYEFNE5fZJFFgePdLTkBjs3GMcD
|
||||
M5UyMHkGCSqGSIb3DQEJDzFsMGowCwYJYIZIAWUDBAEqMAsGCWCGSAFlAwQBFjAL
|
||||
BglghkgBZQMEAQIwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3
|
||||
DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIB
|
||||
AEN+8Cgvfw/72HPSSgJROYqScFrYTCRF7HTAk22zJCVzuh21rbEiPGLJ9Sy4ak/i
|
||||
BXvXtkX8YJBGuVYrx6QxoF8vmcwlIPVw9Qoc2FevyfRQD19hP7rd7miZ8LWu0B8v
|
||||
d54mr7aD5zQADLvQGlxjKvCSM3F8HF1KQrRZrfJbEL9NRrgYD7c8ZEAvisaoEfPO
|
||||
vRjsj9IzKg/RWhOAmh5n591ZNKVb8k0G+5lyCSuP8m/9k0sE705sVrq4sbgIgtFB
|
||||
HNVLwYvxb88F//rFosFW/njsnlgFx5hjpLbwKu6Du2Sd7L1oye/xUGlKDY8yuy2m
|
||||
pwKapV2IpD8TjsL7NZ7rJ5U=
|
||||
|
||||
------6B6A5C5DBC60D7D16B6C08BF092D4185--
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
From: valid-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Auto-Submitted: auto-generated; type=acme
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha1"; boundary="----47B1F5074B8F7A13042C44F61463F58F"
|
||||
|
||||
This is an S/MIME signed message
|
||||
|
||||
------47B1F5074B8F7A13042C44F61463F58F
|
||||
Content-Type: message/RFC822; forwarded=no
|
||||
|
||||
From: valid-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
This is an automatically generated ACME challenge.
|
||||
|
||||
------47B1F5074B8F7A13042C44F61463F58F
|
||||
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="smime.p7s"
|
||||
|
||||
MIIGrAYJKoZIhvcNAQcCoIIGnTCCBpkCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3
|
||||
DQEHAaCCA90wggPZMIICwaADAgECAhRPShCzW2lh0D89RfDJ5mos/gMAJjANBgkq
|
||||
hkiG9w0BAQsFADB8MQswCQYDVQQGEwJYWDESMBAGA1UEBwwJQWNtZSBDaXR5MR4w
|
||||
HAYDVQQKDBVBY21lIENlcnRpZmljYXRlcyBMdGQxFDASBgNVBAMMC2V4YW1wbGUu
|
||||
Y29tMSMwIQYJKoZIhvcNAQkBFhR2YWxpZC1jYUBleGFtcGxlLmNvbTAeFw0yMjEx
|
||||
MDQxMjU1MzlaFw0zMjExMDExMjU1MzlaMHwxCzAJBgNVBAYTAlhYMRIwEAYDVQQH
|
||||
DAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNhdGVzIEx0ZDEUMBIG
|
||||
A1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZhbGlkLWNhQGV4YW1w
|
||||
bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2BDJcOmFx6Tu
|
||||
W58rpO4FXbvF7ZoSpIOi4YWfSmD7LSHUq+xGx/vodijFT1Y6a74o4d+XeYTH/X4j
|
||||
FO9QPdzZDuG8t3ziFACctptaFywUjgYYJQGyPmfg3hn1Cz72q4tAqegOEwL78NA2
|
||||
YcEd6sx0udAF80C1QHi/kKBMDgj9AOyNyIZ/rBN8CZSkfkpPYWI99Fl/DOuYnr7k
|
||||
MN1TUWS1906mPqBslh1YVyp6fdGaL6DdlIY+ZE5c9BhST/t+7eLq7fnB5KB+tDvH
|
||||
D1qnL858K+5Hjfc9MUYTyffDiJaG9zHkEKi3zd0EGcaf1r+lskRqEIOqROjLSDim
|
||||
T5Q4CuHCYQIDAQABo1MwUTAdBgNVHQ4EFgQURoDGdRoZP6EOfLXTlNxWPDTRmp8w
|
||||
HwYDVR0jBBgwFoAURoDGdRoZP6EOfLXTlNxWPDTRmp8wDwYDVR0TAQH/BAUwAwEB
|
||||
/zANBgkqhkiG9w0BAQsFAAOCAQEAvVI9Yj8lL0cvdNY3RD/GQ/tQCGBAzoFTODJU
|
||||
wn4zE/LfiXfu8SxJhzcpjzKc2j+mxuwGh0OqraIO2FkpO23+X1gCdCt+ClE/6nMs
|
||||
8UMo4H1wMYYGhjkoLvsH9Ne5N+91PvLQG97LoLsoy+Y95ws23WyqUJ2g7A7Isk3v
|
||||
7MJZVH2d93hjbtWQ6+3/PP5zJwubEwiDAYvycODfvAig9+0QBIy+uE7XxnEhKxHJ
|
||||
pvN3p8NmLya7XH3v92N7M6CioyBqw8HL7I5lt5HBqa/U9USVMMmi9v+tFLZYyd7r
|
||||
7acw6hB7MDcLmtEu08Cgo89K23oTm1JBJZrjZUFbYcYP+fiuizGCApcwggKTAgEB
|
||||
MIGUMHwxCzAJBgNVBAYTAlhYMRIwEAYDVQQHDAlBY21lIENpdHkxHjAcBgNVBAoM
|
||||
FUFjbWUgQ2VydGlmaWNhdGVzIEx0ZDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xIzAh
|
||||
BgkqhkiG9w0BCQEWFHZhbGlkLWNhQGV4YW1wbGUuY29tAhRPShCzW2lh0D89RfDJ
|
||||
5mos/gMAJjAJBgUrDgMCGgUAoIHYMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEw
|
||||
HAYJKoZIhvcNAQkFMQ8XDTIyMTEwNDEzMzE1NVowIwYJKoZIhvcNAQkEMRYEFK+s
|
||||
B97I9ZGpDGUMWLsE3dCU/pbtMHkGCSqGSIb3DQEJDzFsMGowCwYJYIZIAWUDBAEq
|
||||
MAsGCWCGSAFlAwQBFjALBglghkgBZQMEAQIwCgYIKoZIhvcNAwcwDgYIKoZIhvcN
|
||||
AwICAgCAMA0GCCqGSIb3DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0G
|
||||
CSqGSIb3DQEBAQUABIIBAEvS2tccMXu/OG8fzgOWsf5MzjBdDD/6doTLuIJS7Ktv
|
||||
1alpT8ZqSBn4jOgrlM7efTFK8y1vlOdoFZIsfIe+92lclvgHc/2Dw4XB5SswZ59y
|
||||
fZH+AVtVpzi5oFYiunhBn19vRP9Bri4ma8gCRe7pUwN15Gap8gl3+UQtUY17wcME
|
||||
H7ALcuG0ETPTxz9p2ueN6FmrthmrDSaZVqW5nyTizgr0zSxicEcwfFz9JZGZFKyp
|
||||
lPSVrgCwZ1/yaWXlnBXPTdO/DmAvNUAjUk0HZFu+mnelzPPs3c5s4LY3pBNjDPE2
|
||||
i2hxgRjca2QMsveYdwZn8I/m1P7yatJ3EozHpO3T4Gc=
|
||||
|
||||
------47B1F5074B8F7A13042C44F61463F58F--
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
From: tampered-ca@example.org
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Auto-Submitted: auto-generated; type=acme
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha1"; boundary="----1FD9CF28CC0AD72EF1FF6D0511838F0E"
|
||||
|
||||
This is an S/MIME signed message
|
||||
|
||||
------1FD9CF28CC0AD72EF1FF6D0511838F0E
|
||||
Content-Type: message/RFC822; forwarded=no
|
||||
|
||||
From: valid-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
This is an automatically generated ACME challenge.
|
||||
|
||||
------1FD9CF28CC0AD72EF1FF6D0511838F0E
|
||||
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="smime.p7s"
|
||||
|
||||
MIIGzQYJKoZIhvcNAQcCoIIGvjCCBroCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3
|
||||
DQEHAaCCA/4wggP6MIIC4qADAgECAhQoC/xUcLhcK13sGSiYxuUPf758tDANBgkq
|
||||
hkiG9w0BAQsFADB8MQswCQYDVQQGEwJYWDESMBAGA1UEBwwJQWNtZSBDaXR5MR4w
|
||||
HAYDVQQKDBVBY21lIENlcnRpZmljYXRlcyBMdGQxFDASBgNVBAMMC2V4YW1wbGUu
|
||||
Y29tMSMwIQYJKoZIhvcNAQkBFhR2YWxpZC1jYUBleGFtcGxlLmNvbTAeFw0yMjEx
|
||||
MDQxMjU1MzlaFw0zMjExMDExMjU1MzlaMHwxCzAJBgNVBAYTAlhYMRIwEAYDVQQH
|
||||
DAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNhdGVzIEx0ZDEUMBIG
|
||||
A1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZhbGlkLWNhQGV4YW1w
|
||||
bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzTyW1VRm+mQH
|
||||
YU5hZWgzgrPRkRzMLlLoCamlRs5DjGf3zIpo9a/17m60YfIXBJruImUBXxa5lp0Z
|
||||
qaayty+nZOpS0wBZSqTLuslZ0WuyyyW2DEBNO7jLW58cMn8MfAwMYjDcxtubNb7M
|
||||
AG9iZRj6wn6tKCsXtYUgAIpNhyPPtDuEZ5df1ecOnvlW2vO+MwytM8DLLtwolET/
|
||||
tPzOXPHDiyKjij02jyJ1DlZxptKudiKaBeY1WY/W/PpS6fGskTJQc/bZPgE3OP/9
|
||||
Y9Y1uzZTulkO3R6MlLNdLam32/ehpJvSWyfSbToyC2ejvaXoRChPFcAmTpqA0HPg
|
||||
h8sudiS14QIDAQABo3QwcjAdBgNVHQ4EFgQUR0gRYoOCPJYqFiPGwB141VTCXuIw
|
||||
HwYDVR0jBBgwFoAUR0gRYoOCPJYqFiPGwB141VTCXuIwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAfBgNVHREEGDAWgRR2YWxpZC1jYUBleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAJDQsNTWxVLNHBrVl6p6IetzeBt64GoWp6OP5C8/HY3dlznfbrn6ZvWBr
|
||||
Vsnc7VZ49r8r/QvRKRrljkIQuNwaW/LmRxJ1AVGGiorspmrdz0Lf2WOXnLH/+4lR
|
||||
q5dar5YmGqi9Mo2j5ALg/2MiO1PonuKs1eX9tLZCCeanXFexU0qaeFZelunJ6UUm
|
||||
BXpaGO1QfECcNnvarudosbe1ve6YGABn8MpAY+8zdYnYHPB8Pojhzvk7/8PMHoPu
|
||||
njDb3lZT+b8BDmNz+GISCUSHYkdK2rWh+8wqD3T5rOtzTqAPuSNeDNocUF6wzxem
|
||||
HWqvP7yM3VoXYvn7FA4NCa9mE3k8MzGCApcwggKTAgEBMIGUMHwxCzAJBgNVBAYT
|
||||
AlhYMRIwEAYDVQQHDAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNh
|
||||
dGVzIEx0ZDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZh
|
||||
bGlkLWNhQGV4YW1wbGUuY29tAhQoC/xUcLhcK13sGSiYxuUPf758tDAJBgUrDgMC
|
||||
GgUAoIHYMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X
|
||||
DTIyMTEwNDEzMzE1NVowIwYJKoZIhvcNAQkEMRYEFK+sB97I9ZGpDGUMWLsE3dCU
|
||||
/pbtMHkGCSqGSIb3DQEJDzFsMGowCwYJYIZIAWUDBAEqMAsGCWCGSAFlAwQBFjAL
|
||||
BglghkgBZQMEAQIwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3
|
||||
DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIB
|
||||
AFli04jnSd0d0lnE9GO23qzxI98QIbCz1NU1qk+zDyAhwOWQJdMUfuekk3g4Gn2q
|
||||
OFzdvlIMpgG2W7AVZlLUQMQjWIoDWkTeqxM8n6StoXcDvlArBHQDbourufFUu7OE
|
||||
3TVsI6l/jZG3Xub9Uar0S3lF6rQ/A3vl28poRL/EIQye6ypg6UbS/EvkvfbsKUJD
|
||||
6SpExlwh0R7lk1g/xn3tFVSEAH7VSJYr/8C/Bak06NPOtZZSSeU9ryRzeK/gN3SJ
|
||||
nrEp+NkTezzApjSnZasrPSbzmRL4+18x3kmAmnwR3aRi7F7KhCs78qPUEVP5XbhX
|
||||
2hO9RjMy6Uki+R/AG4aempk=
|
||||
|
||||
------1FD9CF28CC0AD72EF1FF6D0511838F0E--
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
From: valid-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: aDiFfErEnTtOkEn
|
||||
Auto-Submitted: auto-generated; type=acme
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha1"; boundary="----6E9953AAECB0BDB6F65BCD88900D3E15"
|
||||
|
||||
This is an S/MIME signed message
|
||||
|
||||
------6E9953AAECB0BDB6F65BCD88900D3E15
|
||||
Content-Type: message/RFC822; forwarded=no
|
||||
|
||||
From: valid-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
This is an automatically generated ACME challenge.
|
||||
|
||||
------6E9953AAECB0BDB6F65BCD88900D3E15
|
||||
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="smime.p7s"
|
||||
|
||||
MIIGzQYJKoZIhvcNAQcCoIIGvjCCBroCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3
|
||||
DQEHAaCCA/4wggP6MIIC4qADAgECAhQoC/xUcLhcK13sGSiYxuUPf758tDANBgkq
|
||||
hkiG9w0BAQsFADB8MQswCQYDVQQGEwJYWDESMBAGA1UEBwwJQWNtZSBDaXR5MR4w
|
||||
HAYDVQQKDBVBY21lIENlcnRpZmljYXRlcyBMdGQxFDASBgNVBAMMC2V4YW1wbGUu
|
||||
Y29tMSMwIQYJKoZIhvcNAQkBFhR2YWxpZC1jYUBleGFtcGxlLmNvbTAeFw0yMjEx
|
||||
MDQxMjU1MzlaFw0zMjExMDExMjU1MzlaMHwxCzAJBgNVBAYTAlhYMRIwEAYDVQQH
|
||||
DAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNhdGVzIEx0ZDEUMBIG
|
||||
A1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZhbGlkLWNhQGV4YW1w
|
||||
bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzTyW1VRm+mQH
|
||||
YU5hZWgzgrPRkRzMLlLoCamlRs5DjGf3zIpo9a/17m60YfIXBJruImUBXxa5lp0Z
|
||||
qaayty+nZOpS0wBZSqTLuslZ0WuyyyW2DEBNO7jLW58cMn8MfAwMYjDcxtubNb7M
|
||||
AG9iZRj6wn6tKCsXtYUgAIpNhyPPtDuEZ5df1ecOnvlW2vO+MwytM8DLLtwolET/
|
||||
tPzOXPHDiyKjij02jyJ1DlZxptKudiKaBeY1WY/W/PpS6fGskTJQc/bZPgE3OP/9
|
||||
Y9Y1uzZTulkO3R6MlLNdLam32/ehpJvSWyfSbToyC2ejvaXoRChPFcAmTpqA0HPg
|
||||
h8sudiS14QIDAQABo3QwcjAdBgNVHQ4EFgQUR0gRYoOCPJYqFiPGwB141VTCXuIw
|
||||
HwYDVR0jBBgwFoAUR0gRYoOCPJYqFiPGwB141VTCXuIwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAfBgNVHREEGDAWgRR2YWxpZC1jYUBleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAJDQsNTWxVLNHBrVl6p6IetzeBt64GoWp6OP5C8/HY3dlznfbrn6ZvWBr
|
||||
Vsnc7VZ49r8r/QvRKRrljkIQuNwaW/LmRxJ1AVGGiorspmrdz0Lf2WOXnLH/+4lR
|
||||
q5dar5YmGqi9Mo2j5ALg/2MiO1PonuKs1eX9tLZCCeanXFexU0qaeFZelunJ6UUm
|
||||
BXpaGO1QfECcNnvarudosbe1ve6YGABn8MpAY+8zdYnYHPB8Pojhzvk7/8PMHoPu
|
||||
njDb3lZT+b8BDmNz+GISCUSHYkdK2rWh+8wqD3T5rOtzTqAPuSNeDNocUF6wzxem
|
||||
HWqvP7yM3VoXYvn7FA4NCa9mE3k8MzGCApcwggKTAgEBMIGUMHwxCzAJBgNVBAYT
|
||||
AlhYMRIwEAYDVQQHDAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNh
|
||||
dGVzIEx0ZDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZh
|
||||
bGlkLWNhQGV4YW1wbGUuY29tAhQoC/xUcLhcK13sGSiYxuUPf758tDAJBgUrDgMC
|
||||
GgUAoIHYMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X
|
||||
DTIyMTEwNDEzMzE1NVowIwYJKoZIhvcNAQkEMRYEFK+sB97I9ZGpDGUMWLsE3dCU
|
||||
/pbtMHkGCSqGSIb3DQEJDzFsMGowCwYJYIZIAWUDBAEqMAsGCWCGSAFlAwQBFjAL
|
||||
BglghkgBZQMEAQIwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3
|
||||
DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIB
|
||||
AFli04jnSd0d0lnE9GO23qzxI98QIbCz1NU1qk+zDyAhwOWQJdMUfuekk3g4Gn2q
|
||||
OFzdvlIMpgG2W7AVZlLUQMQjWIoDWkTeqxM8n6StoXcDvlArBHQDbourufFUu7OE
|
||||
3TVsI6l/jZG3Xub9Uar0S3lF6rQ/A3vl28poRL/EIQye6ypg6UbS/EvkvfbsKUJD
|
||||
6SpExlwh0R7lk1g/xn3tFVSEAH7VSJYr/8C/Bak06NPOtZZSSeU9ryRzeK/gN3SJ
|
||||
nrEp+NkTezzApjSnZasrPSbzmRL4+18x3kmAmnwR3aRi7F7KhCs78qPUEVP5XbhX
|
||||
2hO9RjMy6Uki+R/AG4aempk=
|
||||
|
||||
------6E9953AAECB0BDB6F65BCD88900D3E15--
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
From: valid-ca@example.com
|
||||
To: tampered-recipient@example.com
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Auto-Submitted: auto-generated; type=acme
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha1"; boundary="----2D5F3855936C8172B69EB7BC1C12A23A"
|
||||
|
||||
This is an S/MIME signed message
|
||||
|
||||
------2D5F3855936C8172B69EB7BC1C12A23A
|
||||
Content-Type: message/RFC822; forwarded=no
|
||||
|
||||
From: valid-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
This is an automatically generated ACME challenge.
|
||||
|
||||
------2D5F3855936C8172B69EB7BC1C12A23A
|
||||
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="smime.p7s"
|
||||
|
||||
MIIGzQYJKoZIhvcNAQcCoIIGvjCCBroCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3
|
||||
DQEHAaCCA/4wggP6MIIC4qADAgECAhQoC/xUcLhcK13sGSiYxuUPf758tDANBgkq
|
||||
hkiG9w0BAQsFADB8MQswCQYDVQQGEwJYWDESMBAGA1UEBwwJQWNtZSBDaXR5MR4w
|
||||
HAYDVQQKDBVBY21lIENlcnRpZmljYXRlcyBMdGQxFDASBgNVBAMMC2V4YW1wbGUu
|
||||
Y29tMSMwIQYJKoZIhvcNAQkBFhR2YWxpZC1jYUBleGFtcGxlLmNvbTAeFw0yMjEx
|
||||
MDQxMjU1MzlaFw0zMjExMDExMjU1MzlaMHwxCzAJBgNVBAYTAlhYMRIwEAYDVQQH
|
||||
DAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNhdGVzIEx0ZDEUMBIG
|
||||
A1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZhbGlkLWNhQGV4YW1w
|
||||
bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzTyW1VRm+mQH
|
||||
YU5hZWgzgrPRkRzMLlLoCamlRs5DjGf3zIpo9a/17m60YfIXBJruImUBXxa5lp0Z
|
||||
qaayty+nZOpS0wBZSqTLuslZ0WuyyyW2DEBNO7jLW58cMn8MfAwMYjDcxtubNb7M
|
||||
AG9iZRj6wn6tKCsXtYUgAIpNhyPPtDuEZ5df1ecOnvlW2vO+MwytM8DLLtwolET/
|
||||
tPzOXPHDiyKjij02jyJ1DlZxptKudiKaBeY1WY/W/PpS6fGskTJQc/bZPgE3OP/9
|
||||
Y9Y1uzZTulkO3R6MlLNdLam32/ehpJvSWyfSbToyC2ejvaXoRChPFcAmTpqA0HPg
|
||||
h8sudiS14QIDAQABo3QwcjAdBgNVHQ4EFgQUR0gRYoOCPJYqFiPGwB141VTCXuIw
|
||||
HwYDVR0jBBgwFoAUR0gRYoOCPJYqFiPGwB141VTCXuIwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAfBgNVHREEGDAWgRR2YWxpZC1jYUBleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAJDQsNTWxVLNHBrVl6p6IetzeBt64GoWp6OP5C8/HY3dlznfbrn6ZvWBr
|
||||
Vsnc7VZ49r8r/QvRKRrljkIQuNwaW/LmRxJ1AVGGiorspmrdz0Lf2WOXnLH/+4lR
|
||||
q5dar5YmGqi9Mo2j5ALg/2MiO1PonuKs1eX9tLZCCeanXFexU0qaeFZelunJ6UUm
|
||||
BXpaGO1QfECcNnvarudosbe1ve6YGABn8MpAY+8zdYnYHPB8Pojhzvk7/8PMHoPu
|
||||
njDb3lZT+b8BDmNz+GISCUSHYkdK2rWh+8wqD3T5rOtzTqAPuSNeDNocUF6wzxem
|
||||
HWqvP7yM3VoXYvn7FA4NCa9mE3k8MzGCApcwggKTAgEBMIGUMHwxCzAJBgNVBAYT
|
||||
AlhYMRIwEAYDVQQHDAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNh
|
||||
dGVzIEx0ZDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZh
|
||||
bGlkLWNhQGV4YW1wbGUuY29tAhQoC/xUcLhcK13sGSiYxuUPf758tDAJBgUrDgMC
|
||||
GgUAoIHYMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X
|
||||
DTIyMTEwNDEzMzE1NVowIwYJKoZIhvcNAQkEMRYEFK+sB97I9ZGpDGUMWLsE3dCU
|
||||
/pbtMHkGCSqGSIb3DQEJDzFsMGowCwYJYIZIAWUDBAEqMAsGCWCGSAFlAwQBFjAL
|
||||
BglghkgBZQMEAQIwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3
|
||||
DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIB
|
||||
AFli04jnSd0d0lnE9GO23qzxI98QIbCz1NU1qk+zDyAhwOWQJdMUfuekk3g4Gn2q
|
||||
OFzdvlIMpgG2W7AVZlLUQMQjWIoDWkTeqxM8n6StoXcDvlArBHQDbourufFUu7OE
|
||||
3TVsI6l/jZG3Xub9Uar0S3lF6rQ/A3vl28poRL/EIQye6ypg6UbS/EvkvfbsKUJD
|
||||
6SpExlwh0R7lk1g/xn3tFVSEAH7VSJYr/8C/Bak06NPOtZZSSeU9ryRzeK/gN3SJ
|
||||
nrEp+NkTezzApjSnZasrPSbzmRL4+18x3kmAmnwR3aRi7F7KhCs78qPUEVP5XbhX
|
||||
2hO9RjMy6Uki+R/AG4aempk=
|
||||
|
||||
------2D5F3855936C8172B69EB7BC1C12A23A--
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
From: valid-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Auto-Submitted: auto-generated; type=acme
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha1"; boundary="----2D188458DC295B22904B7A1FB62F57BF"
|
||||
|
||||
This is an S/MIME signed message
|
||||
|
||||
------2D188458DC295B22904B7A1FB62F57BF
|
||||
Content-Type: message/RFC822; forwarded=no
|
||||
|
||||
From: valid-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
This is an automatically generated ACME challenge.
|
||||
|
||||
------2D188458DC295B22904B7A1FB62F57BF
|
||||
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="smime.p7s"
|
||||
|
||||
MIIG1QYJKoZIhvcNAQcCoIIGxjCCBsICAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3
|
||||
DQEHAaCCBAQwggQAMIIC6KADAgECAhRuqrQwjQAEKPLiumz639inbqPeJzANBgkq
|
||||
hkiG9w0BAQsFADB+MQswCQYDVQQGEwJYWDESMBAGA1UEBwwJQWNtZSBDaXR5MR4w
|
||||
HAYDVQQKDBVFbWNhIENlcnRpZmljYXRlcyBMdGQxFDASBgNVBAMMC2V4YW1wbGUu
|
||||
Y29tMSUwIwYJKoZIhvcNAQkBFhZpbnZhbGlkLWNhQGV4YW1wbGUuY29tMB4XDTIy
|
||||
MTEwNDEyNTUzOVoXDTMyMTEwMTEyNTUzOVowfjELMAkGA1UEBhMCWFgxEjAQBgNV
|
||||
BAcMCUFjbWUgQ2l0eTEeMBwGA1UECgwVRW1jYSBDZXJ0aWZpY2F0ZXMgTHRkMRQw
|
||||
EgYDVQQDDAtleGFtcGxlLmNvbTElMCMGCSqGSIb3DQEJARYWaW52YWxpZC1jYUBl
|
||||
eGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMxVUSNR
|
||||
pIreCKvtK148IWN7MWfK8fymmPOF8oQcFieCC0mfw8efc/4MEVA5qN3avHOXd1RG
|
||||
VgaR+tM30zRiTLllc6YnPePUPZNSQmJcnXgMlRhmOeCfo2hNglWFBnP/CV29xarP
|
||||
Cf94DqXGrLZ8L8uGtk/JsNOreced34V4RZ9WvN53HlyiNtEJJLggM17wzJZcV+rQ
|
||||
7LtsBHZfDOdTScCpEDqLZDmLMVLEBUtrwo5+5mYw4M0PDEP2D4qPux7NAHuaG66F
|
||||
Zt7mq6DcceG/AneuUN7xOyMQ9x/D3NfiSgXbZeJM+BbE0cT7EY9WdZBtsS6HjJA0
|
||||
yt98FgAIDoSzRQcCAwEAAaN2MHQwHQYDVR0OBBYEFB0Xb1ErzzEjzPrJC8PvkAJ3
|
||||
qnoGMB8GA1UdIwQYMBaAFB0Xb1ErzzEjzPrJC8PvkAJ3qnoGMA8GA1UdEwEB/wQF
|
||||
MAMBAf8wIQYDVR0RBBowGIEWaW52YWxpZC1jYUBleGFtcGxlLmNvbTANBgkqhkiG
|
||||
9w0BAQsFAAOCAQEAnwFh8H7lwMWrHSceM6MVt+5M0yVX/r6K5YWGI/AaFG2Q5jkz
|
||||
6yIeESgiXukza4oKY1I1clZwWus9fnrwn+AWbtvKbGLklFWCUB60fx82dZwoO14Q
|
||||
Tm3GX6wwC0Y5eFYiXwEJ4gnazBWEWscp4E94AKqr1EYuOI9sR22l/rNtANrEiVsT
|
||||
P4+kUgLEr9Y5infYglXQMjDVfNXRSETBnx4a5Fljd7pSD4e7H19eMiByd78q98ze
|
||||
t0g2anl2cJbdM6cgu5iyAgS3BgMrFMnd8m7KkZwum+tslNWA1tbDGK0AWH7ztjh3
|
||||
orifkxq2Hw6tdypZoWoLrwSEDEvNIy8+sQjUOTGCApkwggKVAgEBMIGWMH4xCzAJ
|
||||
BgNVBAYTAlhYMRIwEAYDVQQHDAlBY21lIENpdHkxHjAcBgNVBAoMFUVtY2EgQ2Vy
|
||||
dGlmaWNhdGVzIEx0ZDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xJTAjBgkqhkiG9w0B
|
||||
CQEWFmludmFsaWQtY2FAZXhhbXBsZS5jb20CFG6qtDCNAAQo8uK6bPrf2Kduo94n
|
||||
MAkGBSsOAwIaBQCggdgwGAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAcBgkqhkiG
|
||||
9w0BCQUxDxcNMjIxMTA0MTMzMTU1WjAjBgkqhkiG9w0BCQQxFgQUr6wH3sj1kakM
|
||||
ZQxYuwTd0JT+lu0weQYJKoZIhvcNAQkPMWwwajALBglghkgBZQMEASowCwYJYIZI
|
||||
AWUDBAEWMAsGCWCGSAFlAwQBAjAKBggqhkiG9w0DBzAOBggqhkiG9w0DAgICAIAw
|
||||
DQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwDQYJKoZIhvcN
|
||||
AQEBBQAEggEAdZ4XoWViOrqOd4kWZVD+12GXJ7NcCWHOiTdXZ0S/3TKwwTPwQ0f0
|
||||
XZmk8iJwcfXqAv48ITK+yh4jk8urtrjS3xohHGxVonifbgxoLm/yHqA13D4F0M9q
|
||||
r0jfmXAWfH1HDk6AtZA5c1IJVJNMcVcLHkib232FgpicgPEZNWvRr8zHCNN3dymF
|
||||
Qme9h2BqHxy2+nX96BBEiRMImG9Z9G4+sOqpwiDTNgzr7nFtldKtjiV/GarBeteZ
|
||||
nx4QcHXY307ydLDrh2JzLK/+LZEhTMBQ2rWGfAo/owDGi/Pal//SgqQWFy3luJp2
|
||||
8WG34Z4CnG514YmRzN2Z1V3fvreRInllkQ==
|
||||
|
||||
------2D188458DC295B22904B7A1FB62F57BF--
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
From: valid-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Auto-Submitted: auto-generated; type=acme
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/signed; protocol="application/x-pkcs7-signature"; micalg="sha1"; boundary="----163CF1BA3ECF9F288779BFBE9EF3E10C"
|
||||
|
||||
This is an S/MIME signed message
|
||||
|
||||
------163CF1BA3ECF9F288779BFBE9EF3E10C
|
||||
Content-Type: message/RFC822; forwarded=no
|
||||
|
||||
From: valid-ca@example.com
|
||||
To: recipient@example.org
|
||||
Subject: ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=
|
||||
Message-ID: <A2299BB.FF7788@example.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
This is an automatically generated ACME challenge.
|
||||
|
||||
------163CF1BA3ECF9F288779BFBE9EF3E10C
|
||||
Content-Type: application/x-pkcs7-signature; name="smime.p7s"
|
||||
Content-Transfer-Encoding: base64
|
||||
Content-Disposition: attachment; filename="smime.p7s"
|
||||
|
||||
MIIGzQYJKoZIhvcNAQcCoIIGvjCCBroCAQExCzAJBgUrDgMCGgUAMAsGCSqGSIb3
|
||||
DQEHAaCCA/4wggP6MIIC4qADAgECAhQoC/xUcLhcK13sGSiYxuUPf758tDANBgkq
|
||||
hkiG9w0BAQsFADB8MQswCQYDVQQGEwJYWDESMBAGA1UEBwwJQWNtZSBDaXR5MR4w
|
||||
HAYDVQQKDBVBY21lIENlcnRpZmljYXRlcyBMdGQxFDASBgNVBAMMC2V4YW1wbGUu
|
||||
Y29tMSMwIQYJKoZIhvcNAQkBFhR2YWxpZC1jYUBleGFtcGxlLmNvbTAeFw0yMjEx
|
||||
MDQxMjU1MzlaFw0zMjExMDExMjU1MzlaMHwxCzAJBgNVBAYTAlhYMRIwEAYDVQQH
|
||||
DAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNhdGVzIEx0ZDEUMBIG
|
||||
A1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZhbGlkLWNhQGV4YW1w
|
||||
bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzTyW1VRm+mQH
|
||||
YU5hZWgzgrPRkRzMLlLoCamlRs5DjGf3zIpo9a/17m60YfIXBJruImUBXxa5lp0Z
|
||||
qaayty+nZOpS0wBZSqTLuslZ0WuyyyW2DEBNO7jLW58cMn8MfAwMYjDcxtubNb7M
|
||||
AG9iZRj6wn6tKCsXtYUgAIpNhyPPtDuEZ5df1ecOnvlW2vO+MwytM8DLLtwolET/
|
||||
tPzOXPHDiyKjij02jyJ1DlZxptKudiKaBeY1WY/W/PpS6fGskTJQc/bZPgE3OP/9
|
||||
Y9Y1uzZTulkO3R6MlLNdLam32/ehpJvSWyfSbToyC2ejvaXoRChPFcAmTpqA0HPg
|
||||
h8sudiS14QIDAQABo3QwcjAdBgNVHQ4EFgQUR0gRYoOCPJYqFiPGwB141VTCXuIw
|
||||
HwYDVR0jBBgwFoAUR0gRYoOCPJYqFiPGwB141VTCXuIwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAfBgNVHREEGDAWgRR2YWxpZC1jYUBleGFtcGxlLmNvbTANBgkqhkiG9w0BAQsF
|
||||
AAOCAQEAJDQsNTWxVLNHBrVl6p6IetzeBt64GoWp6OP5C8/HY3dlznfbrn6ZvWBr
|
||||
Vsnc7VZ49r8r/QvRKRrljkIQuNwaW/LmRxJ1AVGGiorspmrdz0Lf2WOXnLH/+4lR
|
||||
q5dar5YmGqi9Mo2j5ALg/2MiO1PonuKs1eX9tLZCCeanXFexU0qaeFZelunJ6UUm
|
||||
BXpaGO1QfECcNnvarudosbe1ve6YGABn8MpAY+8zdYnYHPB8Pojhzvk7/8PMHoPu
|
||||
njDb3lZT+b8BDmNz+GISCUSHYkdK2rWh+8wqD3T5rOtzTqAPuSNeDNocUF6wzxem
|
||||
HWqvP7yM3VoXYvn7FA4NCa9mE3k8MzGCApcwggKTAgEBMIGUMHwxCzAJBgNVBAYT
|
||||
AlhYMRIwEAYDVQQHDAlBY21lIENpdHkxHjAcBgNVBAoMFUFjbWUgQ2VydGlmaWNh
|
||||
dGVzIEx0ZDEUMBIGA1UEAwwLZXhhbXBsZS5jb20xIzAhBgkqhkiG9w0BCQEWFHZh
|
||||
bGlkLWNhQGV4YW1wbGUuY29tAhQoC/xUcLhcK13sGSiYxuUPf758tDAJBgUrDgMC
|
||||
GgUAoIHYMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8X
|
||||
DTIyMTEwNDEzMzE1NVowIwYJKoZIhvcNAQkEMRYEFK+sB97I9ZGpDGUMWLsE3dCU
|
||||
/pbtMHkGCSqGSIb3DQEJDzFsMGowCwYJYIZIAWUDBAEqMAsGCWCGSAFlAwQBFjAL
|
||||
BglghkgBZQMEAQIwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMA0GCCqGSIb3
|
||||
DQMCAgFAMAcGBSsOAwIHMA0GCCqGSIb3DQMCAgEoMA0GCSqGSIb3DQEBAQUABIIB
|
||||
AFli04jnSd0d0lnE9GO23qzxI98QIbCz1NU1qk+zDyAhwOWQJdMUfuekk3g4Gn2q
|
||||
OFzdvlIMpgG2W7AVZlLUQMQjWIoDWkTeqxM8n6StoXcDvlArBHQDbourufFUu7OE
|
||||
3TVsI6l/jZG3Xub9Uar0S3lF6rQ/A3vl28poRL/EIQye6ypg6UbS/EvkvfbsKUJD
|
||||
6SpExlwh0R7lk1g/xn3tFVSEAH7VSJYr/8C/Bak06NPOtZZSSeU9ryRzeK/gN3SJ
|
||||
nrEp+NkTezzApjSnZasrPSbzmRL4+18x3kmAmnwR3aRi7F7KhCs78qPUEVP5XbhX
|
||||
2hO9RjMy6Uki+R/AG4aempk=
|
||||
|
||||
------163CF1BA3ECF9F288779BFBE9EF3E10C--
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDMVVEjUaSK3gir
|
||||
7StePCFjezFnyvH8ppjzhfKEHBYnggtJn8PHn3P+DBFQOajd2rxzl3dURlYGkfrT
|
||||
N9M0Yky5ZXOmJz3j1D2TUkJiXJ14DJUYZjngn6NoTYJVhQZz/wldvcWqzwn/eA6l
|
||||
xqy2fC/LhrZPybDTq3nHnd+FeEWfVrzedx5cojbRCSS4IDNe8MyWXFfq0Oy7bAR2
|
||||
XwznU0nAqRA6i2Q5izFSxAVLa8KOfuZmMODNDwxD9g+Kj7sezQB7mhuuhWbe5qug
|
||||
3HHhvwJ3rlDe8TsjEPcfw9zX4koF22XiTPgWxNHE+xGPVnWQbbEuh4yQNMrffBYA
|
||||
CA6Es0UHAgMBAAECggEAByliW6OL6dYYZbY9U+M1pF/3/lRNoPZR3A8wzdKSMDZN
|
||||
oPn5ibCcByZzIOW0dnopKr//TbPdZgON0ANf4rEjUUguAn/Tmn2g3t3+N6ZZWpDO
|
||||
VPmYQ7g0qP42eDreXAhvUprJJ9Bz4EFb+hF5kjfOEQsarrc5/GFBNm7hG7N4dTos
|
||||
ANLHDVt9p++40mBC9UnFTI9fghYqqsBipI2hMcVtLlfsTyhfdYk2atC0YwWH2g7H
|
||||
nyFsfrgwNlza5iAKuQn1vGhM6nigGBiDfHifNoTHZPhIcgHRwPvZWCpxcAt8wPw1
|
||||
4blqZPRqmbOYQHisXVSbKJbgN8zZiZB2j/SSDv9IyQKBgQDqpiSaiBZ+bUfy5M07
|
||||
mSClnHR8/zulR7NuSWZ5C92w2EFYI/OkSwKeshKdmafCz9VeVkeCUjjRkAGOF2pr
|
||||
I1icdY0XDt/Pd+jQzDqTtiUwwMOLRyvV437nCsMer++LbKRblEL+uSLCPhV2dnyx
|
||||
GUXj9JJhnGeZ+xKH20cE1dr2NQKBgQDe7QG6UGrXUzfN2BttvJfOAKETtVfl1Mm0
|
||||
uEC2skPlY1KVFYOCMuOFXLHwlc0KYNzVh5qBH+3dPyX1zjTurXmnaOcW0LxgJ4JN
|
||||
vKiXDLrt8HYJqANjYCh7vaZmuZ8RduR4iS+E+JG6JLAdfGIzPvzzUgbo5hXuFnQE
|
||||
dN8gsJcFywKBgAF24fmY6dMGKZHJfcJmdT6zWELDcQLaDLOef6Y3vb1xzA6ZwtZ+
|
||||
pViKMfWL1PExTNqW3UFh8/rS1D+nw8FBajcnwKapMBpiXDCZZbAwTdEdEttWqV5f
|
||||
WhZlCcyyOmN7XRc5OKXQT/g4XPftS1/rkXUXvKYhTMA4QehZJPtRvlkVAoGBAMS+
|
||||
h/fXYXQIjget4wdGmvPEumSad6jv09UbiIG1cxbQQeIxyo7uOr9IwAKFMyElu8D4
|
||||
nPO5KkVJpkb6Ztz/XY7SlqEcOCTkuavCBUjKg2/b+VEsZ1EdXJ1ZE7M1v526QInh
|
||||
CX9hobuXBZgAXuq7fKOCkXabGl+2kU4dl49SSvdhAoGAH06W9bZUiqkLIzv+LizW
|
||||
rVP9fN4A8EGNtdWVrVD0Ql0hh/PBqGiiVwg47LAVuvpIc9kDDQM/5A6tF7aOGRDR
|
||||
k5ZDIrnWmrGQcEMTcisc5OwPnNjLVzV9r0swmeWcqZDrfgxeKpG7vdRaQdR++0FU
|
||||
1zaGc8HFGtTeJw6f6ZYttg8=
|
||||
-----END PRIVATE KEY-----
|
|
@ -0,0 +1,24 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIEADCCAuigAwIBAgIUbqq0MI0ABCjy4rps+t/Yp26j3icwDQYJKoZIhvcNAQEL
|
||||
BQAwfjELMAkGA1UEBhMCWFgxEjAQBgNVBAcMCUFjbWUgQ2l0eTEeMBwGA1UECgwV
|
||||
RW1jYSBDZXJ0aWZpY2F0ZXMgTHRkMRQwEgYDVQQDDAtleGFtcGxlLmNvbTElMCMG
|
||||
CSqGSIb3DQEJARYWaW52YWxpZC1jYUBleGFtcGxlLmNvbTAeFw0yMjExMDQxMjU1
|
||||
MzlaFw0zMjExMDExMjU1MzlaMH4xCzAJBgNVBAYTAlhYMRIwEAYDVQQHDAlBY21l
|
||||
IENpdHkxHjAcBgNVBAoMFUVtY2EgQ2VydGlmaWNhdGVzIEx0ZDEUMBIGA1UEAwwL
|
||||
ZXhhbXBsZS5jb20xJTAjBgkqhkiG9w0BCQEWFmludmFsaWQtY2FAZXhhbXBsZS5j
|
||||
b20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDMVVEjUaSK3gir7Ste
|
||||
PCFjezFnyvH8ppjzhfKEHBYnggtJn8PHn3P+DBFQOajd2rxzl3dURlYGkfrTN9M0
|
||||
Yky5ZXOmJz3j1D2TUkJiXJ14DJUYZjngn6NoTYJVhQZz/wldvcWqzwn/eA6lxqy2
|
||||
fC/LhrZPybDTq3nHnd+FeEWfVrzedx5cojbRCSS4IDNe8MyWXFfq0Oy7bAR2Xwzn
|
||||
U0nAqRA6i2Q5izFSxAVLa8KOfuZmMODNDwxD9g+Kj7sezQB7mhuuhWbe5qug3HHh
|
||||
vwJ3rlDe8TsjEPcfw9zX4koF22XiTPgWxNHE+xGPVnWQbbEuh4yQNMrffBYACA6E
|
||||
s0UHAgMBAAGjdjB0MB0GA1UdDgQWBBQdF29RK88xI8z6yQvD75ACd6p6BjAfBgNV
|
||||
HSMEGDAWgBQdF29RK88xI8z6yQvD75ACd6p6BjAPBgNVHRMBAf8EBTADAQH/MCEG
|
||||
A1UdEQQaMBiBFmludmFsaWQtY2FAZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQAD
|
||||
ggEBAJ8BYfB+5cDFqx0nHjOjFbfuTNMlV/6+iuWFhiPwGhRtkOY5M+siHhEoIl7p
|
||||
M2uKCmNSNXJWcFrrPX568J/gFm7bymxi5JRVglAetH8fNnWcKDteEE5txl+sMAtG
|
||||
OXhWIl8BCeIJ2swVhFrHKeBPeACqq9RGLjiPbEdtpf6zbQDaxIlbEz+PpFICxK/W
|
||||
OYp32IJV0DIw1XzV0UhEwZ8eGuRZY3e6Ug+Hux9fXjIgcne/KvfM3rdINmp5dnCW
|
||||
3TOnILuYsgIEtwYDKxTJ3fJuypGcLpvrbJTVgNbWwxitAFh+87Y4d6K4n5Math8O
|
||||
rXcqWaFqC68EhAxLzSMvPrEI1Dk=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDYEMlw6YXHpO5b
|
||||
nyuk7gVdu8XtmhKkg6LhhZ9KYPstIdSr7EbH++h2KMVPVjprvijh35d5hMf9fiMU
|
||||
71A93NkO4by3fOIUAJy2m1oXLBSOBhglAbI+Z+DeGfULPvari0Cp6A4TAvvw0DZh
|
||||
wR3qzHS50AXzQLVAeL+QoEwOCP0A7I3Ihn+sE3wJlKR+Sk9hYj30WX8M65ievuQw
|
||||
3VNRZLX3TqY+oGyWHVhXKnp90ZovoN2Uhj5kTlz0GFJP+37t4urt+cHkoH60O8cP
|
||||
Wqcvznwr7keN9z0xRhPJ98OIlob3MeQQqLfN3QQZxp/Wv6WyRGoQg6pE6MtIOKZP
|
||||
lDgK4cJhAgMBAAECggEAEZOKA4KnpJY84pyn5P6M1rNt9jZkolfoAd8IFnmdrS31
|
||||
mje6CU4reqM1686IqZeaRUeWT6cWyr7+VRdjqGilCqIf4zBIRtbG6M7p7P0jveru
|
||||
f2IsMQnrv72OUsggMlO9YqTzMiY5vvz9E4YtbBqOO0haF4/xvqkj8jyr+y9Nf4vY
|
||||
Yag2EUddUX2Giqln97aE8G2O8+LJzXTIk1K15DfyBcq1kkye8OSkjsnLybP4wo+v
|
||||
uRSDbReF//j+MDepP6IZNPBVyEDyjaXFrNmVb+USyHtzKXwl/GwoYjN7gtOtqc1V
|
||||
8vVj1H6+RJK1E67ORLctzzMUZfG6vDB2UZ+vv0lqnQKBgQD7sYWfq1rMzUNhVX4D
|
||||
ef0AOoQlBpnOiwoc+7JEXoZoKBw5xrTAxsKRtJFSgIYDYbfi2y3XLu5IO69nkao6
|
||||
EqArzaGn+Uc5JcCw4GVVoe6q6W4SwTGC690d/D7R2h24CYjqrIXkFwtvvM6f+5gl
|
||||
Vu8da1eXbH73JAEigkKtrvQqVQKBgQDbwzTL6E6hY6DXAxsWzSp1d1n/SK6NdByX
|
||||
2yfCQRAQVX6KPVo8Gw1ZGH3IJ/KNVL/TXzDV3NfY6cYBbydcu0/EcVBS11+3KhT7
|
||||
uB+Y6T3RThwzRDRBlaeJtUmN63JWmCOBiMIRPmJU2uxS3JzNMqC5QekkjRb/7S2J
|
||||
300hAdlb3QKBgGkt3zRBTFmHcZ/sNRPI15RP38cFQiMQ8XH5MJ7njW1bTahLRF/G
|
||||
76op9gyvDtG89TZE95wTzZm772ntcmCARhToAqUKQ9w6zZJcw5wMZotfrxMBTupy
|
||||
HF4aejoB1yeAPIos/Gq7wpi4IvSyE/uOn7AAmoL54PjwP9Um8Cxaj0hdAoGBALQf
|
||||
p6KJ4gj989LHxOhHeUmWbbmEBS4DwXvmMQxS76uzp2f/KXqiYappHI91zqRwllnV
|
||||
Z92iiXhNA/Ig/Q5QqOzGQ6Piy50BbPl0zNE0O2rWrt6GRJ6M3ylL4eHk3W6EfHWr
|
||||
dgVUMJyEY7b3A75chMfTchh3XCaga/bZhApNza4xAoGAZF1mFIowaUog23TWiann
|
||||
ZuCrZObtd2bk4LdtUYSAs2oUFSEWOR4d/av+eb68yf+n69gk1MrP4BA3hyQOX1M9
|
||||
Cz/9x/1Tewytywi36noxlgvTfAe3U93LxGjob4z2bsGQ0Xt8q4ngIrEvDeBQa0cq
|
||||
bUOxUekM/49+AAToLiTrZhM=
|
||||
-----END PRIVATE KEY-----
|
|
@ -0,0 +1,23 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIID2TCCAsGgAwIBAgIUT0oQs1tpYdA/PUXwyeZqLP4DACYwDQYJKoZIhvcNAQEL
|
||||
BQAwfDELMAkGA1UEBhMCWFgxEjAQBgNVBAcMCUFjbWUgQ2l0eTEeMBwGA1UECgwV
|
||||
QWNtZSBDZXJ0aWZpY2F0ZXMgTHRkMRQwEgYDVQQDDAtleGFtcGxlLmNvbTEjMCEG
|
||||
CSqGSIb3DQEJARYUdmFsaWQtY2FAZXhhbXBsZS5jb20wHhcNMjIxMTA0MTI1NTM5
|
||||
WhcNMzIxMTAxMTI1NTM5WjB8MQswCQYDVQQGEwJYWDESMBAGA1UEBwwJQWNtZSBD
|
||||
aXR5MR4wHAYDVQQKDBVBY21lIENlcnRpZmljYXRlcyBMdGQxFDASBgNVBAMMC2V4
|
||||
YW1wbGUuY29tMSMwIQYJKoZIhvcNAQkBFhR2YWxpZC1jYUBleGFtcGxlLmNvbTCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANgQyXDphcek7lufK6TuBV27
|
||||
xe2aEqSDouGFn0pg+y0h1KvsRsf76HYoxU9WOmu+KOHfl3mEx/1+IxTvUD3c2Q7h
|
||||
vLd84hQAnLabWhcsFI4GGCUBsj5n4N4Z9Qs+9quLQKnoDhMC+/DQNmHBHerMdLnQ
|
||||
BfNAtUB4v5CgTA4I/QDsjciGf6wTfAmUpH5KT2FiPfRZfwzrmJ6+5DDdU1FktfdO
|
||||
pj6gbJYdWFcqen3Rmi+g3ZSGPmROXPQYUk/7fu3i6u35weSgfrQ7xw9apy/OfCvu
|
||||
R433PTFGE8n3w4iWhvcx5BCot83dBBnGn9a/pbJEahCDqkToy0g4pk+UOArhwmEC
|
||||
AwEAAaNTMFEwHQYDVR0OBBYEFEaAxnUaGT+hDny105TcVjw00ZqfMB8GA1UdIwQY
|
||||
MBaAFEaAxnUaGT+hDny105TcVjw00ZqfMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
|
||||
hvcNAQELBQADggEBAL1SPWI/JS9HL3TWN0Q/xkP7UAhgQM6BUzgyVMJ+MxPy34l3
|
||||
7vEsSYc3KY8ynNo/psbsBodDqq2iDthZKTtt/l9YAnQrfgpRP+pzLPFDKOB9cDGG
|
||||
BoY5KC77B/TXuTfvdT7y0Bvey6C7KMvmPecLNt1sqlCdoOwOyLJN7+zCWVR9nfd4
|
||||
Y27VkOvt/zz+cycLmxMIgwGL8nDg37wIoPftEASMvrhO18ZxISsRyabzd6fDZi8m
|
||||
u1x97/djezOgoqMgasPBy+yOZbeRwamv1PVElTDJovb/rRS2WMne6+2nMOoQezA3
|
||||
C5rRLtPAoKPPStt6E5tSQSWa42VBW2HGD/n4ros=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,28 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDNPJbVVGb6ZAdh
|
||||
TmFlaDOCs9GRHMwuUugJqaVGzkOMZ/fMimj1r/XubrRh8hcEmu4iZQFfFrmWnRmp
|
||||
prK3L6dk6lLTAFlKpMu6yVnRa7LLJbYMQE07uMtbnxwyfwx8DAxiMNzG25s1vswA
|
||||
b2JlGPrCfq0oKxe1hSAAik2HI8+0O4Rnl1/V5w6e+Vba874zDK0zwMsu3CiURP+0
|
||||
/M5c8cOLIqOKPTaPInUOVnGm0q52IpoF5jVZj9b8+lLp8ayRMlBz9tk+ATc4//1j
|
||||
1jW7NlO6WQ7dHoyUs10tqbfb96Gkm9JbJ9JtOjILZ6O9pehEKE8VwCZOmoDQc+CH
|
||||
yy52JLXhAgMBAAECggEAT/IIjSvV+zYou8o03TQEUKbr/Ls7e9X2pgDrrROes1wy
|
||||
Zf4KWZ3Dzi9YW4jaV4RkO4idyqUHAPjMLM4O8pWA/qnaPm/12EIuS+Gv94gcus5D
|
||||
Ri1sCFX4/QUTDkZ4Hf/xePQwo9Oad4qNW6QHr3rV/xoqKCn1D9O9/gfhoEEeYMVV
|
||||
nPdHlRR1QPcbptsBGkMYrZ8LwjQb8rMvNTK8HRhc4cKrkobEFvwXcWNO9aIlLveP
|
||||
Q58TlQUijeu4eZPM9c3vjl8rM7Oic/ftuU6jmt9IayAVoYblw7yzeEk3lnBlPzME
|
||||
e01hr+QD6ZJiquO1stdm6a7TJv15lAghhTBysy7oawKBgQDcY+PBZByHOZ5GzDBb
|
||||
fwcScm/RM5zMfDJKrYLNehawJ5egyUOeRm+Ym8d7PpCOWrHLURLpxak2Nrsmivf8
|
||||
g1OYAFnWWQm6j3GmlnEspp65n/UVPHETq7tvqulOHmvcOVROsSgHWu8JMgk8mlK1
|
||||
kEKlw3y5yzIB7SdyUhCjY5UMGwKBgQDuZeWfg44qvi9o3bb0zbjAHgh0hCQjHy/G
|
||||
NVcaVXx06j0a1tAFyESmJqtCEbScrInZnrmpXmTvX5UQczWHi4RYMI8NNFmf3+i0
|
||||
XHxWICFrQhdkxppvrEJeXbdfws+UJT8A9K8kokYRO3WyDzrngddfvCbYgHQjMly+
|
||||
3Ke8oS2tswKBgQC0sf2ZoSA2ysn3mBCJ5AODX2pIZv3HNojxa4OUPuZ9NWj/fiS/
|
||||
j1aOFCMg7DIPVVLytR1BqDtNZOBbAJPEaFRQivEdalEssdFn2W8fQdlfrkN+TtkT
|
||||
XLlIHCQ/VXfvzt1Ny7hbF3Zm3qxuEMWBca8DQ91uY6gzpiKye5CCtfINQwKBgQDh
|
||||
EPIoFlsxnzvDFQ6VL2MsfS4eUmKLhfXkepcxFWPaPQpTPFpIGzo0Ym1sgqqw/3Nl
|
||||
MKS3cZZ5JxPj4+C1htH7MFzdan7yoMFhBa+c39itGkhbq+RBaa9+x5tHnPO8OS2y
|
||||
CU8QluLvgeMrp5VE2yAqEcfavernD7TfvBHf04r8YQKBgCHRqnBwHOGHiWyy/Wdu
|
||||
ySxqN1hfJWBdKRbtxTj5uCKp/orNtiRVB4GC1ZqhCJ38rZwMSSbp00o9nyDXlRfP
|
||||
jTo2zHrxtwem5hB31cZalPt4twJ5SofmNLDngz7UxwpTs8jWaAf8yAtRgdxWbYRg
|
||||
bRbZ+LceWQUl8T/RC7UQpy0Y
|
||||
-----END PRIVATE KEY-----
|
|
@ -0,0 +1,24 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIID+jCCAuKgAwIBAgIUKAv8VHC4XCtd7BkomMblD3++fLQwDQYJKoZIhvcNAQEL
|
||||
BQAwfDELMAkGA1UEBhMCWFgxEjAQBgNVBAcMCUFjbWUgQ2l0eTEeMBwGA1UECgwV
|
||||
QWNtZSBDZXJ0aWZpY2F0ZXMgTHRkMRQwEgYDVQQDDAtleGFtcGxlLmNvbTEjMCEG
|
||||
CSqGSIb3DQEJARYUdmFsaWQtY2FAZXhhbXBsZS5jb20wHhcNMjIxMTA0MTI1NTM5
|
||||
WhcNMzIxMTAxMTI1NTM5WjB8MQswCQYDVQQGEwJYWDESMBAGA1UEBwwJQWNtZSBD
|
||||
aXR5MR4wHAYDVQQKDBVBY21lIENlcnRpZmljYXRlcyBMdGQxFDASBgNVBAMMC2V4
|
||||
YW1wbGUuY29tMSMwIQYJKoZIhvcNAQkBFhR2YWxpZC1jYUBleGFtcGxlLmNvbTCC
|
||||
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM08ltVUZvpkB2FOYWVoM4Kz
|
||||
0ZEczC5S6AmppUbOQ4xn98yKaPWv9e5utGHyFwSa7iJlAV8WuZadGammsrcvp2Tq
|
||||
UtMAWUqky7rJWdFrsssltgxATTu4y1ufHDJ/DHwMDGIw3MbbmzW+zABvYmUY+sJ+
|
||||
rSgrF7WFIACKTYcjz7Q7hGeXX9XnDp75VtrzvjMMrTPAyy7cKJRE/7T8zlzxw4si
|
||||
o4o9No8idQ5WcabSrnYimgXmNVmP1vz6UunxrJEyUHP22T4BNzj//WPWNbs2U7pZ
|
||||
Dt0ejJSzXS2pt9v3oaSb0lsn0m06Mgtno72l6EQoTxXAJk6agNBz4IfLLnYkteEC
|
||||
AwEAAaN0MHIwHQYDVR0OBBYEFEdIEWKDgjyWKhYjxsAdeNVUwl7iMB8GA1UdIwQY
|
||||
MBaAFEdIEWKDgjyWKhYjxsAdeNVUwl7iMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0R
|
||||
BBgwFoEUdmFsaWQtY2FAZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBACQ0
|
||||
LDU1sVSzRwa1ZeqeiHrc3gbeuBqFqejj+QvPx2N3Zc53265+mb1ga1bJ3O1WePa/
|
||||
K/0L0Ska5Y5CELjcGlvy5kcSdQFRhoqK7KZq3c9C39ljl5yx//uJUauXWq+WJhqo
|
||||
vTKNo+QC4P9jIjtT6J7irNXl/bS2Qgnmp1xXsVNKmnhWXpbpyelFJgV6WhjtUHxA
|
||||
nDZ72q7naLG3tb3umBgAZ/DKQGPvM3WJ2BzwfD6I4c75O//DzB6D7p4w295WU/m/
|
||||
AQ5jc/hiEglEh2JHStq1ofvMKg90+azrc06gD7kjXgzaHFBesM8Xph1qrz+8jN1a
|
||||
F2L5+xQODQmvZhN5PDM=
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,118 @@
|
|||
#!/bin/env python3
|
||||
#
|
||||
# acme4j - Java ACME client
|
||||
#
|
||||
# Copyright (C) 2022 Richard "Shred" Körber
|
||||
# http://acme4j.shredzone.org
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
|
||||
#
|
||||
# This tool creates ACME test e-mails and signs them. It can be
|
||||
# used to generate S/MIME mails for unit tests.
|
||||
#
|
||||
# Requires: M2Crypto
|
||||
#
|
||||
# WARNING: DO NOT USE THIS CODE TO GENERATE REAL S/MIME MAILS!
|
||||
# This generator is only meant to create test mails for unit test
|
||||
# purposes, and may lack security relevant features that are
|
||||
# needed for real S/MIME mails.
|
||||
#
|
||||
|
||||
from M2Crypto import BIO, Rand, SMIME
|
||||
|
||||
def makebuf(text):
|
||||
return BIO.MemoryBuffer(bytes(text, 'UTF-8'))
|
||||
|
||||
def signmail(text, sender, recipient, subject, privkey, pubkey,
|
||||
envelopeFrom=None, envelopeTo=None, envelopeSubject=None):
|
||||
body = 'Content-Type: message/RFC822; forwarded=no\r\n\r\n'
|
||||
body += 'From: {}\r\n'.format(sender)
|
||||
body += 'To: {}\r\n'.format(recipient)
|
||||
body += 'Subject: {}\r\n'.format(subject)
|
||||
body += 'Message-ID: <A2299BB.FF7788@example.org>\r\n'
|
||||
body += 'MIME-Version: 1.0\r\n'
|
||||
body += 'Content-Type: text/plain; charset=utf-8\r\n'
|
||||
body += '\r\n'
|
||||
body += text
|
||||
body += '\r\n'
|
||||
|
||||
s = SMIME.SMIME()
|
||||
s.load_key(privkey, pubkey)
|
||||
p7 = s.sign(makebuf(body), SMIME.PKCS7_DETACHED)
|
||||
|
||||
out = BIO.MemoryBuffer()
|
||||
out.write('From: {}\r\n'.format(envelopeFrom if envelopeFrom is not None else sender))
|
||||
out.write('To: {}\r\n'.format(envelopeTo if envelopeTo is not None else recipient))
|
||||
out.write('Subject: {}\r\n'.format(envelopeSubject if envelopeSubject is not None else subject))
|
||||
out.write('Auto-Submitted: auto-generated; type=acme\r\n')
|
||||
out.write('Message-ID: <A2299BB.FF7788@example.org>\r\n')
|
||||
s.write(out, p7, makebuf(body))
|
||||
|
||||
return out.read()
|
||||
|
||||
with open('src/test/resources/email/valid-mail.eml', 'wb') as w:
|
||||
w.write(signmail('This is an automatically generated ACME challenge.',
|
||||
'valid-ca@example.com',
|
||||
'recipient@example.org',
|
||||
'ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=',
|
||||
'src/test/resources/valid-signer-privkey.pem',
|
||||
'src/test/resources/valid-signer.pem'))
|
||||
|
||||
with open('src/test/resources/email/invalid-cert-mismatch.eml', 'wb') as w:
|
||||
w.write(signmail('This is an automatically generated ACME challenge.',
|
||||
'different-ca@example.com',
|
||||
'recipient@example.org',
|
||||
'ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=',
|
||||
'src/test/resources/valid-signer-privkey.pem',
|
||||
'src/test/resources/valid-signer.pem',
|
||||
envelopeFrom="different-ca@example.org"))
|
||||
|
||||
with open('src/test/resources/email/invalid-nosan.eml', 'wb') as w:
|
||||
w.write(signmail('This is an automatically generated ACME challenge.',
|
||||
'valid-ca@example.com',
|
||||
'recipient@example.org',
|
||||
'ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=',
|
||||
'src/test/resources/valid-signer-nosan-privkey.pem',
|
||||
'src/test/resources/valid-signer-nosan.pem'))
|
||||
|
||||
with open('src/test/resources/email/invalid-signed-mail.eml', 'wb') as w:
|
||||
w.write(signmail('This is an automatically generated ACME challenge.',
|
||||
'valid-ca@example.com',
|
||||
'recipient@example.org',
|
||||
'ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=',
|
||||
'src/test/resources/invalid-signer-privkey.pem',
|
||||
'src/test/resources/invalid-signer.pem'))
|
||||
|
||||
with open('src/test/resources/email/invalid-protected-mail-from.eml', 'wb') as w:
|
||||
w.write(signmail('This is an automatically generated ACME challenge.',
|
||||
'valid-ca@example.com',
|
||||
'recipient@example.org',
|
||||
'ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=',
|
||||
'src/test/resources/valid-signer-privkey.pem',
|
||||
'src/test/resources/valid-signer.pem',
|
||||
envelopeFrom="tampered-ca@example.org"))
|
||||
|
||||
with open('src/test/resources/email/invalid-protected-mail-to.eml', 'wb') as w:
|
||||
w.write(signmail('This is an automatically generated ACME challenge.',
|
||||
'valid-ca@example.com',
|
||||
'recipient@example.org',
|
||||
'ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=',
|
||||
'src/test/resources/valid-signer-privkey.pem',
|
||||
'src/test/resources/valid-signer.pem',
|
||||
envelopeTo="tampered-recipient@example.com"))
|
||||
|
||||
with open('src/test/resources/email/invalid-protected-mail-subject.eml', 'wb') as w:
|
||||
w.write(signmail('This is an automatically generated ACME challenge.',
|
||||
'valid-ca@example.com',
|
||||
'recipient@example.org',
|
||||
'ACME: LgYemJLy3F1LDkiJrdIGbEzyFJyOyf6vBdyZ1TG3sME=',
|
||||
'src/test/resources/valid-signer-privkey.pem',
|
||||
'src/test/resources/valid-signer.pem',
|
||||
envelopeSubject="ACME: aDiFfErEnTtOkEn"))
|
|
@ -0,0 +1,37 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# acme4j - Java ACME client
|
||||
#
|
||||
# Copyright (C) 2022 Richard "Shred" Körber
|
||||
# http://acme4j.shredzone.org
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
#
|
||||
|
||||
#
|
||||
# Generates test keys for S/MIME unit tests.
|
||||
#
|
||||
# WARNING: DO NOT USE THIS CODE FOR KEY GENERATION IN PRODUCTION
|
||||
# ENVIRONMENTS!
|
||||
#
|
||||
|
||||
TARGET=src/test/resources/
|
||||
|
||||
openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 3650 \
|
||||
-keyout "$TARGET/valid-signer-privkey.pem" -out "$TARGET/valid-signer.pem" \
|
||||
-subj "/C=XX/L=Acme City/O=Acme Certificates Ltd/CN=example.com/emailAddress=valid-ca@example.com" \
|
||||
-addext "subjectAltName=email:valid-ca@example.com"
|
||||
|
||||
openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 3650 \
|
||||
-keyout "$TARGET/valid-signer-nosan-privkey.pem" -out "$TARGET/valid-signer-nosan.pem" \
|
||||
-subj "/C=XX/L=Acme City/O=Acme Certificates Ltd/CN=example.com/emailAddress=valid-ca@example.com"
|
||||
|
||||
openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 3650 \
|
||||
-keyout "$TARGET/invalid-signer-privkey.pem" -out "$TARGET/invalid-signer.pem" \
|
||||
-subj "/C=XX/L=Acme City/O=Emca Certificates Ltd/CN=example.com/emailAddress=invalid-ca@example.com" \
|
||||
-addext "subjectAltName=email:invalid-ca@example.com"
|
|
@ -14,7 +14,7 @@ To use the S/MIME support, you need to:
|
|||
* add the `acme4j-smime` module to your list of dependencies
|
||||
* make sure that `BouncyCastleProvider` is added as security provider
|
||||
|
||||
[RFC 8823](https://tools.ietf.org/html/rfc8823) requires that the DKIM or S/MIME signature of incoming mails _must_ be checked. Outgoing mails _must_ have a valid DKIM or S/MIME signature. This is out of the scope of `acme4j-smime`, but is usually performed by a MTA.
|
||||
[RFC 8823](https://tools.ietf.org/html/rfc8823) requires that the DKIM or S/MIME signature of incoming mails _must_ be checked. Outgoing mails _must_ have a valid DKIM signature. Starting with v2.15, _acme4j_ is able to validate and sign S/MIME verification mails. DKIM is usually done by the MTA and thus out of the scope of `acme4j-smime`.
|
||||
|
||||
## Ordering
|
||||
|
||||
|
@ -59,7 +59,7 @@ EmailReply00Challenge challenge = // challenge that is requested by the C
|
|||
EmailIdentifier identifier = // email address to get the S/MIME cert for
|
||||
javax.mail.Session mailSession = // javax.mail session
|
||||
|
||||
Message response = new EmailProcessor(challengeMessage)
|
||||
Message response = EmailProcessor.plainMessage(challengeMessage)
|
||||
.expectedIdentifier(identifier)
|
||||
.withChallenge(challenge)
|
||||
.respond()
|
||||
|
@ -69,4 +69,28 @@ Transport.send(response); // send response to the CA
|
|||
challenge.trigger(); // trigger the challenge
|
||||
```
|
||||
|
||||
The `EmailProcessor` and the related `ResponseGenerator` offer more methods for validating and for customizing the response email.
|
||||
The `EmailProcessor` and the related `ResponseGenerator` offer more methods for validating and for customizing the response email, see [the autodocs](../acme4j-smime/apidocs/org.shredzone.acme4j.smime/module-summary.html).
|
||||
|
||||
## Validating S/MIME Challenge E-Mails
|
||||
|
||||
The `EmailProcessor` is able to validate challenge e-mails that were signed by the CA using S/MIME. To do so, invoke the processor like this:
|
||||
|
||||
```java
|
||||
Message challengeMessage = // incoming challenge message from the CA
|
||||
EmailReply00Challenge challenge = // challenge that is requested by the CA
|
||||
EmailIdentifier identifier = // email address to get the S/MIME cert for
|
||||
javax.mail.Session mailSession = // javax.mail session
|
||||
X509Certificate signCert = // CA's signing certificate, for validation
|
||||
boolean strict = // strict checks?
|
||||
|
||||
Message response = EmailProcessor.smimeMessage(challengeMessage, mailSession, signCert, strict)
|
||||
.expectedIdentifier(identifier)
|
||||
.withChallenge(challenge)
|
||||
.respond()
|
||||
.generateResponse(mailSession);
|
||||
|
||||
Transport.send(response); // send response to the CA
|
||||
challenge.trigger(); // trigger the challenge
|
||||
```
|
||||
|
||||
If `strict` is set to `true`, the S/MIME protected headers `From:`, `To:`, and `Subject:` inside the e-mail **must** match these headers of the wrapping `challengeMessage`. It is recommended to do strict checks. However, if the inbound MTA is changing the headers of the wrapping mail, this flag can be set to `false` instead. In this case, the wrapping headers are ignored, and only the protected headers are used for responding to the challenge.
|
||||
|
|
|
@ -31,7 +31,7 @@ Latest version: 
|
||||
* [slf4j](http://www.slf4j.org/)
|
||||
* For `acme4j-utils`: [Bouncy Castle](https://www.bouncycastle.org/)
|
||||
* For `acme4j-smime`: [Jakarta Mail](https://eclipse-ee4j.github.io/mail/)
|
||||
* For `acme4j-smime`: [Jakarta Mail](https://eclipse-ee4j.github.io/mail/), [Bouncy Castle](https://www.bouncycastle.org/)
|
||||
|
||||
## Quick Start
|
||||
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
|
||||
This document will help you migrate your code to the latest _acme4j_ version.
|
||||
|
||||
## Migration to Version 2.15
|
||||
|
||||
- `acme4j-smime` requires BouncyCastle now. The `BouncyCastleProvider` must also be added as security provider.
|
||||
- In `acme4j-smime`, the `EmailProcessor` constructor is private now. Use `EmailProcessor.plainMessage()` as drop-in replacement.
|
||||
|
||||
## Migration to Version 2.13
|
||||
|
||||
- The `acme4j-smime` module has switched from _JavaMail_ to _Jakarta Mail_. Unfortunately, this is a breaking API change because classes like `javax.mail.internet.InternetAddress` have moved to respective `jakarta.mail` packages.
|
||||
|
|
Loading…
Reference in New Issue