I have some issues with signing emails in java.
I believe my code is good but when I receive the email in my inbox, it says that it is unable to verify the signature.
Here the code - Pretty straightforward :
boolean isAlias = false;
// Add BouncyCastle content handlers to command map
MailcapCommandMap mailcap = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.superman.mail.smime.handlers.pkcs7_signature");
mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.superman.mail.smime.handlers.pkcs7_mime");
mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.superman.mail.smime.handlers.x_pkcs7_signature");
mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.superman.mail.smime.handlers.x_pkcs7_mime");
mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.superman.mail.smime.handlers.multipart_signed");
CommandMap.setDefaultCommandMap(mailcap);
Security.addProvider(new BouncyCastleProvider());
KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream ins = SigningEmail.class.getResourceAsStream("/keystore.jks");
// Provide location of Java Keystore and password for access
keyStore.load(ins,"changeit".toCharArray());
// Find the first legit alias in the keystore and use it
Enumeration<String> es = keyStore.aliases();
String alias = "";
while (es.hasMoreElements()) {
alias = es.nextElement();
// Does alias refer to a private key? Assign true/false to isAlias & evaluate
if (isAlias = keyStore.isKeyEntry(alias)) {
break;
}
}
if (isAlias) {
KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection("***".toCharArray()));
PrivateKey myPrivateKey = pkEntry.getPrivateKey();
// Load certificate chain
Certificate[] chain = keyStore.getCertificateChain(alias);
// Create the SMIMESignedGenerator
SMIMECapabilityVector capabilities = new SMIMECapabilityVector();
capabilities.addCapability(SMIMECapability.dES_EDE3_CBC);
capabilities.addCapability(SMIMECapability.rC2_CBC, 128);
capabilities.addCapability(SMIMECapability.dES_CBC);
capabilities.addCapability(SMIMECapability.aES256_CBC);
capabilities.addCapability(SMIMECapability.aES128_CBC);
capabilities.addCapability(SMIMECapability.aES192_CBC);
//Cert info
X500Name x500 = new X500Name(((X509Certificate) chain[0]).getIssuerDN().getName());
IssuerAndSerialNumber serialNumber = new IssuerAndSerialNumber(x500 , ((X509Certificate) chain[0]).getSerialNumber()) ;
ASN1EncodableVector signedAttrs = new ASN1EncodableVector();
signedAttrs.add(new SMIMEEncryptionKeyPreferenceAttribute(serialNumber));
signedAttrs.add(new SMIMECapabilitiesAttribute(capabilities));
//Set X509
X509Certificate cert = (X509Certificate) keyStore.getCertificate(alias);
List<X509Certificate> certList = new ArrayList<X509Certificate>();
certList.add(cert);
Store certs = new JcaCertStore(certList);
//Signing generator
SMIMESignedGenerator gen = new SMIMESignedGenerator();
gen.addSignerInfoGenerator(
new JcaSimpleSignerInfoGeneratorBuilder()
.setProvider("BC")
.setSignedAttributeGenerator(new AttributeTable(signedAttrs))
.build("SHA1withRSA", myPrivateKey, cert));
gen.addCertificates(certs);
MimeMessage cloneOriginal = new MimeMessage(body);
//Sign
MimeMultipart mainPart = gen.generate(body , "BC");
// Set the content of the signed message
cloneOriginal.setContent(mainPart, mainPart.getContentType());
cloneOriginal.saveChanges();
// Send the message
sender.send(cloneOriginal);
Here what I get from mail :
I used the .pfx to generate the keystone with that command :
keytool -importkeystore -srckeystore /Users/sign.pfx -srcstoretype pkcs12 -destkeystore /Users/keystore.jks -deststoretype jks
It signed from an authority and everything.
So the import and the code looks good to me I believe but it does not work, and I am wondering what I am missing.
Thanks !!
As far as I know, GoDaddy does not sell email signing certificate. You may want to read this review by mozilla and this to know how to obtain one. This article explain several types of certificate:
Knowing which SSL certificate type can help you avoid many problems such as trying to use a certificate for something that it isn't meant to do.
I had to edit the providers to get your code run but then it worked for me. Thanks!
MailcapCommandMap mailcap = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mailcap.addMailcap("application/pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_signature");
mailcap.addMailcap("application/pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.pkcs7_mime");
mailcap.addMailcap("application/x-pkcs7-signature;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_signature");
mailcap.addMailcap("application/x-pkcs7-mime;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.x_pkcs7_mime");
mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
mailcap.addMailcap("multipart/signed;; x-java-content-handler=org.bouncycastle.mail.smime.handlers.multipart_signed");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With