22
22
using System . Net ;
23
23
using System . Net . Http ;
24
24
using System . Threading . Tasks ;
25
+ using X509Certificate2 = System . Security . Cryptography . X509Certificates . X509Certificate2 ;
26
+
25
27
using System . Security . Cryptography . X509Certificates ;
28
+ using System . Net . Security ;
26
29
27
30
namespace Confluent . SchemaRegistry
28
31
{
@@ -55,7 +58,7 @@ public class RestService : IRestService
55
58
/// </summary>
56
59
public RestService ( string schemaRegistryUrl , int timeoutMs ,
57
60
IAuthenticationHeaderValueProvider authenticationHeaderValueProvider , List < X509Certificate2 > certificates ,
58
- bool enableSslCertificateVerification )
61
+ bool enableSslCertificateVerification , X509Certificate2 sslCaCertificate = null )
59
62
{
60
63
this . authenticationHeaderValueProvider = authenticationHeaderValueProvider ;
61
64
@@ -67,7 +70,7 @@ public RestService(string schemaRegistryUrl, int timeoutMs,
67
70
HttpClient client ;
68
71
if ( certificates . Count > 0 )
69
72
{
70
- client = new HttpClient ( CreateHandler ( certificates , enableSslCertificateVerification ) )
73
+ client = new HttpClient ( CreateHandler ( certificates , enableSslCertificateVerification , sslCaCertificate ) )
71
74
{
72
75
BaseAddress = new Uri ( uri , UriKind . Absolute ) , Timeout = TimeSpan . FromMilliseconds ( timeoutMs )
73
76
} ;
@@ -92,19 +95,54 @@ private static string SanitizeUri(string uri)
92
95
}
93
96
94
97
private static HttpClientHandler CreateHandler ( List < X509Certificate2 > certificates ,
95
- bool enableSslCertificateVerification )
98
+ bool enableSslCertificateVerification , X509Certificate2 sslCaCertificate )
96
99
{
97
100
var handler = new HttpClientHandler ( ) ;
98
101
handler . ClientCertificateOptions = ClientCertificateOption . Manual ;
99
102
103
+ certificates . ForEach ( c => handler . ClientCertificates . Add ( c ) ) ;
104
+
100
105
if ( ! enableSslCertificateVerification )
101
106
{
102
- handler . ServerCertificateCustomValidationCallback =
103
- ( httpRequestMessage , cert , certChain , policyErrors ) => { return true ; } ;
104
- }
107
+ handler . ServerCertificateCustomValidationCallback = ( _ , __ , ___ , ____ ) => { return true ; } ;
108
+ }
109
+ else if ( sslCaCertificate != null )
110
+ {
111
+ handler . ServerCertificateCustomValidationCallback = ( _ , __ , chain , policyErrors ) => {
112
+
113
+ if ( policyErrors == SslPolicyErrors . None )
114
+ {
115
+ return true ;
116
+ }
117
+
118
+
119
+ //The second element of the chain should be the issuer of the certificate
120
+ if ( chain . ChainElements . Count < 2 )
121
+ {
122
+ return false ;
123
+ }
124
+ var connectionCertHash = chain . ChainElements [ 1 ] . Certificate . GetCertHash ( ) ;
125
+
126
+
127
+ var expectedCertHash = sslCaCertificate . GetCertHash ( ) ;
105
128
106
- certificates . ForEach ( c => handler . ClientCertificates . Add ( c ) ) ;
107
- return handler ;
129
+ if ( connectionCertHash . Length != expectedCertHash . Length )
130
+ {
131
+ return false ;
132
+ }
133
+
134
+ for ( int i = 0 ; i < connectionCertHash . Length ; i ++ )
135
+ {
136
+ if ( connectionCertHash [ i ] != expectedCertHash [ i ] )
137
+ {
138
+ return false ;
139
+ }
140
+ }
141
+ return true ;
142
+ } ;
143
+ }
144
+
145
+ return handler ;
108
146
}
109
147
110
148
private RegisteredSchema SanitizeRegisteredSchema ( RegisteredSchema schema )
0 commit comments