|
53 | 53 | import javax.mail.internet.MimeMultipart; |
54 | 54 | import javax.mail.internet.MimePart; |
55 | 55 |
|
| 56 | +import com.sun.mail.smtp.SMTPMessage; |
56 | 57 | import org.bouncycastle.asn1.ASN1EncodableVector; |
57 | 58 | import org.bouncycastle.asn1.cms.AttributeTable; |
58 | 59 | import org.bouncycastle.asn1.cms.IssuerAndSerialNumber; |
59 | 60 | import org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute; |
60 | 61 | import org.bouncycastle.asn1.smime.SMIMECapability; |
61 | 62 | import org.bouncycastle.asn1.smime.SMIMECapabilityVector; |
62 | 63 | import org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute; |
| 64 | +import org.bouncycastle.asn1.x500.RDN; |
63 | 65 | import org.bouncycastle.asn1.x500.X500Name; |
| 66 | +import org.bouncycastle.asn1.x500.style.BCStyle; |
| 67 | +import org.bouncycastle.asn1.x500.style.IETFUtils; |
64 | 68 | import org.bouncycastle.cert.X509CertificateHolder; |
65 | 69 | import org.bouncycastle.cert.jcajce.JcaCertStore; |
66 | 70 | import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; |
@@ -390,23 +394,28 @@ private static JcaCertStore getCertificateStore(SmimeKey smimeKey) throws Certif |
390 | 394 | } |
391 | 395 | return new JcaCertStore(certificateList); |
392 | 396 | } |
393 | | - |
| 397 | + |
394 | 398 | /** |
395 | 399 | * Signs a MIME message and yields a new S/MIME signed MIME message. |
396 | | - * |
| 400 | + * |
397 | 401 | * @param session |
398 | 402 | * The {@link Session} that is used in conjunction with the |
399 | 403 | * original {@link MimeMessage}. |
400 | 404 | * @param mimeMessage |
401 | | - * The original {@link MimeMessage} to be signed. |
| 405 | + * The original {@link MimeMessage} or {@link SMTPMessage} to be signed. |
402 | 406 | * @param smimeKey |
403 | 407 | * The {@link SmimeKey} used to obtain the {@link PrivateKey} to |
404 | 408 | * sign the original message with. |
405 | | - * @return The new S/MIME signed {@link MimeMessage}. |
| 409 | + * @return The new S/MIME signed {@link MimeMessage} or {@link SMTPMessage}. |
406 | 410 | */ |
407 | | - public static MimeMessage sign(Session session, MimeMessage mimeMessage, SmimeKey smimeKey) { |
| 411 | + public static <T extends MimeMessage> T sign(Session session, T mimeMessage, SmimeKey smimeKey) { |
| 412 | + return (mimeMessage instanceof SMTPMessage) |
| 413 | + ? sign(mimeMessage, (T) new SMTPMessage(session), smimeKey) |
| 414 | + : sign(mimeMessage, (T) new MimeMessage(session), smimeKey); |
| 415 | + } |
| 416 | + |
| 417 | + private static <T extends MimeMessage> T sign(T mimeMessage, T signedMessage, SmimeKey smimeKey) { |
408 | 418 | try { |
409 | | - MimeMessage signedMessage = new MimeMessage(session); |
410 | 419 | copyHeaderLines(mimeMessage, signedMessage); |
411 | 420 | copyContent(sign(extractMimeBodyPart(mimeMessage), smimeKey), signedMessage); |
412 | 421 | return signedMessage; |
@@ -491,6 +500,61 @@ private static boolean checkSignature(SMIMESigned smimeSigned) throws MessagingE |
491 | 500 | throw handledException(e); |
492 | 501 | } |
493 | 502 | } |
| 503 | + |
| 504 | + /** |
| 505 | + * @param mimeMultipart |
| 506 | + * The {@link MimeMultipart} to be checked. |
| 507 | + * @return The subject / address to which the certificate was issued to. Email clients may use this to show |
| 508 | + * {@code "Signed by: <subject / address>"} |
| 509 | + */ |
| 510 | + public static String getSignedByAddress(MimeMultipart mimeMultipart) { |
| 511 | + try { |
| 512 | + return getSignedByAddress(new SMIMESigned(mimeMultipart)); |
| 513 | + } catch (Exception e) { |
| 514 | + throw handledException(e); |
| 515 | + } |
| 516 | + } |
| 517 | + |
| 518 | + /** |
| 519 | + * @param mimePart |
| 520 | + * The {@link MimePart} to be checked. |
| 521 | + * @return The subject / address to which the certificate was issued to. Email clients may use this to show |
| 522 | + * {@code "Signed by: <subject / address>"} |
| 523 | + */ |
| 524 | + public static String getSignedByAddress(MimePart mimePart) { |
| 525 | + try { |
| 526 | + if (mimePart.isMimeType("multipart/signed")) { |
| 527 | + return getSignedByAddress(new SMIMESigned((MimeMultipart) mimePart.getContent())); |
| 528 | + } else if (mimePart.isMimeType("application/pkcs7-mime") || mimePart.isMimeType("application/x-pkcs7-mime")) { |
| 529 | + return getSignedByAddress(new SMIMESigned(mimePart)); |
| 530 | + } else { |
| 531 | + throw new SmimeException("Message not signed"); |
| 532 | + } |
| 533 | + } catch (Exception e) { |
| 534 | + throw handledException(e); |
| 535 | + } |
| 536 | + } |
| 537 | + |
| 538 | + /** |
| 539 | + * Returns the subject / address to which the certificate was issued to. Email clients may use this to show |
| 540 | + * {@code "Signed by: <subject / address>"} |
| 541 | + */ |
| 542 | + private static String getSignedByAddress(SMIMESigned smimeSigned) { |
| 543 | + try { |
| 544 | + @SuppressWarnings("rawtypes") |
| 545 | + Store certificates = smimeSigned.getCertificates(); |
| 546 | + |
| 547 | + SignerInformation signerInformation = smimeSigned.getSignerInfos().getSigners().iterator().next(); |
| 548 | + X509Certificate certificate = getCertificate(certificates, signerInformation.getSID()); |
| 549 | + SignerInformationVerifier verifier = getVerifier(certificate); |
| 550 | + X500Name x500name = verifier.getAssociatedCertificate().getSubject(); |
| 551 | + RDN cn = x500name.getRDNs(BCStyle.CN)[0]; |
| 552 | + return IETFUtils.valueToString(cn.getFirst().getValue()); |
| 553 | + |
| 554 | + } catch (Exception e) { |
| 555 | + throw handledException(e); |
| 556 | + } |
| 557 | + } |
494 | 558 |
|
495 | 559 | private static X509Certificate getCertificate(@SuppressWarnings("rawtypes") Store certificates, SignerId signerId) |
496 | 560 | throws CertificateException { |
|
0 commit comments