diff --git a/Crypto/src/asn1/cms/SignedData.cs b/Crypto/src/asn1/cms/SignedData.cs
new file mode 100644
index 000000000..40ed09f32
--- /dev/null
+++ b/Crypto/src/asn1/cms/SignedData.cs
@@ -0,0 +1,282 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Asn1;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+ /**
+ * a signed data object.
+ */
+ public class SignedData
+ : Asn1Encodable
+ {
+ private readonly DerInteger version;
+ private readonly Asn1Set digestAlgorithms;
+ private readonly ContentInfo contentInfo;
+ private readonly Asn1Set certificates;
+ private readonly Asn1Set crls;
+ private readonly Asn1Set signerInfos;
+ private readonly bool certsBer;
+ private readonly bool crlsBer;
+
+ public static SignedData GetInstance(
+ object obj)
+ {
+ if (obj is SignedData)
+ return (SignedData) obj;
+
+ if (obj is Asn1Sequence)
+ return new SignedData((Asn1Sequence) obj);
+
+ throw new ArgumentException("Unknown object in factory: " + obj.GetType().FullName, "obj");
+ }
+
+ public SignedData(
+ Asn1Set digestAlgorithms,
+ ContentInfo contentInfo,
+ Asn1Set certificates,
+ Asn1Set crls,
+ Asn1Set signerInfos)
+ {
+ this.version = CalculateVersion(contentInfo.ContentType, certificates, crls, signerInfos);
+ this.digestAlgorithms = digestAlgorithms;
+ this.contentInfo = contentInfo;
+ this.certificates = certificates;
+ this.crls = crls;
+ this.signerInfos = signerInfos;
+ this.crlsBer = crls is BerSet;
+ this.certsBer = certificates is BerSet;
+ }
+
+ // RFC3852, section 5.1:
+ // IF ((certificates is present) AND
+ // (any certificates with a type of other are present)) OR
+ // ((crls is present) AND
+ // (any crls with a type of other are present))
+ // THEN version MUST be 5
+ // ELSE
+ // IF (certificates is present) AND
+ // (any version 2 attribute certificates are present)
+ // THEN version MUST be 4
+ // ELSE
+ // IF ((certificates is present) AND
+ // (any version 1 attribute certificates are present)) OR
+ // (any SignerInfo structures are version 3) OR
+ // (encapContentInfo eContentType is other than id-data)
+ // THEN version MUST be 3
+ // ELSE version MUST be 1
+ //
+ private DerInteger CalculateVersion(
+ DerObjectIdentifier contentOid,
+ Asn1Set certs,
+ Asn1Set crls,
+ Asn1Set signerInfs)
+ {
+ bool otherCert = false;
+ bool otherCrl = false;
+ bool attrCertV1Found = false;
+ bool attrCertV2Found = false;
+
+ if (certs != null)
+ {
+ foreach (object obj in certs)
+ {
+ if (obj is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagged = (Asn1TaggedObject)obj;
+
+ if (tagged.TagNo == 1)
+ {
+ attrCertV1Found = true;
+ }
+ else if (tagged.TagNo == 2)
+ {
+ attrCertV2Found = true;
+ }
+ else if (tagged.TagNo == 3)
+ {
+ otherCert = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (otherCert)
+ {
+ return new DerInteger(5);
+ }
+
+ if (crls != null)
+ {
+ foreach (object obj in crls)
+ {
+ if (obj is Asn1TaggedObject)
+ {
+ otherCrl = true;
+ break;
+ }
+ }
+ }
+
+ if (otherCrl)
+ {
+ return new DerInteger(5);
+ }
+
+ if (attrCertV2Found)
+ {
+ return new DerInteger(4);
+ }
+
+ if (attrCertV1Found || !CmsObjectIdentifiers.Data.Equals(contentOid) || CheckForVersion3(signerInfs))
+ {
+ return new DerInteger(3);
+ }
+
+ return new DerInteger(1);
+ }
+
+ private bool CheckForVersion3(
+ Asn1Set signerInfs)
+ {
+ foreach (object obj in signerInfs)
+ {
+ SignerInfo s = SignerInfo.GetInstance(obj);
+
+ if (s.Version.Value.IntValue == 3)
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private SignedData(
+ Asn1Sequence seq)
+ {
+ IEnumerator e = seq.GetEnumerator();
+
+ e.MoveNext();
+ version = (DerInteger)e.Current;
+
+ e.MoveNext();
+ digestAlgorithms = ((Asn1Set)e.Current);
+
+ e.MoveNext();
+ contentInfo = ContentInfo.GetInstance(e.Current);
+
+ while (e.MoveNext())
+ {
+ Asn1Object o = (Asn1Object)e.Current;
+
+ //
+ // an interesting feature of SignedData is that there appear
+ // to be varying implementations...
+ // for the moment we ignore anything which doesn't fit.
+ //
+ if (o is Asn1TaggedObject)
+ {
+ Asn1TaggedObject tagged = (Asn1TaggedObject)o;
+
+ switch (tagged.TagNo)
+ {
+ case 0:
+ certsBer = tagged is BerTaggedObject;
+ certificates = Asn1Set.GetInstance(tagged, false);
+ break;
+ case 1:
+ crlsBer = tagged is BerTaggedObject;
+ crls = Asn1Set.GetInstance(tagged, false);
+ break;
+ default:
+ throw new ArgumentException("unknown tag value " + tagged.TagNo);
+ }
+ }
+ else
+ {
+ signerInfos = (Asn1Set) o;
+ }
+ }
+ }
+
+ public DerInteger Version
+ {
+ get { return version; }
+ }
+
+ public Asn1Set DigestAlgorithms
+ {
+ get { return digestAlgorithms; }
+ }
+
+ public ContentInfo EncapContentInfo
+ {
+ get { return contentInfo; }
+ }
+
+ public Asn1Set Certificates
+ {
+ get { return certificates; }
+ }
+
+ public Asn1Set CRLs
+ {
+ get { return crls; }
+ }
+
+ public Asn1Set SignerInfos
+ {
+ get { return signerInfos; }
+ }
+
+ /**
+ * Produce an object suitable for an Asn1OutputStream.
+ * <pre>
+ * SignedData ::= Sequence {
+ * version CMSVersion,
+ * digestAlgorithms DigestAlgorithmIdentifiers,
+ * encapContentInfo EncapsulatedContentInfo,
+ * certificates [0] IMPLICIT CertificateSet OPTIONAL,
+ * crls [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+ * signerInfos SignerInfos
+ * }
+ * </pre>
+ */
+ public override Asn1Object ToAsn1Object()
+ {
+ Asn1EncodableVector v = new Asn1EncodableVector(
+ version, digestAlgorithms, contentInfo);
+
+ if (certificates != null)
+ {
+ if (certsBer)
+ {
+ v.Add(new BerTaggedObject(false, 0, certificates));
+ }
+ else
+ {
+ v.Add(new DerTaggedObject(false, 0, certificates));
+ }
+ }
+
+ if (crls != null)
+ {
+ if (crlsBer)
+ {
+ v.Add(new BerTaggedObject(false, 1, crls));
+ }
+ else
+ {
+ v.Add(new DerTaggedObject(false, 1, crls));
+ }
+ }
+
+ v.Add(signerInfos);
+
+ return new BerSequence(v);
+ }
+ }
+}
|