From dde9d815631647efea23a97cf89dfde7989d452e Mon Sep 17 00:00:00 2001 From: bbottema Date: Sat, 13 Apr 2019 22:30:39 +0200 Subject: [PATCH 1/3] Ignore IntelliJ project files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 91a5ca7..9818eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ .project .classpath .checkstyle +/.idea +/*.iml From 97a76ab0a5359645435788c807416ff3cb78b5a8 Mon Sep 17 00:00:00 2001 From: bbottema Date: Sat, 13 Apr 2019 22:37:12 +0200 Subject: [PATCH 2/3] #5: Implement API to return the (CN) subject of the first certificate on a MimePart. This subject is actually the email address of the person to which the certificate was issued to, a value often used by email clients to display "Signed by: ". --- .../utils/mail/smime/SmimeUtil.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/main/java/net/markenwerk/utils/mail/smime/SmimeUtil.java b/src/main/java/net/markenwerk/utils/mail/smime/SmimeUtil.java index 60b6e46..0456d04 100644 --- a/src/main/java/net/markenwerk/utils/mail/smime/SmimeUtil.java +++ b/src/main/java/net/markenwerk/utils/mail/smime/SmimeUtil.java @@ -60,7 +60,10 @@ import org.bouncycastle.asn1.smime.SMIMECapability; import org.bouncycastle.asn1.smime.SMIMECapabilityVector; import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute; +import org.bouncycastle.asn1.x500.RDN; import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x500.style.IETFUtils; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaCertStore; import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; @@ -491,6 +494,61 @@ private static boolean checkSignature(SMIMESigned smimeSigned) throws MessagingE throw handledException(e); } } + + /** + * @param mimeMultipart + * The {@link MimeMultipart} to be checked. + * @return The subject / address to which the certificate was issued to. Email clients may use this to show + * {@code "Signed by: "} + */ + public static String getSignedByAddress(MimeMultipart mimeMultipart) { + try { + return getSignedByAddress(new SMIMESigned(mimeMultipart)); + } catch (Exception e) { + throw handledException(e); + } + } + + /** + * @param mimePart + * The {@link MimePart} to be checked. + * @return The subject / address to which the certificate was issued to. Email clients may use this to show + * {@code "Signed by: "} + */ + public static String getSignedByAddress(MimePart mimePart) { + try { + if (mimePart.isMimeType("multipart/signed")) { + return getSignedByAddress(new SMIMESigned((MimeMultipart) mimePart.getContent())); + } else if (mimePart.isMimeType("application/pkcs7-mime") || mimePart.isMimeType("application/x-pkcs7-mime")) { + return getSignedByAddress(new SMIMESigned(mimePart)); + } else { + throw new SmimeException("Message not signed"); + } + } catch (Exception e) { + throw handledException(e); + } + } + + /** + * Returns the subject / address to which the certificate was issued to. Email clients may use this to show + * {@code "Signed by: "} + */ + private static String getSignedByAddress(SMIMESigned smimeSigned) { + try { + @SuppressWarnings("rawtypes") + Store certificates = smimeSigned.getCertificates(); + + SignerInformation signerInformation = smimeSigned.getSignerInfos().getSigners().iterator().next(); + X509Certificate certificate = getCertificate(certificates, signerInformation.getSID()); + SignerInformationVerifier verifier = getVerifier(certificate); + X500Name x500name = verifier.getAssociatedCertificate().getSubject(); + RDN cn = x500name.getRDNs(BCStyle.CN)[0]; + return IETFUtils.valueToString(cn.getFirst().getValue()); + + } catch (Exception e) { + throw handledException(e); + } + } private static X509Certificate getCertificate(@SuppressWarnings("rawtypes") Store certificates, SignerId signerId) throws CertificateException { From 0137f246677b7380819e5b8ef4e0f8c3b917541a Mon Sep 17 00:00:00 2001 From: bbottema Date: Fri, 31 May 2019 20:01:06 +0200 Subject: [PATCH 3/3] #8: Added support for SMTPMessage --- .../markenwerk/utils/mail/smime/SmimeUtil.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/net/markenwerk/utils/mail/smime/SmimeUtil.java b/src/main/java/net/markenwerk/utils/mail/smime/SmimeUtil.java index 0456d04..e900e49 100644 --- a/src/main/java/net/markenwerk/utils/mail/smime/SmimeUtil.java +++ b/src/main/java/net/markenwerk/utils/mail/smime/SmimeUtil.java @@ -53,6 +53,7 @@ import javax.mail.internet.MimeMultipart; import javax.mail.internet.MimePart; +import com.sun.mail.smtp.SMTPMessage; import org.bouncycastle.asn1.ASN1EncodableVector; import org.bouncycastle.asn1.cms.AttributeTable; import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; @@ -393,23 +394,28 @@ private static JcaCertStore getCertificateStore(SmimeKey smimeKey) throws Certif } return new JcaCertStore(certificateList); } - + /** * Signs a MIME message and yields a new S/MIME signed MIME message. - * + * * @param session * The {@link Session} that is used in conjunction with the * original {@link MimeMessage}. * @param mimeMessage - * The original {@link MimeMessage} to be signed. + * The original {@link MimeMessage} or {@link SMTPMessage} to be signed. * @param smimeKey * The {@link SmimeKey} used to obtain the {@link PrivateKey} to * sign the original message with. - * @return The new S/MIME signed {@link MimeMessage}. + * @return The new S/MIME signed {@link MimeMessage} or {@link SMTPMessage}. */ - public static MimeMessage sign(Session session, MimeMessage mimeMessage, SmimeKey smimeKey) { + public static T sign(Session session, T mimeMessage, SmimeKey smimeKey) { + return (mimeMessage instanceof SMTPMessage) + ? sign(mimeMessage, (T) new SMTPMessage(session), smimeKey) + : sign(mimeMessage, (T) new MimeMessage(session), smimeKey); + } + + private static T sign(T mimeMessage, T signedMessage, SmimeKey smimeKey) { try { - MimeMessage signedMessage = new MimeMessage(session); copyHeaderLines(mimeMessage, signedMessage); copyContent(sign(extractMimeBodyPart(mimeMessage), smimeKey), signedMessage); return signedMessage;