package org.bouncycastle.asn1.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1OctetStringParser;
import org.bouncycastle.asn1.ASN1OutputStream;
import org.bouncycastle.asn1.ASN1SequenceParser;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.ASN1SetParser;
import org.bouncycastle.asn1.ASN1StreamParser;
import org.bouncycastle.asn1.BERTags;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.CompressedData;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.cms.ContentInfoParser;
import org.bouncycastle.asn1.cms.EncryptedContentInfoParser;
import org.bouncycastle.asn1.cms.EnvelopedData;
import org.bouncycastle.asn1.cms.EnvelopedDataParser;
import org.bouncycastle.asn1.cms.KEKRecipientInfo;
import org.bouncycastle.asn1.cms.KeyTransRecipientInfo;
import org.bouncycastle.asn1.cms.RecipientInfo;
import org.bouncycastle.asn1.cms.SignedData;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.io.Streams;
import org.bouncycastle.util.test.SimpleTestResult;
import org.bouncycastle.util.test.Test;
import org.bouncycastle.util.test.TestResult;
public class CMSTest
implements Test
{
byte[] compData = Base64.decode(
"MIAGCyqGSIb3DQEJEAEJoIAwgAIBADANBgsqhkiG9w0BCRADCDCABgkqhkiG9w0BBwGggCSABIIC"
+ "Hnic7ZRdb9owFIbvK/k/5PqVYPFXGK12YYyboVFASSp1vQtZGiLRACZE49/XHoUW7S/0tXP8Efux"
+ "fU5ivWnasml72XFb3gb5druui7ytN803M570nii7C5r8tfwR281hy/p/KSM3+jzH5s3+pbQ90xSb"
+ "P3VT3QbLusnt8WPIuN5vN/vaA2+DulnXTXkXvNTr8j8ouZmkCmGI/UW+ZS/C8zP0bz2dz0zwLt+1"
+ "UEk2M8mlaxjRMByAhZTj0RGYg4TvogiRASROsZgjpVcJCb1KV6QzQeDJ1XkoQ5Jm+C5PbOHZZGRi"
+ "v+ORAcshOGeCcdFJyfgFxdtCdEcmOrbinc/+BBMzRThEYpwl+jEBpciSGWQkI0TSlREmD/eOHb2D"
+ "SGLuESm/iKUFt1y4XHBO2a5oq0IKJKWLS9kUZTA7vC5LSxYmgVL46SIWxIfWBQd6AdrnjLmH94UT"
+ "vGxVibLqRCtIpp4g2qpdtqK1LiOeolpVK5wVQ5P7+QjZAlrh0cePYTx/gNZuB9Vhndtgujl9T/tg"
+ "W9ogK+3rnmg3YWygnTuF5GDS+Q/jIVLnCcYZFc6Kk/+c80wKwZjwdZIqDYWRH68MuBQSXLgXYXj2"
+ "3CAaYOBNJMliTl0X7eV5DnoKIFSKYdj3cRpD/cK/JWTHJRe76MUXnfBW8m7Hd5zhQ4ri2NrVF/WL"
+ "+kV1/3AGSlJ32bFPd2BsQD8uSzIx6lObkjdz95c0AAAAAAAAAAAAAAAA");
byte[] envDataKeyTrns = Base64.decode(
"MIAGCSqGSIb3DQEHA6CAMIACAQAxgcQwgcECAQAwKjAlMRYwFAYDVQQKEw1Cb3Vu"
+ "Y3kgQ2FzdGxlMQswCQYDVQQGEwJBVQIBCjANBgkqhkiG9w0BAQEFAASBgC5vdGrB"
+ "itQSGwifLf3KwPILjaB4WEXgT/IIO1KDzrsbItCJsMA0Smq2y0zptxT0pSRL6JRg"
+ "NMxLk1ySnrIrvGiEPLMR1zjxlT8yQ6VLX+kEoK43ztd1aaLw0oBfrcXcLN7BEpZ1"
+ "TIdjlBfXIOx1S88WY1MiYqJJFc3LMwRUaTEDMIAGCSqGSIb3DQEHATAdBglghkgB"
+ "ZQMEARYEEAfxLMWeaBOTTZQwUq0Y5FuggAQgwOJhL04rjSZCBCSOv5i5XpFfGsOd"
+ "YSHSqwntGpFqCx4AAAAAAAAAAAAA");
byte[] envDataKEK = Base64.decode(
"MIAGCSqGSIb3DQEHA6CAMIACAQIxUqJQAgEEMAcEBQECAwQFMBAGCyqGSIb3DQEJE"
+ "AMHAgE6BDC7G/HyUPilIrin2Yeajqmj795VoLWETRnZAAFcAiQdoQWyz+oCh6WY/H"
+ "jHHi+0y+cwgAYJKoZIhvcNAQcBMBQGCCqGSIb3DQMHBAiY3eDBBbF6naCABBiNdzJb"
+ "/v6+UZB3XXKipxFDUpz9GyjzB+gAAAAAAAAAAAAA");
byte[] envDataNestedNDEF = Base64.decode(
"MIAGCSqGSIb3DQEHA6CAMIACAQAxge8wgewCAQAwgZUwgY8xKDAmBgNVBAoMH1RoZSBMZWdpb24g"
+ "b2YgdGhlIEJvdW5jeSBDYXN0bGUxLzAtBgkqhkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3Vu"
+ "Y3ljYXN0bGUub3JnMREwDwYDVQQIDAhWaWN0b3JpYTESMBAGA1UEBwwJTWVsYm91cm5lMQswCQYD"
+ "VQQGEwJBVQIBATANBgkqhkiG9w0BAQEFAARABIXMd8xiTyWDKO/LQfvdGYTPW3I9oSQWwtm4OIaN"
+ "VINpfY2lfwTvbmE6VXiLKeALC0dMBV8z7DEM9hE0HVmvLDCABgkqhkiG9w0BBwEwHQYJYIZIAWUD"
+ "BAECBBB32ko6WrVxDTqwUYEpV6IUoIAEggKgS6RowrhNlmWWI13zxD/lryxkZ5oWXPUfNiUxYX/P"
+ "r5iscW3s8VKJKUpJ4W5SNA7JGL4l/5LmSnJ4Qu/xzxcoH4r4vmt75EDE9p2Ob2Xi1NuSFAZubJFc"
+ "Zlnp4e05UHKikmoaz0PbiAi277sLQlK2FcVsntTYVT00y8+IwuuQu0ATVqkXC+VhfjV/sK6vQZnw"
+ "2rQKedZhLB7B4dUkmxCujb/UAq4lgSpLMXg2P6wMimTczXyQxRiZxPeI4ByCENjkafXbfcJft2eD"
+ "gv1DEDdYM5WrW9Z75b4lmJiOJ/xxDniHCvum7KGXzpK1d1mqTlpzPC2xoz08/MO4lRf5Mb0bYdq6"
+ "CjMaYqVwGsYryp/2ayX+d8H+JphEG+V9Eg8uPcDoibwhDI4KkoyGHstPw5bxcy7vVFt7LXUdNjJc"
+ "K1wxaUKEXDGKt9Vj93FnBTLMX0Pc9HpueV5o1ipX34dn/P3HZB9XK8ScbrE38B1VnIgylStnhVFO"
+ "Cj9s7qSVqI2L+xYHJRHsxaMumIRnmRuOqdXDfIo28EZAnFtQ/b9BziMGVvAW5+A8h8s2oazhSmK2"
+ "23ftV7uv98ScgE8fCd3PwT1kKJM83ThTYyBzokvMfPYCCvsonMV+kTWXhWcwjYTS4ukrpR452ZdW"
+ "l3aJqDnzobt5FK4T8OGciOj+1PxYFZyRmCuafm2Dx6o7Et2Tu/T5HYvhdY9jHyqtDl2PXH4CTnVi"
+ "gA1YOAArjPVmsZVwAM3Ml46uyXXhcsXwQ1X0Tv4D+PSa/id4UQ2cObOw8Cj1eW2GB8iJIZVqkZaU"
+ "XBexqgWYOIoxjqODSeoZKiBsTK3c+oOUBqBDueY1i55swE2o6dDt95FluX6iyr/q4w2wLt3upY1J"
+ "YL+TuvZxAKviuAczMS1bAAAAAAAAAAAAAA==");
byte[] signedData = Base64.decode(
"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"
+ "a+fEv4J8wQ8Xwvk0C8iMAAAAAAAA");
private boolean isSameAs(
byte[] a,
byte[] b)
{
if (a.length != b.length)
{
return false;
}
for (int i = 0; i != a.length; i++)
{
if (a[i] != b[i])
{
return false;
}
}
return true;
}
private TestResult compressionTest()
{
try
{
ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(compData));
ContentInfo info = ContentInfo.getInstance(aIn.readObject());
CompressedData data = CompressedData.getInstance(info.getContent());
data = new CompressedData(data.getCompressionAlgorithmIdentifier(), data.getEncapContentInfo());
info = new ContentInfo(CMSObjectIdentifiers.compressedData, data);
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
aOut.writeObject(info);
if (!isSameAs(bOut.toByteArray(), compData))
{
return new SimpleTestResult(false, getName() + ": CMS compression failed to re-encode");
}
return new SimpleTestResult(true, getName() + ": Okay");
}
catch (Exception e)
{
return new SimpleTestResult(false, getName() + ": CMS compression failed - " + e.toString(), e);
}
}
private TestResult envelopedTest()
{
try
{
ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(envDataKeyTrns));
ContentInfo info = ContentInfo.getInstance(aIn.readObject());
EnvelopedData envData = EnvelopedData.getInstance(info.getContent());
ASN1Set s = envData.getRecipientInfos();
if (s.size() != 1)
{
return new SimpleTestResult(false, getName() + ": CMS KeyTrans enveloped, wrong number of recipients");
}
RecipientInfo recip = RecipientInfo.getInstance(s.getObjectAt(0));
if (recip.getInfo() instanceof KeyTransRecipientInfo)
{
KeyTransRecipientInfo inf = KeyTransRecipientInfo.getInstance(recip.getInfo());
inf = new KeyTransRecipientInfo(inf.getRecipientIdentifier(), inf.getKeyEncryptionAlgorithm(), inf.getEncryptedKey());
s = new DERSet(new RecipientInfo(inf));
}
else
{
return new SimpleTestResult(false, getName() + ": CMS KeyTrans enveloped, wrong recipient type");
}
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
envData = new EnvelopedData(envData.getOriginatorInfo(), s, envData.getEncryptedContentInfo(), envData.getUnprotectedAttrs());
info = new ContentInfo(CMSObjectIdentifiers.envelopedData, envData);
aOut.writeObject(info);
if (!isSameAs(bOut.toByteArray(), envDataKeyTrns))
{
return new SimpleTestResult(false, getName() + ": CMS KeyTrans enveloped failed to re-encode");
}
aIn = new ASN1InputStream(new ByteArrayInputStream(envDataKEK));
info = ContentInfo.getInstance(aIn.readObject());
envData = EnvelopedData.getInstance(info.getContent());
s = envData.getRecipientInfos();
if (s.size() != 1)
{
return new SimpleTestResult(false, getName() + ": CMS KEK enveloped, wrong number of recipients");
}
recip = RecipientInfo.getInstance(s.getObjectAt(0));
if (recip.getInfo() instanceof KEKRecipientInfo)
{
KEKRecipientInfo inf = KEKRecipientInfo.getInstance(recip.getInfo());
inf = new KEKRecipientInfo(inf.getKekid(), inf.getKeyEncryptionAlgorithm(), inf.getEncryptedKey());
s = new DERSet(new RecipientInfo(inf));
}
else
{
return new SimpleTestResult(false, getName() + ": CMS KEK enveloped, wrong recipient type");
}
bOut = new ByteArrayOutputStream();
aOut = new ASN1OutputStream(bOut);
envData = new EnvelopedData(envData.getOriginatorInfo(), s, envData.getEncryptedContentInfo(), envData.getUnprotectedAttrs());
info = new ContentInfo(CMSObjectIdentifiers.envelopedData, envData);
aOut.writeObject(info);
if (!isSameAs(bOut.toByteArray(), envDataKEK))
{ System.out.println(new String(Base64.encode(bOut.toByteArray())));
return new SimpleTestResult(false, getName() + ": CMS KEK enveloped failed to re-encode");
}
ASN1StreamParser asn1In = new ASN1StreamParser(new ByteArrayInputStream(envDataNestedNDEF));
ContentInfoParser ci = new ContentInfoParser((ASN1SequenceParser)asn1In.readObject());
EnvelopedDataParser ed = new EnvelopedDataParser((ASN1SequenceParser)ci
.getContent(BERTags.SEQUENCE));
ed.getVersion();
ed.getOriginatorInfo();
ed.getRecipientInfos().toASN1Primitive();
EncryptedContentInfoParser eci = ed.getEncryptedContentInfo();
eci.getContentType();
eci.getContentEncryptionAlgorithm();
InputStream dataIn = ((ASN1OctetStringParser)eci.getEncryptedContent(BERTags.OCTET_STRING))
.getOctetStream();
Streams.drain(dataIn);
dataIn.close();
ASN1SetParser upa = ed.getUnprotectedAttrs();
if (upa != null)
{
upa.toASN1Primitive();
}
return new SimpleTestResult(true, getName() + ": Okay");
}
catch (Exception e)
{
return new SimpleTestResult(false, getName() + ": CMS enveloped failed - " + e.toString(), e);
}
}
private TestResult signedTest()
{
try
{
ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(signedData));
ContentInfo info = ContentInfo.getInstance(aIn.readObject());
SignedData sData = SignedData.getInstance(info.getContent());
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ASN1OutputStream aOut = new ASN1OutputStream(bOut);
sData = new SignedData(sData.getDigestAlgorithms(), sData.getEncapContentInfo(), sData.getCertificates(), sData.getCRLs(), sData.getSignerInfos());
info = new ContentInfo(CMSObjectIdentifiers.signedData, sData);
aOut.writeObject(info);
if (!isSameAs(bOut.toByteArray(), signedData))
{
return new SimpleTestResult(false, getName() + ": CMS signed failed to re-encode");
}
return new SimpleTestResult(true, getName() + ": Okay");
}
catch (Exception e)
{
return new SimpleTestResult(false, getName() + ": CMS signed failed - " + e.toString(), e);
}
}
public TestResult perform()
{
TestResult res = compressionTest();
if (!res.isSuccessful())
{
return res;
}
res = envelopedTest();
if (!res.isSuccessful())
{
return res;
}
return signedTest();
}
public String getName()
{
return "CMS";
}
public static void main(
String[] args)
{
CMSTest test = new CMSTest();
TestResult result = test.perform();
System.out.println(result);
}
}