Skip to content

Commit 388dd6c

Browse files
wfurtbartonjs
andauthored
Add CertificateChainPolicy to ssl options
Co-authored-by: Jeremy Barton <jbarton@microsoft.com>
1 parent 5615b56 commit 388dd6c

15 files changed

+175
-46
lines changed

src/libraries/System.Net.Security/ref/System.Net.Security.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ public SslClientAuthenticationOptions() { }
207207
public System.Net.Security.LocalCertificateSelectionCallback? LocalCertificateSelectionCallback { get { throw null; } set { } }
208208
public System.Net.Security.RemoteCertificateValidationCallback? RemoteCertificateValidationCallback { get { throw null; } set { } }
209209
public string? TargetHost { get { throw null; } set { } }
210+
public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } }
210211
}
211212
public readonly partial struct SslClientHelloInfo
212213
{
@@ -229,6 +230,7 @@ public SslServerAuthenticationOptions() { }
229230
public System.Security.Cryptography.X509Certificates.X509Certificate? ServerCertificate { get { throw null; } set { } }
230231
public System.Net.Security.SslStreamCertificateContext? ServerCertificateContext { get { throw null; } set { } }
231232
public System.Net.Security.ServerCertificateSelectionCallback? ServerCertificateSelectionCallback { get { throw null; } set { } }
233+
public System.Security.Cryptography.X509Certificates.X509ChainPolicy? CertificateChainPolicy { get { throw null; } set { } }
232234
}
233235
public partial class SslStream : System.Net.Security.AuthenticatedStream
234236
{

src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Android.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ internal static SslPolicyErrors VerifyCertificateProperties(
4444
private static X509Certificate2? GetRemoteCertificate(
4545
SafeDeleteContext? securityContext,
4646
bool retrieveChainCertificates,
47-
ref X509Chain? chain)
47+
ref X509Chain? chain,
48+
X509ChainPolicy? chainPolicy)
4849
{
4950
SafeSslHandle? sslContext = ((SafeDeleteSslContext?)securityContext)?.SslContext;
5051
if (sslContext == null)
@@ -65,6 +66,10 @@ internal static SslPolicyErrors VerifyCertificateProperties(
6566
else
6667
{
6768
chain ??= new X509Chain();
69+
if (chainPolicy != null)
70+
{
71+
chain.ChainPolicy = chainPolicy;
72+
}
6873
IntPtr[]? ptrs = Interop.AndroidCrypto.SSLStreamGetPeerCertificates(sslContext);
6974
if (ptrs != null && ptrs.Length > 0)
7075
{

src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.OSX.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ internal static SslPolicyErrors VerifyCertificateProperties(
5050
private static X509Certificate2? GetRemoteCertificate(
5151
SafeDeleteContext? securityContext,
5252
bool retrieveChainCertificates,
53-
ref X509Chain? chain)
53+
ref X509Chain? chain,
54+
X509ChainPolicy? chainPolicy)
5455
{
5556
if (securityContext == null)
5657
{
@@ -73,6 +74,10 @@ internal static SslPolicyErrors VerifyCertificateProperties(
7374
if (retrieveChainCertificates)
7475
{
7576
chain ??= new X509Chain();
77+
if (chainPolicy != null)
78+
{
79+
chain.ChainPolicy = chainPolicy;
80+
}
7681

7782
for (int i = 0; i < chainSize; i++)
7883
{

src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Unix.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ internal static SslPolicyErrors VerifyCertificateProperties(
2424
//
2525
// Extracts a remote certificate upon request.
2626
//
27-
private static X509Certificate2? GetRemoteCertificate(SafeDeleteContext? securityContext, bool retrieveChainCertificates, ref X509Chain? chain)
27+
private static X509Certificate2? GetRemoteCertificate(
28+
SafeDeleteContext? securityContext,
29+
bool retrieveChainCertificates,
30+
ref X509Chain? chain,
31+
X509ChainPolicy? chainPolicy)
2832
{
2933
bool gotReference = false;
3034

@@ -48,6 +52,10 @@ internal static SslPolicyErrors VerifyCertificateProperties(
4852
if (retrieveChainCertificates)
4953
{
5054
chain ??= new X509Chain();
55+
if (chainPolicy != null)
56+
{
57+
chain.ChainPolicy = chainPolicy;
58+
}
5159

5260
using (SafeSharedX509StackHandle chainStack =
5361
Interop.OpenSsl.GetPeerCertificateChain(((SafeDeleteSslContext)securityContext).SslContext))

src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ internal static SslPolicyErrors VerifyCertificateProperties(
2929
//
3030

3131
private static X509Certificate2? GetRemoteCertificate(
32-
SafeDeleteContext? securityContext, bool retrieveChainCertificates, ref X509Chain? chain)
32+
SafeDeleteContext? securityContext,
33+
bool retrieveChainCertificates,
34+
ref X509Chain? chain,
35+
X509ChainPolicy? chainPolicy)
3336
{
3437
if (securityContext == null)
3538
{
@@ -67,6 +70,10 @@ internal static SslPolicyErrors VerifyCertificateProperties(
6770
if (retrieveChainCertificates)
6871
{
6972
chain ??= new X509Chain();
73+
if (chainPolicy != null)
74+
{
75+
chain.ChainPolicy = chainPolicy;
76+
}
7077

7178
UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext, chain.ChainPolicy.ExtraStore);
7279
}

src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ internal static partial class CertificateValidationPal
1919
private static X509Chain? s_chain;
2020

2121
internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext? securityContext) =>
22-
GetRemoteCertificate(securityContext, retrieveChainCertificates: false, ref s_chain);
22+
GetRemoteCertificate(securityContext, retrieveChainCertificates: false, ref s_chain, null);
2323

24-
internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext? securityContext, ref X509Chain? chain) =>
25-
GetRemoteCertificate(securityContext, retrieveChainCertificates: true, ref chain);
24+
internal static X509Certificate2? GetRemoteCertificate(SafeDeleteContext? securityContext, ref X509Chain? chain, X509ChainPolicy? chainPolicy) =>
25+
GetRemoteCertificate(securityContext, retrieveChainCertificates: true, ref chain, chainPolicy);
2626

2727
static partial void CheckSupportsStore(StoreLocation storeLocation, ref bool hasSupport);
2828

src/libraries/System.Net.Security/src/System/Net/Security/SslAuthenticationOptions.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ internal void UpdateOptions(SslClientAuthenticationOptions sslClientAuthenticati
5656
CertificateRevocationCheckMode = sslClientAuthenticationOptions.CertificateRevocationCheckMode;
5757
ClientCertificates = sslClientAuthenticationOptions.ClientCertificates;
5858
CipherSuitesPolicy = sslClientAuthenticationOptions.CipherSuitesPolicy;
59+
60+
if (sslClientAuthenticationOptions.CertificateChainPolicy != null)
61+
{
62+
CertificateChainPolicy = sslClientAuthenticationOptions.CertificateChainPolicy.Clone();
63+
}
5964
}
6065

6166
internal void UpdateOptions(ServerOptionsSelectionCallback optionCallback, object? state)
@@ -135,6 +140,11 @@ internal void UpdateOptions(SslServerAuthenticationOptions sslServerAuthenticati
135140
{
136141
ServerCertSelectionDelegate = sslServerAuthenticationOptions.ServerCertificateSelectionCallback;
137142
}
143+
144+
if (sslServerAuthenticationOptions.CertificateChainPolicy != null)
145+
{
146+
CertificateChainPolicy = sslServerAuthenticationOptions.CertificateChainPolicy.Clone();
147+
}
138148
}
139149

140150
private static SslProtocols FilterOutIncompatibleSslProtocols(SslProtocols protocols)
@@ -170,5 +180,6 @@ private static SslProtocols FilterOutIncompatibleSslProtocols(SslProtocols proto
170180
internal CipherSuitesPolicy? CipherSuitesPolicy { get; set; }
171181
internal object? UserState { get; set; }
172182
internal ServerOptionsSelectionCallback? ServerOptionDelegate { get; set; }
183+
internal X509ChainPolicy? CertificateChainPolicy { get; set; }
173184
}
174185
}

src/libraries/System.Net.Security/src/System/Net/Security/SslClientAuthenticationOptions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,5 +73,13 @@ public SslProtocols EnabledSslProtocols
7373
/// Use extreme caution when changing this setting.
7474
/// </summary>
7575
public CipherSuitesPolicy? CipherSuitesPolicy { get; set; }
76+
77+
/// <summary>
78+
/// Gets or sets an optional customized policy for remote certificate
79+
/// validation. If not <see langword="null"/>,
80+
/// <see cref="CertificateRevocationCheckMode"/> and <see cref="SslCertificateTrust"/>
81+
/// are ignored.
82+
/// </summary>
83+
public X509ChainPolicy? CertificateChainPolicy { get; set; }
7684
}
7785
}

src/libraries/System.Net.Security/src/System/Net/Security/SslServerAuthenticationOptions.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,5 +74,13 @@ public EncryptionPolicy EncryptionPolicy
7474
/// Use extreme caution when changing this setting.
7575
/// </summary>
7676
public CipherSuitesPolicy? CipherSuitesPolicy { get; set; }
77+
78+
/// <summary>
79+
/// Gets or sets an optional customized policy for remote certificate
80+
/// validation. If not <see langword="null"/>,
81+
/// <see cref="CertificateRevocationCheckMode"/> and <see cref="SslCertificateTrust"/>
82+
/// are ignored.
83+
/// </summary>
84+
public X509ChainPolicy? CertificateChainPolicy { get; set; }
7785
}
7886
}

src/libraries/System.Net.Security/src/System/Net/Security/SslStream.Protocol.cs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -936,7 +936,7 @@ internal bool VerifyRemoteCertificate(RemoteCertificateValidationCallback? remot
936936

937937
try
938938
{
939-
X509Certificate2? certificate = CertificateValidationPal.GetRemoteCertificate(_securityContext, ref chain);
939+
X509Certificate2? certificate = CertificateValidationPal.GetRemoteCertificate(_securityContext, ref chain, _sslAuthenticationOptions.CertificateChainPolicy);
940940
if (_remoteCertificate != null && certificate != null &&
941941
certificate.RawDataMemory.Span.SequenceEqual(_remoteCertificate.RawDataMemory.Span))
942942
{
@@ -955,25 +955,37 @@ internal bool VerifyRemoteCertificate(RemoteCertificateValidationCallback? remot
955955
else
956956
{
957957
chain ??= new X509Chain();
958-
chain.ChainPolicy.RevocationMode = _sslAuthenticationOptions.CertificateRevocationCheckMode;
959-
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
960958

961-
// Authenticate the remote party: (e.g. when operating in server mode, authenticate the client).
962-
chain.ChainPolicy.ApplicationPolicy.Add(_sslAuthenticationOptions.IsServer ? s_clientAuthOid : s_serverAuthOid);
963-
964-
if (trust != null)
959+
if (_sslAuthenticationOptions.CertificateChainPolicy != null)
965960
{
966-
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
967-
if (trust._store != null)
968-
{
969-
chain.ChainPolicy.CustomTrustStore.AddRange(trust._store.Certificates);
970-
}
971-
if (trust._trustList != null)
961+
chain.ChainPolicy = _sslAuthenticationOptions.CertificateChainPolicy;
962+
}
963+
else
964+
{
965+
chain.ChainPolicy.RevocationMode = _sslAuthenticationOptions.CertificateRevocationCheckMode;
966+
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
967+
968+
if (trust != null)
972969
{
973-
chain.ChainPolicy.CustomTrustStore.AddRange(trust._trustList);
970+
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
971+
if (trust._store != null)
972+
{
973+
chain.ChainPolicy.CustomTrustStore.AddRange(trust._store.Certificates);
974+
}
975+
if (trust._trustList != null)
976+
{
977+
chain.ChainPolicy.CustomTrustStore.AddRange(trust._trustList);
978+
}
974979
}
975980
}
976981

982+
// set ApplicationPolicy unless already provided.
983+
if (chain.ChainPolicy.ApplicationPolicy.Count == 0)
984+
{
985+
// Authenticate the remote party: (e.g. when operating in server mode, authenticate the client).
986+
chain.ChainPolicy.ApplicationPolicy.Add(_sslAuthenticationOptions.IsServer ? s_clientAuthOid : s_serverAuthOid);
987+
}
988+
977989
sslPolicyErrors |= CertificateValidationPal.VerifyCertificateProperties(
978990
_securityContext!,
979991
chain,

0 commit comments

Comments
 (0)