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