Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c76ac56

Browse files
krwqjozkee
authored andcommitted
Merged PR 30724: [6.0] Apply iteration work limits to X509 certificate loading
Block password-less PKCS12 blobs on X509 certificate loadings/imports and prevent AIA fetching of non-cert types.
1 parent 320aeb7 commit c76ac56

File tree

45 files changed

+2561
-159
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2561
-159
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
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+
4+
using System.Diagnostics;
5+
6+
namespace System.Security.Cryptography
7+
{
8+
// Places KDF work limits on the current thread.
9+
internal static class KdfWorkLimiter
10+
{
11+
[ThreadStatic]
12+
private static State? t_state;
13+
14+
// Entry point: sets the iteration limit to a new value.
15+
internal static void SetIterationLimit(ulong workLimit)
16+
{
17+
Debug.Assert(t_state == null, "This method is not intended to be called recursively.");
18+
State state = new State();
19+
state.RemainingAllowedWork = workLimit;
20+
t_state = state;
21+
}
22+
23+
internal static bool WasWorkLimitExceeded()
24+
{
25+
Debug.Assert(t_state != null, "This method should only be called within a protected block.");
26+
return t_state.WorkLimitWasExceeded;
27+
}
28+
29+
// Removes any iteration limit on the current thread.
30+
internal static void ResetIterationLimit()
31+
{
32+
t_state = null;
33+
}
34+
35+
// Records that we're about to perform some amount of work.
36+
// Overflows if the work count is exceeded.
37+
internal static void RecordIterations(int workCount)
38+
{
39+
RecordIterations((long)workCount);
40+
}
41+
42+
// Records that we're about to perform some amount of work.
43+
// Overflows if the work count is exceeded.
44+
internal static void RecordIterations(long workCount)
45+
{
46+
State? state = t_state;
47+
if (state == null)
48+
{
49+
return;
50+
}
51+
52+
bool success = false;
53+
54+
if (workCount < 0)
55+
{
56+
throw new CryptographicException();
57+
}
58+
59+
try
60+
{
61+
if (!state.WorkLimitWasExceeded)
62+
{
63+
state.RemainingAllowedWork = checked(state.RemainingAllowedWork - (ulong)workCount);
64+
success = true;
65+
}
66+
}
67+
finally
68+
{
69+
// If for any reason we failed, mark the thread as "no further work allowed" and
70+
// normalize to CryptographicException.
71+
if (!success)
72+
{
73+
state.RemainingAllowedWork = 0;
74+
state.WorkLimitWasExceeded = true;
75+
throw new CryptographicException();
76+
}
77+
}
78+
}
79+
80+
private sealed class State
81+
{
82+
internal ulong RemainingAllowedWork;
83+
internal bool WorkLimitWasExceeded;
84+
}
85+
}
86+
}

src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ internal static unsafe int Encrypt(
377377
Debug.Assert(pwdTmpBytes!.Length == 0);
378378
}
379379

380+
KdfWorkLimiter.RecordIterations(iterationCount);
380381
using (var pbkdf2 = new Rfc2898DeriveBytes(pwdTmpBytes, salt.ToArray(), iterationCount, prf))
381382
{
382383
derivedKey = pbkdf2.GetBytes(keySizeBytes);

src/libraries/Common/src/System/Security/Cryptography/Pkcs12Kdf.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ private static void Derive(
147147
I = IRented.AsSpan(0, ILen);
148148
}
149149

150+
KdfWorkLimiter.RecordIterations(iterationCount);
150151
IncrementalHash hash = IncrementalHash.CreateHash(hashAlgorithm);
151152

152153
try

src/libraries/Common/tests/System/Net/Http/TestHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ public static X509Certificate2 CreateServerSelfSignedCertificate(string name = "
157157
X509Certificate2 cert = req.CreateSelfSigned(start, end);
158158
if (PlatformDetection.IsWindows)
159159
{
160-
cert = new X509Certificate2(cert.Export(X509ContentType.Pfx));
160+
cert = new X509Certificate2(cert.Export(X509ContentType.Pfx), (string?)null);
161161
}
162162

163163
return cert;

src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Threading;
88
using System.Threading.Tasks;
99
using System.Web;
10+
using Xunit;
1011

1112
namespace System.Security.Cryptography.X509Certificates.Tests.Common
1213
{
@@ -29,6 +30,7 @@ private readonly Dictionary<string, CertificateAuthority> _crlPaths
2930
public string UriPrefix { get; }
3031

3132
public bool RespondEmpty { get; set; }
33+
public AiaResponseKind AiaResponseKind { get; set; }
3234

3335
public TimeSpan ResponseDelay { get; set; }
3436
public DelayedActionsFlag DelayedActions { get; set; }
@@ -181,13 +183,13 @@ private void HandleRequest(HttpListenerContext context, ref bool responded)
181183
Thread.Sleep(ResponseDelay);
182184
}
183185

184-
byte[] certData = RespondEmpty ? Array.Empty<byte>() : authority.GetCertData();
186+
byte[] certData = RespondEmpty ? Array.Empty<byte>() : GetCertDataForAiaResponseKind(AiaResponseKind, authority);
185187

186188
responded = true;
187189
context.Response.StatusCode = 200;
188-
context.Response.ContentType = "application/pkix-cert";
190+
context.Response.ContentType = AiaResponseKindToContentType(AiaResponseKind);
189191
context.Response.Close(certData, willBlock: true);
190-
Trace($"Responded with {certData.Length}-byte certificate from {authority.SubjectName}.");
192+
Trace($"Responded with {certData.Length}-byte {AiaResponseKind} from {authority.SubjectName}.");
191193
return;
192194
}
193195

@@ -295,6 +297,41 @@ private static HttpListener OpenListener(out string uriPrefix)
295297
}
296298
}
297299

300+
private static string AiaResponseKindToContentType(AiaResponseKind kind)
301+
{
302+
if (kind == AiaResponseKind.Cert)
303+
{
304+
return "application/pkix-cert";
305+
}
306+
else if (kind == AiaResponseKind.Pkcs12)
307+
{
308+
return "application/x-pkcs12";
309+
}
310+
else
311+
{
312+
Assert.True(false, $"Unknown value AiaResponseKind.`{kind}`.");
313+
return null;
314+
}
315+
}
316+
317+
private static byte[] GetCertDataForAiaResponseKind(AiaResponseKind kind, CertificateAuthority authority)
318+
{
319+
if (kind == AiaResponseKind.Cert)
320+
{
321+
return authority.GetCertData();
322+
}
323+
else if (kind == AiaResponseKind.Pkcs12)
324+
{
325+
using X509Certificate2 cert = new X509Certificate2(authority.GetCertData());
326+
return cert.Export(X509ContentType.Pkcs12);
327+
}
328+
else
329+
{
330+
Assert.True(false, $"Unknown value AiaResponseKind.`{kind}`.");
331+
return null;
332+
}
333+
}
334+
298335
private static bool TryGetOcspRequestBytes(HttpListenerRequest request, string prefix, out byte[] requestBytes)
299336
{
300337
requestBytes = null;
@@ -425,4 +462,10 @@ public enum DelayedActionsFlag : byte
425462
Aia = 0b100,
426463
All = 0b11111111
427464
}
465+
466+
public enum AiaResponseKind
467+
{
468+
Cert = 0,
469+
Pkcs12 = 1,
470+
}
428471
}

src/libraries/System.Net.Security/tests/FunctionalTests/SslStreamStreamToStreamTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public static IEnumerable<object[]> SslStream_StreamToStream_Authentication_Succ
6363
using (X509Certificate2 clientCert = Configuration.Certificates.GetClientCertificate())
6464
{
6565
yield return new object[] { new X509Certificate2(serverCert), new X509Certificate2(clientCert) };
66-
yield return new object[] { new X509Certificate(serverCert.Export(X509ContentType.Pfx)), new X509Certificate(clientCert.Export(X509ContentType.Pfx)) };
66+
yield return new object[] { new X509Certificate(serverCert.Export(X509ContentType.Pfx), (string)null, X509KeyStorageFlags.DefaultKeySet), new X509Certificate(clientCert.Export(X509ContentType.Pfx), (string)null, X509KeyStorageFlags.DefaultKeySet) };
6767
}
6868
}
6969

src/libraries/System.Net.Security/tests/FunctionalTests/TestHelper.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ internal static (X509Certificate2 certificate, X509Certificate2Collection) Gener
169169
if (PlatformDetection.IsWindows)
170170
{
171171
X509Certificate2 ephemeral = endEntity;
172-
endEntity = new X509Certificate2(endEntity.Export(X509ContentType.Pfx));
172+
endEntity = new X509Certificate2(endEntity.Export(X509ContentType.Pfx), (string)null, X509KeyStorageFlags.DefaultKeySet);
173173
ephemeral.Dispose();
174174
}
175175

src/libraries/System.Security.Cryptography.Algorithms/src/System.Security.Cryptography.Algorithms.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Project Sdk="Microsoft.NET.Sdk">
1+
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
33
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
44
<DefineConstants>$(DefineConstants);INTERNAL_ASYMMETRIC_IMPLEMENTATIONS</DefineConstants>
@@ -132,6 +132,8 @@
132132
Link="Common\System\Security\Cryptography\KeyFormatHelper.cs" />
133133
<Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.Encrypted.cs"
134134
Link="Common\System\Security\Cryptography\KeyFormatHelper.Encrypted.cs" />
135+
<Compile Include="$(CommonPath)System\Security\Cryptography\KdfWorkLimiter.cs"
136+
Link="Common\System\Security\Cryptography\KdfWorkLimiter.cs" />
135137
<Compile Include="$(CommonPath)System\Security\Cryptography\KeySizeHelpers.cs"
136138
Link="Common\System\Security\Cryptography\KeySizeHelpers.cs" />
137139
<Compile Include="$(CommonPath)System\Security\Cryptography\Oids.cs"

src/libraries/System.Security.Cryptography.Cng/src/System.Security.Cryptography.Cng.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@
212212
Link="Common\System\Security\Cryptography\KeyFormatHelper.cs" />
213213
<Compile Include="$(CommonPath)System\Security\Cryptography\KeyFormatHelper.Encrypted.cs"
214214
Link="Common\System\Security\Cryptography\KeyFormatHelper.Encrypted.cs" />
215+
<Compile Include="$(CommonPath)System\Security\Cryptography\KdfWorkLimiter.cs"
216+
Link="Common\System\Security\Cryptography\KdfWorkLimiter.cs" />
215217
<Compile Include="$(CommonPath)System\Security\Cryptography\KeySizeHelpers.cs"
216218
Link="Common\System\Security\Cryptography\KeySizeHelpers.cs" />
217219
<Compile Include="$(CommonPath)System\Security\Cryptography\Oids.cs"

src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent);netcoreapp3.1-windows;netcoreapp3.1;netstandard2.1-windows;netstandard2.1;netstandard2.0-windows;netstandard2.0;net461-windows</TargetFrameworks>
88
<IsPackable>true</IsPackable>
99
<!-- If you enable GeneratePackageOnBuild for this package and bump ServicingVersion, make sure to also bump ServicingVersion in Microsoft.Windows.Compatibility.csproj once for the next release. -->
10-
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
11-
<ServicingVersion>2</ServicingVersion>
10+
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
11+
<ServicingVersion>3</ServicingVersion>
1212
<PackageDescription>Provides support for PKCS and CMS algorithms.
1313

1414
Commonly Used Types:
@@ -613,6 +613,8 @@ System.Security.Cryptography.Pkcs.EnvelopedCms</PackageDescription>
613613
<Link>Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml.cs</Link>
614614
<DependentUpon>Common\System\Security\Cryptography\Asn1\Pkcs7\EncryptedDataAsn.xml</DependentUpon>
615615
</Compile>
616+
<Compile Include="$(CommonPath)System\Security\Cryptography\KdfWorkLimiter.cs"
617+
Link="Common\System\Security\Cryptography\KdfWorkLimiter.cs" />
616618
<Compile Include="$(CommonPath)System\Security\Cryptography\PasswordBasedEncryption.cs"
617619
Link="Common\System\Security\Cryptography\PasswordBasedEncryption.cs" />
618620
<Compile Include="$(CommonPath)System\Security\Cryptography\Pkcs12Kdf.cs"
@@ -650,7 +652,7 @@ System.Security.Cryptography.Pkcs.EnvelopedCms</PackageDescription>
650652
<ProjectReference Include="$(LibrariesProjectRoot)System.Formats.Asn1\src\System.Formats.Asn1.csproj" />
651653
</ItemGroup>
652654
<ItemGroup Condition="$(TargetFramework.StartsWith('netstandard2.0'))">
653-
<PackageReference Include="System.Buffers" Version="$(SystemBuffersVersion)" />
655+
<PackageReference Include="System.Buffers" Version="$(SystemBuffersVersion)" />
654656
<PackageReference Include="System.Memory" Version="$(SystemMemoryVersion)" />
655657
<!-- S.R.C.Unsafe isn't a primary but transitive dependency and this P2P makes sure that the live version is used. -->
656658
<ProjectReference Include="$(LibrariesProjectRoot)System.Runtime.CompilerServices.Unsafe\src\System.Runtime.CompilerServices.Unsafe.ilproj" PrivateAssets="all" />

0 commit comments

Comments
 (0)