package org.bouncycastle.cms.test; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.security.KeyPair; import java.security.MessageDigest; import java.security.Security; import java.security.cert.X509CRL; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import junit.framework.Test; import junit.framework.TestCase; import junit.framework.TestSuite; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.cert.jcajce.JcaCRLStore; import org.bouncycastle.cert.jcajce.JcaCertStore; import org.bouncycastle.cms.CMSCompressedDataStreamGenerator; import org.bouncycastle.cms.CMSDigestedData; import org.bouncycastle.cms.CMSSignedDataParser; import org.bouncycastle.cms.CMSSignedDataStreamGenerator; import org.bouncycastle.cms.CMSTypedStream; import org.bouncycastle.cms.SignerInformation; import org.bouncycastle.cms.SignerInformationStore; import org.bouncycastle.cms.jcajce.JcaSignerInfoVerifierBuilder; import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoGeneratorBuilder; import org.bouncycastle.cms.jcajce.JcaX509CertSelectorConverter; import org.bouncycastle.cms.jcajce.ZlibCompressor; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.operator.DigestCalculatorProvider; import org.bouncycastle.operator.OperatorCreationException; import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder; import org.bouncycastle.util.Arrays; import org.bouncycastle.util.Store; import org.bouncycastle.util.encoders.Base64; public class MiscDataStreamTest extends TestCase { private static final String BC = BouncyCastleProvider.PROVIDER_NAME; private static byte[] data = Base64.decode( "TUlNRS1WZXJzaW9uOiAxLjAKQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9v" + "Y3RldC1zdHJlYW0KQ29udGVudC1UcmFuc2Zlci1FbmNvZGluZzogYmluYXJ5" + "CkNvbnRlbnQtRGlzcG9zaXRpb246IGF0dGFjaG1lbnQ7IGZpbGVuYW1lPWRv" + "Yy5iaW4KClRoaXMgaXMgYSB2ZXJ5IGh1Z2Ugc2VjcmV0LCBtYWRlIHdpdGgg" + "b3BlbnNzbAoKCgo="); private static byte[] digestedData = Base64.decode( "MIIBGAYJKoZIhvcNAQcFoIIBCTCCAQUCAQAwCwYJYIZIAWUDBAIBMIHQBgkq" + "hkiG9w0BBwGggcIEgb9NSU1FLVZlcnNpb246IDEuMApDb250ZW50LVR5cGU6" + "IGFwcGxpY2F0aW9uL29jdGV0LXN0cmVhbQpDb250ZW50LVRyYW5zZmVyLUVu" + "Y29kaW5nOiBiaW5hcnkKQ29udGVudC1EaXNwb3NpdGlvbjogYXR0YWNobWVu" + "dDsgZmlsZW5hbWU9ZG9jLmJpbgoKVGhpcyBpcyBhIHZlcnkgaHVnZSBzZWNy" + "ZXQsIG1hZGUgd2l0aCBvcGVuc3NsCgoKCgQgHLG72tSYW0LgcxOA474iwdCv" + "KyhnaV4RloWTAvkq+do="); private static final String TEST_MESSAGE = "Hello World!"; private static String _signDN; private static KeyPair _signKP; private static X509Certificate _signCert; private static String _origDN; private static KeyPair _origKP; private static X509Certificate _origCert; private static String _reciDN; private static KeyPair _reciKP; private static X509Certificate _reciCert; private static KeyPair _origDsaKP; private static X509Certificate _origDsaCert; private static X509CRL _signCrl; private static X509CRL _origCrl; private static boolean _initialised = false; private static final JcaX509CertSelectorConverter selectorConverter = new JcaX509CertSelectorConverter(); private static final DigestCalculatorProvider digCalcProv; static { try { digCalcProv = new JcaDigestCalculatorProviderBuilder().build(); } catch (OperatorCreationException e) { throw new IllegalStateException("can't create default provider!!!"); } } public MiscDataStreamTest(String name) { super(name); } private static void init() throws Exception { if (!_initialised) { _initialised = true; Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); _signDN = "O=Bouncy Castle, C=AU"; _signKP = CMSTestUtil.makeKeyPair(); _signCert = CMSTestUtil.makeCertificate(_signKP, _signDN, _signKP, _signDN); _origDN = "CN=Bob, OU=Sales, O=Bouncy Castle, C=AU"; _origKP = CMSTestUtil.makeKeyPair(); _origCert = CMSTestUtil.makeCertificate(_origKP, _origDN, _signKP, _signDN); _origDsaKP = CMSTestUtil.makeDsaKeyPair(); _origDsaCert = CMSTestUtil.makeCertificate(_origDsaKP, _origDN, _signKP, _signDN); _reciDN = "CN=Doug, OU=Sales, O=Bouncy Castle, C=AU"; _reciKP = CMSTestUtil.makeKeyPair(); _reciCert = CMSTestUtil.makeCertificate(_reciKP, _reciDN, _signKP, _signDN); _signCrl = CMSTestUtil.makeCrl(_signKP); _origCrl = CMSTestUtil.makeCrl(_origKP); } } private void verifySignatures(CMSSignedDataParser sp, byte[] contentDigest) throws Exception { Store certStore = sp.getCertificates(); SignerInformationStore signers = sp.getSignerInfos(); Collection c = signers.getSigners(); Iterator it = c.iterator(); while (it.hasNext()) { SignerInformation signer = (SignerInformation)it.next(); Collection certCollection = certStore.getMatches(signer.getSID()); Iterator certIt = certCollection.iterator(); X509CertificateHolder cert = (X509CertificateHolder)certIt.next(); assertEquals(true, signer.verify(new JcaSignerInfoVerifierBuilder(digCalcProv).setProvider(BC).build(cert))); if (contentDigest != null) { assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest())); } } } private void verifySignatures(CMSSignedDataParser sp) throws Exception { verifySignatures(sp, null); } private void verifyEncodedData(ByteArrayOutputStream bOut) throws Exception { CMSSignedDataParser sp; sp = new CMSSignedDataParser(digCalcProv, bOut.toByteArray()); sp.getSignedContent().drain(); verifySignatures(sp); sp.close(); } private void checkSigParseable(byte[] sig) throws Exception { CMSSignedDataParser sp = new CMSSignedDataParser(digCalcProv, sig); sp.getVersion(); CMSTypedStream sc = sp.getSignedContent(); if (sc != null) { sc.drain(); } sp.getCertificates(); sp.getSignerInfos(); sp.close(); } public void testSHA1WithRSA() throws Exception { List certList = new ArrayList(); List crlList = new ArrayList(); ByteArrayOutputStream bOut = new ByteArrayOutputStream(); certList.add(_origCert); certList.add(_signCert); crlList.add(_signCrl); crlList.add(_origCrl); CMSSignedDataStreamGenerator gen = new CMSSignedDataStreamGenerator(); gen.addSignerInfoGenerator(new JcaSimpleSignerInfoGeneratorBuilder().setProvider(BC).build("SHA1withRSA", _origKP.getPrivate(), _origCert)); gen.addCertificates(new JcaCertStore(certList)); gen.addCRLs(new JcaCRLStore(crlList)); OutputStream sigOut = gen.open(bOut); CMSCompressedDataStreamGenerator cGen = new CMSCompressedDataStreamGenerator(); OutputStream cOut = cGen.open(sigOut, new ZlibCompressor()); cOut.write(TEST_MESSAGE.getBytes()); cOut.close(); sigOut.close(); checkSigParseable(bOut.toByteArray()); // generate compressed stream ByteArrayOutputStream cDataOut = new ByteArrayOutputStream(); cOut = cGen.open(cDataOut, new ZlibCompressor()); cOut.write(TEST_MESSAGE.getBytes()); cOut.close(); CMSSignedDataParser sp = new CMSSignedDataParser(digCalcProv, new CMSTypedStream(new ByteArrayInputStream(cDataOut.toByteArray())), bOut.toByteArray()); sp.getSignedContent().drain(); // // compute expected content digest // MessageDigest md = MessageDigest.getInstance("SHA1", BC); verifySignatures(sp, md.digest(cDataOut.toByteArray())); } public void testDigestedData() throws Exception { CMSDigestedData digData = new CMSDigestedData(digestedData); assertTrue(Arrays.areEqual(data, (byte[])digData.getDigestedContent().getContent())); assertTrue(digData.verify(new JcaDigestCalculatorProviderBuilder().setProvider(BC).build())); } public static Test suite() throws Exception { init(); return new CMSTestSetup(new TestSuite(MiscDataStreamTest.class)); } }