package org.bouncycastle.cms;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1Set;
import org.bouncycastle.asn1.ASN1TaggedObject;
import org.bouncycastle.asn1.BEROctetStringGenerator;
import org.bouncycastle.asn1.BERSet;
import org.bouncycastle.asn1.DERNull;
import org.bouncycastle.asn1.DERSet;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.cms.CMSObjectIdentifiers;
import org.bouncycastle.asn1.cms.ContentInfo;
import org.bouncycastle.asn1.cms.OtherRevocationInfoFormat;
import org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers;
import org.bouncycastle.asn1.ocsp.OCSPResponse;
import org.bouncycastle.asn1.ocsp.OCSPResponseStatus;
import org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
import org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers;
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
import org.bouncycastle.cert.X509AttributeCertificateHolder;
import org.bouncycastle.cert.X509CRLHolder;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.operator.DigestCalculator;
import org.bouncycastle.util.Store;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.io.Streams;
import org.bouncycastle.util.io.TeeInputStream;
import org.bouncycastle.util.io.TeeOutputStream;
class CMSUtils
{
private static final Set<String> des = new HashSet<String>();
private static final Set mqvAlgs = new HashSet();
private static final Set ecAlgs = new HashSet();
private static final Set gostAlgs = new HashSet();
static
{
des.add("DES");
des.add("DESEDE");
des.add(OIWObjectIdentifiers.desCBC.getId());
des.add(PKCSObjectIdentifiers.des_EDE3_CBC.getId());
des.add(PKCSObjectIdentifiers.des_EDE3_CBC.getId());
des.add(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId());
mqvAlgs.add(X9ObjectIdentifiers.mqvSinglePass_sha1kdf_scheme);
mqvAlgs.add(SECObjectIdentifiers.mqvSinglePass_sha224kdf_scheme);
mqvAlgs.add(SECObjectIdentifiers.mqvSinglePass_sha256kdf_scheme);
mqvAlgs.add(SECObjectIdentifiers.mqvSinglePass_sha384kdf_scheme);
mqvAlgs.add(SECObjectIdentifiers.mqvSinglePass_sha512kdf_scheme);
ecAlgs.add(X9ObjectIdentifiers.dhSinglePass_cofactorDH_sha1kdf_scheme);
ecAlgs.add(X9ObjectIdentifiers.dhSinglePass_stdDH_sha1kdf_scheme);
ecAlgs.add(SECObjectIdentifiers.dhSinglePass_cofactorDH_sha224kdf_scheme);
ecAlgs.add(SECObjectIdentifiers.dhSinglePass_stdDH_sha224kdf_scheme);
ecAlgs.add(SECObjectIdentifiers.dhSinglePass_cofactorDH_sha256kdf_scheme);
ecAlgs.add(SECObjectIdentifiers.dhSinglePass_stdDH_sha256kdf_scheme);
ecAlgs.add(SECObjectIdentifiers.dhSinglePass_cofactorDH_sha384kdf_scheme);
ecAlgs.add(SECObjectIdentifiers.dhSinglePass_stdDH_sha384kdf_scheme);
ecAlgs.add(SECObjectIdentifiers.dhSinglePass_cofactorDH_sha512kdf_scheme);
ecAlgs.add(SECObjectIdentifiers.dhSinglePass_stdDH_sha512kdf_scheme);
gostAlgs.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_ESDH);
gostAlgs.add(RosstandartObjectIdentifiers.id_tc26_agreement_gost_3410_12_256);
gostAlgs.add(RosstandartObjectIdentifiers.id_tc26_agreement_gost_3410_12_512);
}
static boolean isMQV(ASN1ObjectIdentifier algorithm)
{
return mqvAlgs.contains(algorithm);
}
static boolean isEC(ASN1ObjectIdentifier algorithm)
{
return ecAlgs.contains(algorithm);
}
static boolean isGOST(ASN1ObjectIdentifier algorithm)
{
return gostAlgs.contains(algorithm);
}
static boolean isRFC2631(ASN1ObjectIdentifier algorithm)
{
return algorithm.equals(PKCSObjectIdentifiers.id_alg_ESDH) || algorithm.equals(PKCSObjectIdentifiers.id_alg_SSDH);
}
static boolean isDES(String algorithmID)
{
String name = Strings.toUpperCase(algorithmID);
return des.contains(name);
}
static boolean isEquivalent(AlgorithmIdentifier algId1, AlgorithmIdentifier algId2)
{
if (algId1 == null || algId2 == null)
{
return false;
}
if (!algId1.getAlgorithm().equals(algId2.getAlgorithm()))
{
return false;
}
ASN1Encodable params1 = algId1.getParameters();
ASN1Encodable params2 = algId2.getParameters();
if (params1 != null)
{
return params1.equals(params2) || (params1.equals(DERNull.INSTANCE) && params2 == null);
}
return params2 == null || params2.equals(DERNull.INSTANCE);
}
static ContentInfo readContentInfo(
byte[] input)
throws CMSException
{
return readContentInfo(new ASN1InputStream(input));
}
static ContentInfo readContentInfo(
InputStream input)
throws CMSException
{
return readContentInfo(new ASN1InputStream(input));
}
static List getCertificatesFromStore(Store certStore)
throws CMSException
{
List certs = new ArrayList();
try
{
for (Iterator it = certStore.getMatches(null).iterator(); it.hasNext(); )
{
X509CertificateHolder c = (X509CertificateHolder)it.next();
certs.add(c.toASN1Structure());
}
return certs;
}
catch (ClassCastException e)
{
throw new CMSException("error processing certs", e);
}
}
static List getAttributeCertificatesFromStore(Store attrStore)
throws CMSException
{
List certs = new ArrayList();
try
{
for (Iterator it = attrStore.getMatches(null).iterator(); it.hasNext(); )
{
X509AttributeCertificateHolder attrCert = (X509AttributeCertificateHolder)it.next();
certs.add(new DERTaggedObject(false, 2, attrCert.toASN1Structure()));
}
return certs;
}
catch (ClassCastException e)
{
throw new CMSException("error processing certs", e);
}
}
static List getCRLsFromStore(Store crlStore)
throws CMSException
{
List crls = new ArrayList();
try
{
for (Iterator it = crlStore.getMatches(null).iterator(); it.hasNext(); )
{
Object rev = it.next();
if (rev instanceof X509CRLHolder)
{
X509CRLHolder c = (X509CRLHolder)rev;
crls.add(c.toASN1Structure());
}
else if (rev instanceof OtherRevocationInfoFormat)
{
OtherRevocationInfoFormat infoFormat = OtherRevocationInfoFormat.getInstance(rev);
validateInfoFormat(infoFormat);
crls.add(new DERTaggedObject(false, 1, infoFormat));
}
else if (rev instanceof ASN1TaggedObject)
{
crls.add(rev);
}
}
return crls;
}
catch (ClassCastException e)
{
throw new CMSException("error processing certs", e);
}
}
private static void validateInfoFormat(OtherRevocationInfoFormat infoFormat)
{
if (CMSObjectIdentifiers.id_ri_ocsp_response.equals(infoFormat.getInfoFormat()))
{
OCSPResponse resp = OCSPResponse.getInstance(infoFormat.getInfo());
if (resp.getResponseStatus().getValue().intValue() != OCSPResponseStatus.SUCCESSFUL)
{
throw new IllegalArgumentException("cannot add unsuccessful OCSP response to CMS SignedData");
}
}
}
static Collection getOthersFromStore(ASN1ObjectIdentifier otherRevocationInfoFormat, Store otherRevocationInfos)
{
List others = new ArrayList();
for (Iterator it = otherRevocationInfos.getMatches(null).iterator(); it.hasNext(); )
{
ASN1Encodable info = (ASN1Encodable)it.next();
OtherRevocationInfoFormat infoFormat = new OtherRevocationInfoFormat(otherRevocationInfoFormat, info);
validateInfoFormat(infoFormat);
others.add(new DERTaggedObject(false, 1, infoFormat));
}
return others;
}
static ASN1Set createBerSetFromList(List derObjects)
{
ASN1EncodableVector v = new ASN1EncodableVector();
for (Iterator it = derObjects.iterator(); it.hasNext(); )
{
v.add((ASN1Encodable)it.next());
}
return new BERSet(v);
}
static ASN1Set createDerSetFromList(List derObjects)
{
ASN1EncodableVector v = new ASN1EncodableVector();
for (Iterator it = derObjects.iterator(); it.hasNext(); )
{
v.add((ASN1Encodable)it.next());
}
return new DERSet(v);
}
static OutputStream createBEROctetOutputStream(OutputStream s,
int tagNo, boolean isExplicit, int bufferSize)
throws IOException
{
BEROctetStringGenerator octGen = new BEROctetStringGenerator(s, tagNo, isExplicit);
if (bufferSize != 0)
{
return octGen.getOctetOutputStream(new byte[bufferSize]);
}
return octGen.getOctetOutputStream();
}
private static ContentInfo readContentInfo(
ASN1InputStream in)
throws CMSException
{
try
{
ContentInfo info = ContentInfo.getInstance(in.readObject());
if (info == null)
{
throw new CMSException("No content found.");
}
return info;
}
catch (IOException e)
{
throw new CMSException("IOException reading content.", e);
}
catch (ClassCastException e)
{
throw new CMSException("Malformed content.", e);
}
catch (IllegalArgumentException e)
{
throw new CMSException("Malformed content.", e);
}
}
public static byte[] streamToByteArray(
InputStream in)
throws IOException
{
return Streams.readAll(in);
}
public static byte[] streamToByteArray(
InputStream in,
int limit)
throws IOException
{
return Streams.readAllLimited(in, limit);
}
static InputStream attachDigestsToInputStream(Collection digests, InputStream s)
{
InputStream result = s;
Iterator it = digests.iterator();
while (it.hasNext())
{
DigestCalculator digest = (DigestCalculator)it.next();
result = new TeeInputStream(result, digest.getOutputStream());
}
return result;
}
static OutputStream attachSignersToOutputStream(Collection signers, OutputStream s)
{
OutputStream result = s;
Iterator it = signers.iterator();
while (it.hasNext())
{
SignerInfoGenerator signerGen = (SignerInfoGenerator)it.next();
result = getSafeTeeOutputStream(result, signerGen.getCalculatingOutputStream());
}
return result;
}
static OutputStream getSafeOutputStream(OutputStream s)
{
return s == null ? new NullOutputStream() : s;
}
static OutputStream getSafeTeeOutputStream(OutputStream s1,
OutputStream s2)
{
return s1 == null ? getSafeOutputStream(s2)
: s2 == null ? getSafeOutputStream(s1) : new TeeOutputStream(
s1, s2);
}
}