summary refs log tree commit diff
path: root/crypto/src/asn1/DerSet.cs
blob: d89285d9e57a06536bc6fb09c05fdca7c36f5d3d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
using System;

namespace Org.BouncyCastle.Asn1
{
	/**
	 * A Der encoded set object
	 */
	public class DerSet
		: Asn1Set
	{
		public static readonly DerSet Empty = new DerSet();

		public static DerSet FromVector(Asn1EncodableVector elementVector)
		{
            return elementVector.Count < 1 ? Empty : new DerSet(elementVector);
		}

        private int m_contentsLengthDer = -1;

        /**
		 * create an empty set
		 */
        public DerSet()
			: base()
		{
		}

		/**
		 * @param obj - a single object that makes up the set.
		 */
		public DerSet(Asn1Encodable element)
			: base(element)
		{
		}

        public DerSet(params Asn1Encodable[] elements)
            : base(elements, true)
        {
        }

        internal DerSet(Asn1Encodable[] elements, bool doSort)
			: base(elements, doSort)
		{
		}

		/**
		 * @param v - a vector of objects making up the set.
		 */
		public DerSet(Asn1EncodableVector elementVector)
			: base(elementVector, true)
		{
		}

		internal DerSet(Asn1EncodableVector	elementVector, bool doSort)
			: base(elementVector, doSort)
		{
		}

        internal DerSet(bool isSorted, Asn1Encodable[] elements)
            : base(isSorted, elements)
        {
        }

        internal override int EncodedLength(int encoding, bool withID)
        {
            encoding = Asn1OutputStream.EncodingDer;

            int count = elements.Length;
            int contentsLength = 0;

            for (int i = 0; i < count; ++i)
            {
                Asn1Object asn1Object = elements[i].ToAsn1Object();
                contentsLength += asn1Object.EncodedLength(encoding, true);
            }

            return Asn1OutputStream.GetLengthOfEncodingDL(withID, contentsLength);
        }

        /*
		 * A note on the implementation:
		 * <p>
		 * As Der requires the constructed, definite-length model to
		 * be used for structured types, this varies slightly from the
		 * ASN.1 descriptions given. Rather than just outputing Set,
		 * we also have to specify Constructed, and the objects length.
		 */
        internal override void Encode(Asn1OutputStream asn1Out, bool withID)
        {
            if (Count < 1)
            {
                asn1Out.WriteEncodingDL(withID, Asn1Tags.Constructed | Asn1Tags.Set, Asn1OctetString.EmptyOctets);
                return;
            }

            Asn1Encodable[] elements = this.elements;
            if (!isSorted)
            {
                elements = Sort((Asn1Encodable[])elements.Clone());
            }

            asn1Out = asn1Out.GetDerSubStream();

            asn1Out.WriteIdentifier(withID, Asn1Tags.Constructed | Asn1Tags.Set);

            int count = elements.Length;
            if (m_contentsLengthDer >= 0 || count > 16)
            {
                asn1Out.WriteDL(GetContentsLengthDer());

                for (int i = 0; i < count; ++i)
                {
                    Asn1Object asn1Object = elements[i].ToAsn1Object();
                    asn1Object.Encode(asn1Out, true);
                }
            }
            else
            {
                int contentsLength = 0;

                Asn1Object[] asn1Objects = new Asn1Object[count];
                for (int i = 0; i < count; ++i)
                {
                    Asn1Object asn1Object = elements[i].ToAsn1Object();
                    asn1Objects[i] = asn1Object;
                    contentsLength += asn1Object.EncodedLength(asn1Out.Encoding, true);
                }

                this.m_contentsLengthDer = contentsLength;
                asn1Out.WriteDL(contentsLength);

                for (int i = 0; i < count; ++i)
                {
                    asn1Objects[i].Encode(asn1Out, true);
                }
            }
        }

        private int GetContentsLengthDer()
        {
            if (m_contentsLengthDer < 0)
            {
                m_contentsLengthDer = CalculateContentsLength(Asn1OutputStream.EncodingDer);
            }
            return m_contentsLengthDer;
        }
    }
}