1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Collections;
6 using System.Diagnostics;
7 using System.Security.Cryptography.Pkcs.Asn1;
8 using System.Security.Cryptography.Xml;
9 
10 namespace System.Security.Cryptography.Pkcs
11 {
12     public sealed class SignerInfoCollection : ICollection, IEnumerable
13     {
14         private readonly SignerInfo[] _signerInfos;
15 
SignerInfoCollection()16         internal SignerInfoCollection()
17         {
18             _signerInfos = Array.Empty<SignerInfo>();
19         }
20 
SignerInfoCollection(SignerInfo[] signerInfos)21         internal SignerInfoCollection(SignerInfo[] signerInfos)
22         {
23             Debug.Assert(signerInfos != null);
24 
25             _signerInfos = signerInfos;
26         }
27 
SignerInfoCollection(SignerInfoAsn[] signedDataSignerInfos, SignedCms ownerDocument)28         internal SignerInfoCollection(SignerInfoAsn[] signedDataSignerInfos, SignedCms ownerDocument)
29         {
30             Debug.Assert(signedDataSignerInfos != null);
31 
32             _signerInfos = new SignerInfo[signedDataSignerInfos.Length];
33 
34             for (int i = 0; i < signedDataSignerInfos.Length; i++)
35             {
36                 _signerInfos[i] = new SignerInfo(ref signedDataSignerInfos[i], ownerDocument);
37             }
38         }
39 
40         public SignerInfo this[int index] => _signerInfos[index];
41 
42         public int Count => _signerInfos.Length;
43 
GetEnumerator()44         public SignerInfoEnumerator GetEnumerator() => new SignerInfoEnumerator(this);
IEnumerable.GetEnumerator()45         IEnumerator IEnumerable.GetEnumerator() => new SignerInfoEnumerator(this);
46 
CopyTo(Array array, int index)47         public void CopyTo(Array array, int index)
48         {
49             if (array == null)
50                 throw new ArgumentNullException(nameof(array));
51             if (array.Rank != 1)
52                 throw new ArgumentException(SR.Arg_RankMultiDimNotSupported, nameof(array));
53             if (index < 0 || index >= array.Length)
54                 throw new ArgumentOutOfRangeException(nameof(index),SR.ArgumentOutOfRange_Index);
55             if (index + Count > array.Length)
56                 throw new ArgumentException(SR.Argument_InvalidOffLen);
57 
58             for (int i = 0; i < Count; i++)
59             {
60                 array.SetValue(this[i], index + i);
61             }
62         }
63 
64         // The collections are usually small (usually Count == 1) so there's not value in repeating
65         // the validation of the Array overload to defer to a faster copy routine.
CopyTo(SignerInfo[] array, int index)66         public void CopyTo(SignerInfo[] array, int index) => ((ICollection)this).CopyTo(array, index);
67 
68         public bool IsSynchronized => false;
69         public object SyncRoot => this;
70 
FindIndexForSigner(SignerInfo signer)71         internal int FindIndexForSigner(SignerInfo signer)
72         {
73             Debug.Assert(signer != null);
74             SubjectIdentifier id = signer.SignerIdentifier;
75             X509IssuerSerial issuerSerial = default;
76 
77             if (id.Type == SubjectIdentifierType.IssuerAndSerialNumber)
78             {
79                 issuerSerial = (X509IssuerSerial)id.Value;
80             }
81 
82             for (int i = 0; i < _signerInfos.Length; i++)
83             {
84                 SignerInfo current = _signerInfos[i];
85                 SubjectIdentifier currentId = current.SignerIdentifier;
86 
87                 if (currentId.Type != id.Type)
88                 {
89                     continue;
90                 }
91 
92                 bool equal = false;
93 
94                 switch (id.Type)
95                 {
96                     case SubjectIdentifierType.IssuerAndSerialNumber:
97                     {
98                         X509IssuerSerial currentIssuerSerial = (X509IssuerSerial)currentId.Value;
99 
100                         if (currentIssuerSerial.IssuerName == issuerSerial.IssuerName &&
101                             currentIssuerSerial.SerialNumber == issuerSerial.SerialNumber)
102                         {
103                             equal = true;
104                         }
105 
106                         break;
107                     }
108                     case SubjectIdentifierType.SubjectKeyIdentifier:
109                         if ((string)id.Value == (string)currentId.Value)
110                         {
111                             equal = true;
112                         }
113 
114                         break;
115                     case SubjectIdentifierType.NoSignature:
116                         equal = true;
117                         break;
118                     default:
119                         Debug.Fail($"No match logic for SubjectIdentifierType {id.Type}");
120                         throw new CryptographicException();
121                 }
122 
123                 if (equal)
124                 {
125                     return i;
126                 }
127             }
128 
129             return -1;
130         }
131     }
132 }
133