5 // Martin Baulig <martin.baulig@xamarin.com>
7 // Copyright (c) 2015 Xamarin, Inc.
9 // Permission is hereby granted, free of charge, to any person obtaining a copy
10 // of this software and associated documentation files (the "Software"), to deal
11 // in the Software without restriction, including without limitation the rights
12 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 // copies of the Software, and to permit persons to whom the Software is
14 // furnished to do so, subject to the following conditions:
16 // The above copyright notice and this permission notice shall be included in
17 // all copies or substantial portions of the Software.
19 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28 #if MONO_SECURITY_ALIAS
29 extern alias MonoSecurity
;
32 #if MONO_SECURITY_ALIAS
33 using MonoSecurity
::Mono
.Security
.Interface
;
35 using Mono
.Security
.Interface
;
42 using System
.Net
.Sockets
;
43 using System
.Net
.Security
;
44 using System
.Threading
;
45 using System
.Threading
.Tasks
;
46 using System
.Security
.Authentication
;
47 using System
.Security
.Cryptography
.X509Certificates
;
48 using System
.Security
.Principal
;
49 using System
.Security
.Cryptography
;
51 namespace Mono
.Net
.Security
53 class MonoTlsStream
: IDisposable
56 readonly MobileTlsProvider provider
;
57 readonly NetworkStream networkStream
;
58 readonly HttpWebRequest request
;
60 readonly MonoTlsSettings settings
;
62 internal HttpWebRequest Request
{
63 get { return request; }
68 internal SslStream SslStream
{
69 get { return sslStream; }
72 const string EXCEPTION_MESSAGE
= "System.Net.Security.SslStream is not supported on the current platform.";
75 WebExceptionStatus status
;
77 internal WebExceptionStatus ExceptionStatus
{
78 get { return status; }
81 internal bool CertificateValidationFailed
{
85 public MonoTlsStream (HttpWebRequest request
, NetworkStream networkStream
)
88 this.request
= request
;
89 this.networkStream
= networkStream
;
91 settings
= request
.TlsSettings
;
92 provider
= request
.TlsProvider
?? MonoTlsProviderFactory
.GetProviderInternal ();
93 status
= WebExceptionStatus
.SecureChannelFailure
;
95 ChainValidationHelper
.Create (provider
, ref settings
, this);
97 status
= WebExceptionStatus
.SecureChannelFailure
;
98 throw new PlatformNotSupportedException (EXCEPTION_MESSAGE
);
102 internal async Task
<Stream
> CreateStream (WebConnectionTunnel tunnel
, CancellationToken cancellationToken
)
105 var socket
= networkStream
.InternalSocket
;
106 WebConnection
.Debug ($"MONO TLS STREAM CREATE STREAM: {socket.ID}");
107 sslStream
= new SslStream (networkStream
, false, provider
, settings
);
110 var host
= request
.Host
;
111 if (!string.IsNullOrEmpty (host
)) {
112 var pos
= host
.IndexOf (':');
114 host
= host
.Substring (0, pos
);
117 await sslStream
.AuthenticateAsClientAsync (
118 host
, request
.ClientCertificates
,
119 (SslProtocols
)ServicePointManager
.SecurityProtocol
,
120 ServicePointManager
.CheckCertificateRevocationList
).ConfigureAwait (false);
122 status
= WebExceptionStatus
.Success
;
124 request
.ServicePoint
.UpdateClientCertificate (sslStream
.LocalCertificate
);
125 } catch (Exception ex
) {
126 WebConnection
.Debug ($"MONO TLS STREAM ERROR: {socket.ID} {socket.CleanedUp} {ex.Message}");
127 if (socket
.CleanedUp
)
128 status
= WebExceptionStatus
.RequestCanceled
;
129 else if (CertificateValidationFailed
)
130 status
= WebExceptionStatus
.TrustFailure
;
132 status
= WebExceptionStatus
.SecureChannelFailure
;
134 request
.ServicePoint
.UpdateClientCertificate (null);
140 if (tunnel
?.Data
!= null)
141 await sslStream
.WriteAsync (tunnel
.Data
, 0, tunnel
.Data
.Length
, cancellationToken
).ConfigureAwait (false);
143 status
= WebExceptionStatus
.SendFailure
;
150 throw new PlatformNotSupportedException (EXCEPTION_MESSAGE
);
154 public void Dispose ()
159 void CloseSslStream () {
160 if (sslStream
!= null) {
161 sslStream
.Dispose ();