Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 02a00bd

Browse files
committed
Merge pull request #2824 from justinvp/x509_collections
Cleanup and harden X509Certificate collections
2 parents d95a76c + dd524b0 commit 02a00bd

File tree

5 files changed

+809
-180
lines changed

5 files changed

+809
-180
lines changed

src/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/X509Certificate2Collection.cs

Lines changed: 19 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
11
// Copyright (c) Microsoft. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4-
using System;
5-
using System.IO;
6-
using System.Text;
7-
using System.Diagnostics;
8-
using System.Globalization;
9-
using System.Runtime.InteropServices;
10-
11-
using Internal.Cryptography;
124
using Internal.Cryptography.Pal;
135

146
namespace System.Security.Cryptography.X509Certificates
@@ -38,13 +30,11 @@ public X509Certificate2Collection(X509Certificate2Collection certificates)
3830
{
3931
get
4032
{
41-
return (X509Certificate2)(List[index]);
33+
return (X509Certificate2)(base[index]);
4234
}
4335
set
4436
{
45-
if (value == null)
46-
throw new ArgumentNullException("value");
47-
List[index] = value;
37+
base[index] = value;
4838
}
4939
}
5040

@@ -53,7 +43,7 @@ public int Add(X509Certificate2 certificate)
5343
if (certificate == null)
5444
throw new ArgumentNullException("certificate");
5545

56-
return List.Add(certificate);
46+
return base.Add(certificate);
5747
}
5848

5949
public void AddRange(X509Certificate2[] certificates)
@@ -87,10 +77,9 @@ public void AddRange(X509Certificate2Collection certificates)
8777
int i = 0;
8878
try
8979
{
90-
foreach (X509Certificate2 certificate in certificates)
80+
for (; i < certificates.Count; i++)
9181
{
92-
Add(certificate);
93-
i++;
82+
Add(certificates[i]);
9483
}
9584
}
9685
catch
@@ -105,26 +94,27 @@ public void AddRange(X509Certificate2Collection certificates)
10594

10695
public bool Contains(X509Certificate2 certificate)
10796
{
108-
if (certificate == null)
109-
throw new ArgumentNullException("certificate");
97+
// This method used to throw ArgumentNullException, but it has been deliberately changed
98+
// to no longer throw to match the behavior of X509CertificateCollection.Contains and the
99+
// IList.Contains implementation, which do not throw.
110100

111-
return List.Contains(certificate);
101+
return base.Contains(certificate);
112102
}
113103

114104
public byte[] Export(X509ContentType contentType)
115105
{
116106
return Export(contentType, password: null);
117107
}
118108

119-
public byte[] Export(X509ContentType contentType, String password)
109+
public byte[] Export(X509ContentType contentType, string password)
120110
{
121111
using (IStorePal storePal = StorePal.LinkFromCertificateCollection(this))
122112
{
123113
return storePal.Export(contentType, password);
124114
}
125115
}
126116

127-
public X509Certificate2Collection Find(X509FindType findType, Object findValue, bool validOnly)
117+
public X509Certificate2Collection Find(X509FindType findType, object findValue, bool validOnly)
128118
{
129119
if (findValue == null)
130120
throw new ArgumentNullException("findValue");
@@ -139,16 +129,15 @@ public X509Certificate2Collection Find(X509FindType findType, Object findValue,
139129

140130
public new X509Certificate2Enumerator GetEnumerator()
141131
{
142-
X509CertificateEnumerator baseEnumerator = base.GetEnumerator();
143-
return new X509Certificate2Enumerator(baseEnumerator);
132+
return new X509Certificate2Enumerator(this);
144133
}
145134

146135
public void Import(byte[] rawData)
147136
{
148137
Import(rawData, password: null, keyStorageFlags: X509KeyStorageFlags.DefaultKeySet);
149138
}
150139

151-
public void Import(byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)
140+
public void Import(byte[] rawData, string password, X509KeyStorageFlags keyStorageFlags)
152141
{
153142
if (rawData == null)
154143
throw new ArgumentNullException("rawData");
@@ -159,12 +148,12 @@ public void Import(byte[] rawData, String password, X509KeyStorageFlags keyStora
159148
}
160149
}
161150

162-
public void Import(String fileName)
151+
public void Import(string fileName)
163152
{
164153
Import(fileName, password: null, keyStorageFlags: X509KeyStorageFlags.DefaultKeySet);
165154
}
166155

167-
public void Import(String fileName, String password, X509KeyStorageFlags keyStorageFlags)
156+
public void Import(string fileName, string password, X509KeyStorageFlags keyStorageFlags)
168157
{
169158
if (fileName == null)
170159
throw new ArgumentNullException("fileName");
@@ -180,15 +169,15 @@ public void Insert(int index, X509Certificate2 certificate)
180169
if (certificate == null)
181170
throw new ArgumentNullException("certificate");
182171

183-
List.Insert(index, certificate);
172+
base.Insert(index, certificate);
184173
}
185174

186175
public void Remove(X509Certificate2 certificate)
187176
{
188177
if (certificate == null)
189178
throw new ArgumentNullException("certificate");
190179

191-
List.Remove(certificate);
180+
base.Remove(certificate);
192181
}
193182

194183
public void RemoveRange(X509Certificate2[] certificates)
@@ -222,10 +211,9 @@ public void RemoveRange(X509Certificate2Collection certificates)
222211
int i = 0;
223212
try
224213
{
225-
foreach (X509Certificate2 certificate in certificates)
214+
for (; i < certificates.Count; i++)
226215
{
227-
Remove(certificate);
228-
i++;
216+
Remove(certificates[i]);
229217
}
230218
}
231219
catch
@@ -239,4 +227,3 @@ public void RemoveRange(X509Certificate2Collection certificates)
239227
}
240228
}
241229
}
242-
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,56 @@
11
// Copyright (c) Microsoft. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

4-
using System;
5-
using System.IO;
6-
using System.Text;
74
using System.Diagnostics;
85
using System.Collections;
9-
using System.Globalization;
10-
using System.Runtime.InteropServices;
11-
12-
using Internal.Cryptography;
6+
using System.Collections.Generic;
137

148
namespace System.Security.Cryptography.X509Certificates
159
{
1610
public sealed class X509Certificate2Enumerator : IEnumerator
1711
{
18-
internal X509Certificate2Enumerator(IEnumerator baseEnumerator)
12+
// This is a mutable struct enumerator, so don't mark it as readonly.
13+
private List<X509Certificate>.Enumerator _enumerator;
14+
15+
internal X509Certificate2Enumerator(X509Certificate2Collection collection)
1916
{
20-
_baseEnumerator = baseEnumerator;
17+
Debug.Assert(collection != null);
18+
19+
collection.GetEnumerator(out _enumerator);
2120
}
2221

2322
public X509Certificate2 Current
2423
{
25-
get
26-
{
27-
return (X509Certificate2)(_baseEnumerator.Current);
28-
}
24+
// Call the struct enumerator's IEnumerator.Current implementation, which has the
25+
// behavior we want of throwing InvalidOperationException when the enumerator
26+
// hasn't been started or has ended, without boxing.
27+
get { return (X509Certificate2)(EnumeratorHelper.GetCurrent(ref _enumerator)); }
2928
}
3029

31-
Object IEnumerator.Current
30+
object IEnumerator.Current
3231
{
33-
get
34-
{
35-
return _baseEnumerator.Current;
36-
}
32+
get { return Current; }
3733
}
3834

3935
public bool MoveNext()
4036
{
41-
return _baseEnumerator.MoveNext();
37+
return _enumerator.MoveNext();
4238
}
4339

4440
bool IEnumerator.MoveNext()
4541
{
46-
return _baseEnumerator.MoveNext();
42+
return MoveNext();
4743
}
4844

4945
public void Reset()
5046
{
51-
_baseEnumerator.Reset();
47+
// Call Reset on the struct enumerator without boxing.
48+
EnumeratorHelper.Reset(ref _enumerator);
5249
}
5350

5451
void IEnumerator.Reset()
5552
{
56-
_baseEnumerator.Reset();
53+
Reset();
5754
}
58-
59-
private IEnumerator _baseEnumerator;
6055
}
6156
}
62-

0 commit comments

Comments
 (0)