Email with attachments and images signed with boun

2019-07-04 05:09发布

问题:

I have a MailComposer that builds a mime message and digitally signs the body part (content) using a MailSigningService.

Signing is implemented in the sign() and buildSignedGenerator() methods.

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).

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?

MailComposer.java

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;
}

MailSigningService.java

@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<Certificate> certificates=new ArrayList<Certificate>();
    if (caCertificateChain !=null && caCertificateChain.length>0) {
        certificates.addAll(Arrays.asList(caCertificateChain));
    } else {
        certificates.add(signerCertificate);
    }
    Store certificateStore = new JcaCertStore(certificates);
    generator.addCertificates(certificateStore);
    return generator;
}