1 // Licensed to the Apache Software Foundation(ASF) under one
2 // or more contributor license agreements.See the NOTICE file
3 // distributed with this work for additional information
4 // regarding copyright ownership.The ASF licenses this file
5 // to you under the Apache License, Version 2.0 (the
6 // "License"); you may not use this file except in compliance
7 // with the License. You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing,
12 // software distributed under the License is distributed on an
13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14 // KIND, either express or implied. See the License for the
15 // specific language governing permissions and limitations
20 using System.Net.Security;
21 using System.Net.Sockets;
22 using System.Security.Authentication;
23 using System.Security.Cryptography.X509Certificates;
24 using System.Threading;
25 using System.Threading.Tasks;
27 namespace Thrift.Transports.Client
29 //TODO: check for correct work
31 // ReSharper disable once InconsistentNaming
32 public class TTlsSocketClientTransport : TStreamClientTransport
34 private readonly X509Certificate2 _certificate;
35 private readonly RemoteCertificateValidationCallback _certValidator;
36 private readonly IPAddress _host;
37 private readonly bool _isServer;
38 private readonly LocalCertificateSelectionCallback _localCertificateSelectionCallback;
39 private readonly int _port;
40 private readonly SslProtocols _sslProtocols;
41 private TcpClient _client;
42 private SslStream _secureStream;
45 public TTlsSocketClientTransport(TcpClient client, X509Certificate2 certificate, bool isServer = false,
46 RemoteCertificateValidationCallback certValidator = null,
47 LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
48 SslProtocols sslProtocols = SslProtocols.Tls12)
51 _certificate = certificate;
52 _certValidator = certValidator;
53 _localCertificateSelectionCallback = localCertificateSelectionCallback;
54 _sslProtocols = sslProtocols;
57 if (isServer && certificate == null)
59 throw new ArgumentException("TTlsSocketClientTransport needs certificate to be used for server",
65 InputStream = client.GetStream();
66 OutputStream = client.GetStream();
70 public TTlsSocketClientTransport(IPAddress host, int port, string certificatePath,
71 RemoteCertificateValidationCallback certValidator = null,
72 LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
73 SslProtocols sslProtocols = SslProtocols.Tls12)
75 new X509Certificate2(certificatePath),
77 localCertificateSelectionCallback,
82 public TTlsSocketClientTransport(IPAddress host, int port,
83 X509Certificate2 certificate = null,
84 RemoteCertificateValidationCallback certValidator = null,
85 LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
86 SslProtocols sslProtocols = SslProtocols.Tls12)
90 localCertificateSelectionCallback,
95 public TTlsSocketClientTransport(IPAddress host, int port, int timeout,
96 X509Certificate2 certificate,
97 RemoteCertificateValidationCallback certValidator = null,
98 LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
99 SslProtocols sslProtocols = SslProtocols.Tls12)
104 _certificate = certificate;
105 _certValidator = certValidator;
106 _localCertificateSelectionCallback = localCertificateSelectionCallback;
107 _sslProtocols = sslProtocols;
114 set { _client.ReceiveTimeout = _client.SendTimeout = _timeout = value; }
117 public TcpClient TcpClient => _client;
119 public IPAddress Host => _host;
121 public int Port => _port;
123 public override bool IsOpen
132 return _client.Connected;
136 private void InitSocket()
138 _client = new TcpClient();
139 _client.ReceiveTimeout = _client.SendTimeout = _timeout;
140 _client.Client.NoDelay = true;
143 private bool DefaultCertificateValidator(object sender, X509Certificate certificate, X509Chain chain,
144 SslPolicyErrors sslValidationErrors)
146 return sslValidationErrors == SslPolicyErrors.None;
149 public override async Task OpenAsync(CancellationToken cancellationToken)
153 throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
158 throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
163 throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
173 await _client.ConnectAsync(_host, _port);
174 await SetupTlsAsync();
178 public async Task SetupTlsAsync()
180 var validator = _certValidator ?? DefaultCertificateValidator;
182 if (_localCertificateSelectionCallback != null)
184 _secureStream = new SslStream(_client.GetStream(), false, validator, _localCertificateSelectionCallback);
188 _secureStream = new SslStream(_client.GetStream(), false, validator);
195 // Server authentication
197 _secureStream.AuthenticateAsServerAsync(_certificate, _certValidator != null, _sslProtocols,
202 // Client authentication
203 var certs = _certificate != null
204 ? new X509CertificateCollection {_certificate}
205 : new X509CertificateCollection();
207 var targetHost = _host.ToString();
208 await _secureStream.AuthenticateAsClientAsync(targetHost, certs, _sslProtocols, true);
217 InputStream = _secureStream;
218 OutputStream = _secureStream;
221 public override void Close()
230 if (_secureStream != null)
232 _secureStream.Dispose();
233 _secureStream = null;