Note that there are some explanatory texts on larger screens.

plurals
  1. POEmail with attachments and images signed with bouncycastle can't be verified by email client
    text
    copied!<p>I have a <strong>MailComposer</strong> that builds a mime message and digitally signs the body part (content) using a <strong>MailSigningService</strong>. </p> <p>Signing is implemented in the <em>sign()</em> and <em>buildSignedGenerator()</em> methods.</p> <p>After receiving the mail, the mail client detects a signature but complains that the mail may have been tampered. The mail client is able to show the certificate, it shows all certificates (incl the CA).</p> <p>So, either the signing implementation based on Bouncycastle is not done properly or the message itself is not built as it should be. Any hints what could go wrong here?</p> <p>MailComposer.java</p> <pre><code>private MimeMessage buildMimeMessage(com.jumio.jump.domain.Message message, String[] recipients, String subject, Session session) throws MessagingException, IOException { MimeMultipart parts = buildContentParts(message); parts = (message.getSendOnBehalfOfDomain() != null) ? signContentParts(message, parts) : parts; return buildMimeMessage(message, recipients, subject, session, parts); } private MimeMessage buildMimeMessage(com.jumio.jump.domain.Message message, String[] recipients, String subject, Session session, MimeMultipart parts) throws MessagingException { MimeMessage mimeMessage = new MimeMessage(session); mimeMessage.setSubject(subject, "UTF-8"); mimeMessage.setHeader("Content-ParamType", "text/html; charset=UTF-8"); mimeMessage.setSentDate(new Date()); mimeMessage.setFrom(buildFromEmailAddress(message)); for (String recipient : recipients) { if (recipient == null) { continue; } InternetAddress addressTo = new InternetAddress(recipient); mimeMessage.addRecipient(Message.RecipientType.TO, addressTo); } mimeMessage.setContent(parts); return mimeMessage; } private MimeMultipart signContentParts(com.jumio.jump.domain.Message message, MimeMultipart contentParts) throws MessagingException { MimeBodyPart body = new MimeBodyPart(); body.setContent(contentParts); MimeMultipart result; try { result = mailSigningService.sign(body, signerCertificate, certificateChain, privateKey); } catch (Exception e) { logger.error(String.format("Error signing message $s, sending unsigned", message), e); return contentParts; } return result; } </code></pre> <p>MailSigningService.java</p> <pre><code>@Override public MimeMultipart sign(MimeBodyPart mimeBodyPart, X509Certificate signerCertificate, Certificate[] caCertificateChain, PrivateKey privateKey) throws SMIMEException, OperatorCreationException, CertificateEncodingException, NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { Validate.notNull(signerCertificate, "Valid certificate required, check keystore and/or keystore " + "configuration"); Validate.notNull(privateKey, "Valid private key required, check keystore and/or keystore configuration"); SMIMESignedGenerator generator = buildSignedGenerator(signerCertificate, caCertificateChain, privateKey); return generator.generate(mimeBodyPart); } private SMIMESignedGenerator buildSignedGenerator(X509Certificate signerCertificate, Certificate[] caCertificateChain, PrivateKey privateKey) throws OperatorCreationException, CertificateEncodingException, NoSuchProviderException, NoSuchAlgorithmException, InvalidAlgorithmParameterException { SMIMECapabilityVector capabilities = new SMIMECapabilityVector(); capabilities.addCapability(SMIMECapability.dES_EDE3_CBC); capabilities.addCapability(SMIMECapability.rC2_CBC, 128); capabilities.addCapability(SMIMECapability.dES_CBC); ASN1EncodableVector attributes = new ASN1EncodableVector(); attributes.add(new SMIMEEncryptionKeyPreferenceAttribute(new IssuerAndSerialNumber(new X509Name( signerCertificate.getIssuerDN().getName()), signerCertificate.getSerialNumber()))); attributes.add(new SMIMECapabilitiesAttribute(capabilities)); SMIMESignedGenerator generator = new SMIMESignedGenerator(); generator.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(SECURITY_PROVIDER_NAME) .setSignedAttributeGenerator(new AttributeTable(attributes)).build(SIGNER_ALGORITHM, privateKey, signerCertificate)); List&lt;Certificate&gt; certificates=new ArrayList&lt;Certificate&gt;(); if (caCertificateChain !=null &amp;&amp; caCertificateChain.length&gt;0) { certificates.addAll(Arrays.asList(caCertificateChain)); } else { certificates.add(signerCertificate); } Store certificateStore = new JcaCertStore(certificates); generator.addCertificates(certificateStore); return generator; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload