diff --git a/.gitignore b/.gitignore index 91a5ca7..9818eb8 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ .project .classpath .checkstyle +/.idea +/*.iml 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..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; @@ -60,7 +61,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; @@ -390,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; @@ -491,6 +500,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 {