package org.jboss.resteasy.test.crypto; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bouncycastle.cms.SignerInfoGenerator; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.SignerInformationStore; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.mail.smime.SMIMESigned; import org.bouncycastle.mail.smime.SMIMESignedGenerator; import org.jboss.resteasy.security.DerUtils; import org.jboss.resteasy.security.PemUtils; import org.jboss.resteasy.utils.TestUtil; import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import javax.mail.MessagingException; import javax.mail.internet.InternetHeaders; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMultipart; import javax.mail.util.ByteArrayDataSource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.security.PrivateKey; import java.security.Security; import java.security.cert.X509Certificate; /** * @tpSubChapter Crypto * @tpChapter Unit tests * @tpTestCaseDetails Test for sign by X509Certificate. * @tpSince RESTEasy 3.0.16 */ public class SignedTest { protected static final Logger logger = LogManager.getLogger(SignedTest.class.getName()); private static X509Certificate cert; private static PrivateKey privateKey; private static PrivateKey badKey; static final String certPemPath; static final String certPrivatePemPath; static final String certPrivateKeyDerPath; static final String pythonPath; static { String base = TestUtil.getResourcePath(SignedTest.class, ""); certPemPath = new StringBuilder().append(base).append("SignedMycert.pem").toString(); certPrivatePemPath = new StringBuilder().append(base).append("MycertPrivate.pem").toString(); certPrivateKeyDerPath = new StringBuilder().append(base).append("SignedPrivateDkimKeyDer.der").toString(); pythonPath = new StringBuilder().append(base).append("SignedPython.txt").toString(); } @BeforeClass public static void setup() throws Exception { Security.addProvider(new BouncyCastleProvider()); InputStream certIs = new FileInputStream(certPemPath); cert = PemUtils.decodeCertificate(certIs); InputStream privateIs = new FileInputStream(certPrivatePemPath); privateKey = PemUtils.decodePrivateKey(privateIs); InputStream badIs = new FileInputStream(certPrivateKeyDerPath); badKey = DerUtils.decodePrivateKey(badIs); } private MimeBodyPart createMsg() throws MessagingException { InternetHeaders ih = new InternetHeaders(); ih.addHeader("Content-Type", "application/xml"); return new MimeBodyPart(ih, "<customer name=\"bill\"/>".getBytes()); } private void output(MimeBodyPart mp) throws IOException, MessagingException { ByteArrayOutputStream os = new ByteArrayOutputStream(); mp.writeTo(os); String s = new String(os.toByteArray()); logger.info(s); } private void output(MimeMultipart mp) throws IOException, MessagingException { ByteArrayOutputStream os = new ByteArrayOutputStream(); mp.writeTo(os); String s = new String(os.toByteArray()); logger.info(s); } /** * @tpTestDetails Multipart test * @tpSince RESTEasy 3.0.16 */ @Test public void testMultipart() throws Exception { MimeMultipart mp = new MimeMultipart(); InternetHeaders ih = new InternetHeaders(); ih.addHeader("Content-Type", "text/xml"); MimeBodyPart bp = new MimeBodyPart(ih, "<customer/>".getBytes()); mp.addBodyPart(bp); bp = new MimeBodyPart(ih, "<product/>".getBytes()); mp.addBodyPart(bp); ByteArrayOutputStream os = new ByteArrayOutputStream(); mp.writeTo(os); String s = new String(os.toByteArray()); logger.info(s); logger.info("************"); String contentType = mp.getContentType(); contentType = contentType.replace("\r\n", "").replace("\t", " "); logger.info("Content-Type: " + contentType); mp = new MimeMultipart(new ByteArrayDataSource(s.getBytes(), "multipart/signed")); logger.info("count: " + mp.getCount()); } /** * @tpTestDetails Test for python sign format * @tpSince RESTEasy 3.0.16 */ @Test public void testPythonSigned() throws Exception { final InputStream pythonIs = new FileInputStream(pythonPath); ByteArrayDataSource ds = new ByteArrayDataSource(pythonIs, "multipart/signed"); MimeMultipart mm = new MimeMultipart(ds); logger.info(mm.getContentType()); logger.info("Multipart.count(): " + mm.getCount()); MimeBodyPart mbp = (MimeBodyPart) mm.getBodyPart(0); output(mbp); SMIMESigned signed = new SMIMESigned(mm); SignerInformationStore signers = signed.getSignerInfos(); Assert.assertEquals("Wrong count of signers", 1, signers.size()); SignerInformation signer = signers.getSigners().iterator().next(); Assert.assertTrue("Unsuccessful verification of signer", signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert.getPublicKey()))); } /** * @tpTestDetails Check output after signing * @tpSince RESTEasy 3.0.16 */ @Test public void testOutput() throws Exception { { SMIMESignedGenerator gen = new SMIMESignedGenerator(); SignerInfoGenerator signer = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").build("SHA1WITHRSA", privateKey, cert); gen.addSignerInfoGenerator(signer); MimeMultipart mp = gen.generate(createMsg()); output(mp); } { SMIMESignedGenerator gen = new SMIMESignedGenerator(); SignerInfoGenerator signer = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").build("SHA1WITHRSA", privateKey, cert); gen.addSignerInfoGenerator(signer); MimeMultipart mp = gen.generate(createMsg()); ByteArrayOutputStream os = new ByteArrayOutputStream(); mp.writeTo(os); ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); String contentType = mp.getContentType(); contentType = contentType.replace("\r\n", "").replace("\t", " "); ByteArrayDataSource ds = new ByteArrayDataSource(is, contentType); MimeMultipart mm = new MimeMultipart(ds); MimeBodyPart part = (MimeBodyPart) mm.getBodyPart(0); } } /** * @tpTestDetails Test python-style verification * @tpSince RESTEasy 3.0.16 */ @Test public void testPythonVerified() throws Exception { SMIMESignedGenerator gen = new SMIMESignedGenerator(); SignerInfoGenerator signer = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").build("SHA1WITHRSA", privateKey, cert); gen.addSignerInfoGenerator(signer); MimeMultipart mp = gen.generate(createMsg()); ByteArrayOutputStream os = new ByteArrayOutputStream(); mp.writeTo(os); String contentType = mp.getContentType(); contentType = contentType.replace("\r\n", "").replace("\t", " "); logger.info(contentType); String s = new String(os.toByteArray()); StringBuilder builder = new StringBuilder(); builder.append("Content-Type: ").append(contentType).append("\r\n\r\n").append(s); String output = builder.toString(); FileOutputStream fp = new FileOutputStream("target/smime_signed.txt"); fp.write(output.getBytes()); fp.close(); } /** * @tpTestDetails Test python-style wrong verification * @tpSince RESTEasy 3.0.16 */ @Test public void testPythonVerifiedBad() throws Exception { SMIMESignedGenerator gen = new SMIMESignedGenerator(); SignerInfoGenerator signer = new JcaSimpleSignerInfoGeneratorBuilder().setProvider("BC").build("SHA1WITHRSA", badKey, cert); gen.addSignerInfoGenerator(signer); MimeMultipart mp = gen.generate(createMsg()); ByteArrayOutputStream os = new ByteArrayOutputStream(); mp.writeTo(os); String contentType = mp.getContentType(); contentType = contentType.replace("\r\n", "").replace("\t", " "); logger.info(contentType); String s = new String(os.toByteArray()); StringBuilder builder = new StringBuilder(); builder.append("Content-Type: ").append(contentType).append("\r\n\r\n").append(s); String output = builder.toString(); FileOutputStream fp = new FileOutputStream("target/smime_signed_bad.txt"); fp.write(output.getBytes()); fp.close(); } }