summary refs log tree commit diff
path: root/crypto/src/asn1/cms/EnvelopedData.cs
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src/asn1/cms/EnvelopedData.cs')
-rw-r--r--crypto/src/asn1/cms/EnvelopedData.cs201
1 files changed, 122 insertions, 79 deletions
diff --git a/crypto/src/asn1/cms/EnvelopedData.cs b/crypto/src/asn1/cms/EnvelopedData.cs
index 1b88d7791..846062f1c 100644
--- a/crypto/src/asn1/cms/EnvelopedData.cs
+++ b/crypto/src/asn1/cms/EnvelopedData.cs
@@ -1,3 +1,5 @@
+using System;
+
 namespace Org.BouncyCastle.Asn1.Cms
 {
     public class EnvelopedData
@@ -17,85 +19,53 @@ namespace Org.BouncyCastle.Asn1.Cms
             return new EnvelopedData(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-        private DerInteger				version;
-        private OriginatorInfo			originatorInfo;
-        private Asn1Set					recipientInfos;
-        private EncryptedContentInfo	encryptedContentInfo;
-        private Asn1Set					unprotectedAttrs;
-
-        public EnvelopedData(
-            OriginatorInfo			originatorInfo,
-            Asn1Set					recipientInfos,
-            EncryptedContentInfo	encryptedContentInfo,
-            Asn1Set					unprotectedAttrs)
+        private readonly DerInteger m_version;
+        private readonly OriginatorInfo m_originatorInfo;
+        private readonly Asn1Set m_recipientInfos;
+        private readonly EncryptedContentInfo m_encryptedContentInfo;
+        private readonly Asn1Set m_unprotectedAttrs;
+
+        public EnvelopedData(OriginatorInfo originatorInfo, Asn1Set recipientInfos,
+            EncryptedContentInfo encryptedContentInfo, Asn1Set unprotectedAttrs)
         {
-            this.version = new DerInteger(CalculateVersion(originatorInfo, recipientInfos, unprotectedAttrs));
-            this.originatorInfo = originatorInfo;
-            this.recipientInfos = recipientInfos;
-            this.encryptedContentInfo = encryptedContentInfo;
-            this.unprotectedAttrs = unprotectedAttrs;
+            m_version = CalculateVersionField(originatorInfo, recipientInfos, unprotectedAttrs);
+            m_originatorInfo = originatorInfo;
+            m_recipientInfos = recipientInfos ?? throw new ArgumentNullException(nameof(recipientInfos));
+            m_encryptedContentInfo = encryptedContentInfo ?? throw new ArgumentNullException(nameof(encryptedContentInfo));
+            m_unprotectedAttrs = unprotectedAttrs;
         }
 
-        public EnvelopedData(
-            OriginatorInfo originatorInfo,
-            Asn1Set recipientInfos,
-            EncryptedContentInfo encryptedContentInfo,
-            Attributes unprotectedAttrs)
+        public EnvelopedData(OriginatorInfo originatorInfo, Asn1Set recipientInfos,
+            EncryptedContentInfo encryptedContentInfo, Attributes unprotectedAttrs)
+            : this(originatorInfo, recipientInfos, encryptedContentInfo, Asn1Set.GetInstance(unprotectedAttrs))
         {
-            this.version = new DerInteger(CalculateVersion(originatorInfo, recipientInfos, Asn1Set.GetInstance(unprotectedAttrs)));
-            this.originatorInfo = originatorInfo;
-            this.recipientInfos = recipientInfos;
-            this.encryptedContentInfo = encryptedContentInfo;
-            this.unprotectedAttrs = Asn1Set.GetInstance(unprotectedAttrs);
         }
 
         private EnvelopedData(Asn1Sequence seq)
         {
-            int index = 0;
-
-            version = (DerInteger) seq[index++];
-
-            object tmp = seq[index++];
-
-            if (tmp is Asn1TaggedObject taggedObject)
-            {
-                originatorInfo = OriginatorInfo.GetInstance(taggedObject, false);
-                tmp = seq[index++];
-            }
-
-            recipientInfos = Asn1Set.GetInstance(tmp);
-            encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[index++]);
-
-            if (seq.Count > index)
-            {
-                unprotectedAttrs = Asn1Set.GetInstance((Asn1TaggedObject)seq[index], false);
-            }
+            int count = seq.Count, pos = 0;
+            if (count < 3 || count > 5)
+                throw new ArgumentException("Bad sequence size: " + count, nameof(seq));
+
+            m_version = DerInteger.GetInstance(seq[pos++]);
+            m_originatorInfo = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 0, false, OriginatorInfo.GetInstance);
+            m_recipientInfos = Asn1Set.GetInstance(seq[pos++]);
+            m_encryptedContentInfo = EncryptedContentInfo.GetInstance(seq[pos++]);
+            m_unprotectedAttrs = Asn1Utilities.ReadOptionalContextTagged(seq, ref pos, 1, false, Asn1Set.GetInstance);
+
+            if (pos != count)
+                throw new ArgumentException("Unexpected elements in sequence", nameof(seq));
         }
 
-        public DerInteger Version
-        {
-            get { return version; }
-        }
+        public DerInteger Version => m_version;
 
-        public OriginatorInfo OriginatorInfo
-        {
-            get { return originatorInfo; }
-        }
+        public OriginatorInfo OriginatorInfo => m_originatorInfo;
 
-        public Asn1Set RecipientInfos
-        {
-            get { return recipientInfos; }
-        }
+        public Asn1Set RecipientInfos => m_recipientInfos;
 
-        public EncryptedContentInfo EncryptedContentInfo
-        {
-            get { return encryptedContentInfo; }
-        }
+        public EncryptedContentInfo EncryptedContentInfo => m_encryptedContentInfo;
 
-        public Asn1Set UnprotectedAttrs
-        {
-            get { return unprotectedAttrs; }
-        }
+        public Asn1Set UnprotectedAttrs => m_unprotectedAttrs;
 
         /**
          * Produce an object suitable for an Asn1OutputStream.
@@ -111,31 +81,104 @@ namespace Org.BouncyCastle.Asn1.Cms
          */
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector(version);
-            v.AddOptionalTagged(false, 0, originatorInfo);
-            v.Add(recipientInfos, encryptedContentInfo);
-            v.AddOptionalTagged(false, 1, unprotectedAttrs);
+            Asn1EncodableVector v = new Asn1EncodableVector(5);
+            v.Add(m_version);
+            v.AddOptionalTagged(false, 0, m_originatorInfo);
+            v.Add(m_recipientInfos, m_encryptedContentInfo);
+            v.AddOptionalTagged(false, 1, m_unprotectedAttrs);
             return new BerSequence(v);
         }
 
-        public static int CalculateVersion(OriginatorInfo originatorInfo, Asn1Set recipientInfos, Asn1Set unprotectedAttrs)
+        public static int CalculateVersion(OriginatorInfo originatorInfo, Asn1Set recipientInfos,
+            Asn1Set unprotectedAttrs)
         {
-            if (originatorInfo != null || unprotectedAttrs != null)
-            {
-                return 2;
-            }
+            return CalculateVersionField(originatorInfo, recipientInfos, unprotectedAttrs).IntValueExact;
+        }
 
-            foreach (object o in recipientInfos)
+        private static DerInteger CalculateVersionField(OriginatorInfo originatorInfo, Asn1Set recipientInfos,
+            Asn1Set unprotectedAttrs)
+        {
+            /*
+             * IF (originatorInfo is present) AND
+             *    ((any certificates with a type of other are present) OR
+             *    (any crls with a type of other are present))
+             * THEN version is 4
+             * ELSE
+             *    IF ((originatorInfo is present) AND
+             *       (any version 2 attribute certificates are present)) OR
+             *       (any RecipientInfo structures include pwri) OR
+             *       (any RecipientInfo structures include ori)
+             *    THEN version is 3
+             *    ELSE
+             *       IF (originatorInfo is absent) AND
+             *          (unprotectedAttrs is absent) AND
+             *          (all RecipientInfo structures are version 0)
+             *       THEN version is 0
+             *       ELSE version is 2
+             */
+
+            if (originatorInfo != null)
             {
-                RecipientInfo ri = RecipientInfo.GetInstance(o);
+                var crls = originatorInfo.Crls;
+                if (crls != null)
+                {
+                    foreach (var element in crls)
+                    {
+                        var tagged = Asn1TaggedObject.GetOptional(element);
+                        if (tagged != null)
+                        {
+                            // RevocationInfoChoice.other
+                            if (tagged.HasContextTag(1))
+                                return DerInteger.Four;
+                        }
+                    }
+                }
 
-                if (!ri.Version.HasValue(0))
+                var certs = originatorInfo.Certificates;
+                if (certs != null)
                 {
-                    return 2;
+                    bool anyV2AttrCerts = false;
+
+                    foreach (var element in certs)
+                    {
+                        var tagged = Asn1TaggedObject.GetOptional(element);
+                        if (tagged != null)
+                        {
+                            // CertificateChoices.other
+                            if (tagged.HasContextTag(3))
+                                return DerInteger.Four;
+
+                            // CertificateChoices.v2AttrCert
+                            anyV2AttrCerts = anyV2AttrCerts || tagged.HasContextTag(2);
+                        }
+                    }
+
+                    if (anyV2AttrCerts)
+                        return DerInteger.Three;
                 }
             }
 
-            return 0;
+            bool allV0Recipients = true;
+            foreach (var element in recipientInfos)
+            {
+                var recipientInfo = RecipientInfo.GetInstance(element);
+
+                // (any RecipientInfo structures include pwri) OR
+                // (any RecipientInfo structures include ori)
+                if (recipientInfo.IsPasswordOrOther())
+                    return DerInteger.Three;
+
+                // (all RecipientInfo structures are version 0)
+                // -- 'kari.version' is always 3
+                // -- 'kekri.version' is always 4
+                // -- 'pwri' and 'ori' have already been excluded
+                allV0Recipients = allV0Recipients && recipientInfo.IsKeyTransV0();
+            }
+
+            if (originatorInfo == null && unprotectedAttrs == null && allV0Recipients)
+                return DerInteger.Zero;
+
+            return DerInteger.Two;
         }
     }
 }