1 // Transport Security Layer (TLS) 2 // Copyright (c) 2003-2004 Carlos Guzman Alvarez 3 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining 6 // a copy of this software and associated documentation files (the 7 // "Software"), to deal in the Software without restriction, including 8 // without limitation the rights to use, copy, modify, merge, publish, 9 // distribute, sublicense, and/or sell copies of the Software, and to 10 // permit persons to whom the Software is furnished to do so, subject to 11 // the following conditions: 12 // 13 // The above copyright notice and this permission notice shall be 14 // included in all copies or substantial portions of the Software. 15 // 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 // 24 25 using System; 26 using System.Collections; 27 using System.IO; 28 using System.Net; 29 using System.Net.Sockets; 30 using System.Security.Cryptography; 31 using System.Security.Cryptography.X509Certificates; 32 33 using Mono.Security.Protocol.Tls.Handshake; 34 using Mono.Security.Interface; 35 36 namespace Mono.Security.Protocol.Tls 37 { 38 #if INSIDE_SYSTEM 39 internal 40 #else 41 public 42 #endif 43 class SslServerStream : SslStreamBase 44 { 45 #region Internal Events 46 47 internal event CertificateValidationCallback ClientCertValidation; 48 internal event PrivateKeySelectionCallback PrivateKeySelection; 49 50 #endregion 51 52 #region Properties 53 54 public X509Certificate ClientCertificate 55 { 56 get 57 { 58 if (this.context.HandshakeState == HandshakeState.Finished) 59 { 60 return this.context.ClientSettings.ClientCertificate; 61 } 62 63 return null; 64 } 65 } 66 67 #endregion 68 69 #region Callback Properties 70 71 public CertificateValidationCallback ClientCertValidationDelegate 72 { 73 get { return this.ClientCertValidation; } 74 set { this.ClientCertValidation = value; } 75 } 76 77 public PrivateKeySelectionCallback PrivateKeyCertSelectionDelegate 78 { 79 get { return this.PrivateKeySelection; } 80 set { this.PrivateKeySelection = value; } 81 } 82 83 #endregion 84 85 public event CertificateValidationCallback2 ClientCertValidation2; 86 #region Constructors 87 SslServerStream( Stream stream, X509Certificate serverCertificate)88 public SslServerStream( 89 Stream stream, 90 X509Certificate serverCertificate) : this( 91 stream, 92 serverCertificate, 93 false, 94 false, 95 SecurityProtocolType.Default) 96 { 97 } 98 SslServerStream( Stream stream, X509Certificate serverCertificate, bool clientCertificateRequired, bool ownsStream)99 public SslServerStream( 100 Stream stream, 101 X509Certificate serverCertificate, 102 bool clientCertificateRequired, 103 bool ownsStream): this( 104 stream, 105 serverCertificate, 106 clientCertificateRequired, 107 ownsStream, 108 SecurityProtocolType.Default) 109 { 110 } 111 SslServerStream( Stream stream, X509Certificate serverCertificate, bool clientCertificateRequired, bool requestClientCertificate, bool ownsStream)112 public SslServerStream( 113 Stream stream, 114 X509Certificate serverCertificate, 115 bool clientCertificateRequired, 116 bool requestClientCertificate, 117 bool ownsStream) 118 : this (stream, serverCertificate, clientCertificateRequired, requestClientCertificate, ownsStream, SecurityProtocolType.Default) 119 { 120 } 121 SslServerStream( Stream stream, X509Certificate serverCertificate, bool clientCertificateRequired, bool ownsStream, SecurityProtocolType securityProtocolType)122 public SslServerStream( 123 Stream stream, 124 X509Certificate serverCertificate, 125 bool clientCertificateRequired, 126 bool ownsStream, 127 SecurityProtocolType securityProtocolType) 128 : this (stream, serverCertificate, clientCertificateRequired, false, ownsStream, securityProtocolType) 129 { 130 } 131 SslServerStream( Stream stream, X509Certificate serverCertificate, bool clientCertificateRequired, bool requestClientCertificate, bool ownsStream, SecurityProtocolType securityProtocolType)132 public SslServerStream( 133 Stream stream, 134 X509Certificate serverCertificate, 135 bool clientCertificateRequired, 136 bool requestClientCertificate, 137 bool ownsStream, 138 SecurityProtocolType securityProtocolType) 139 : base(stream, ownsStream) 140 { 141 this.context = new ServerContext( 142 this, 143 securityProtocolType, 144 serverCertificate, 145 clientCertificateRequired, 146 requestClientCertificate); 147 148 this.protocol = new ServerRecordProtocol(innerStream, (ServerContext)this.context); 149 } 150 151 #endregion 152 153 #region Finalizer 154 ~SslServerStream()155 ~SslServerStream() 156 { 157 this.Dispose(false); 158 } 159 160 #endregion 161 162 #region IDisposable Methods 163 Dispose(bool disposing)164 protected override void Dispose(bool disposing) 165 { 166 base.Dispose(disposing); 167 168 if (disposing) 169 { 170 this.ClientCertValidation = null; 171 this.PrivateKeySelection = null; 172 } 173 } 174 175 #endregion 176 177 #region Handsake Methods 178 179 /* 180 Client Server 181 182 ClientHello --------> 183 ServerHello 184 Certificate* 185 ServerKeyExchange* 186 CertificateRequest* 187 <-------- ServerHelloDone 188 Certificate* 189 ClientKeyExchange 190 CertificateVerify* 191 [ChangeCipherSpec] 192 Finished --------> 193 [ChangeCipherSpec] 194 <-------- Finished 195 Application Data <-------> Application Data 196 197 Fig. 1 - Message flow for a full handshake 198 */ 199 BeginNegotiateHandshake(AsyncCallback callback, object state)200 internal override IAsyncResult BeginNegotiateHandshake(AsyncCallback callback, object state) 201 { 202 // Reset the context if needed 203 if (this.context.HandshakeState != HandshakeState.None) 204 { 205 this.context.Clear(); 206 } 207 208 // Obtain supported cipher suites 209 this.context.SupportedCiphers = CipherSuiteFactory.GetSupportedCiphers (true, context.SecurityProtocol); 210 211 // Set handshake state 212 this.context.HandshakeState = HandshakeState.Started; 213 214 // Receive Client Hello message 215 return this.protocol.BeginReceiveRecord(this.innerStream, callback, state); 216 217 } 218 EndNegotiateHandshake(IAsyncResult asyncResult)219 internal override void EndNegotiateHandshake(IAsyncResult asyncResult) 220 { 221 // Receive Client Hello message and ignore it 222 this.protocol.EndReceiveRecord(asyncResult); 223 224 // If received message is not an ClientHello send a 225 // Fatal Alert 226 if (this.context.LastHandshakeMsg != HandshakeType.ClientHello) 227 { 228 this.protocol.SendAlert(AlertDescription.UnexpectedMessage); 229 } 230 231 // Send ServerHello message 232 this.protocol.SendRecord(HandshakeType.ServerHello); 233 234 // Send ServerCertificate message 235 this.protocol.SendRecord(HandshakeType.Certificate); 236 237 // If the client certificate is required send the CertificateRequest message 238 if (((ServerContext)this.context).ClientCertificateRequired || 239 ((ServerContext)this.context).RequestClientCertificate) 240 { 241 this.protocol.SendRecord(HandshakeType.CertificateRequest); 242 } 243 244 // Send ServerHelloDone message 245 this.protocol.SendRecord(HandshakeType.ServerHelloDone); 246 247 // Receive client response, until the Client Finished message 248 // is received. IE can be interrupted at this stage and never 249 // complete the handshake 250 while (this.context.LastHandshakeMsg != HandshakeType.Finished) 251 { 252 byte[] record = this.protocol.ReceiveRecord(this.innerStream); 253 if ((record == null) || (record.Length == 0)) 254 { 255 throw new TlsException( 256 AlertDescription.HandshakeFailiure, 257 "The client stopped the handshake."); 258 } 259 } 260 261 // Send ChangeCipherSpec and ServerFinished messages 262 this.protocol.SendChangeCipherSpec(); 263 this.protocol.SendRecord (HandshakeType.Finished); 264 265 // The handshake is finished 266 this.context.HandshakeState = HandshakeState.Finished; 267 268 // Reset Handshake messages information 269 this.context.HandshakeMessages.Reset (); 270 271 // Clear Key Info 272 this.context.ClearKeyInfo(); 273 } 274 275 #endregion 276 277 #region Event Methods 278 OnLocalCertificateSelection(X509CertificateCollection clientCertificates, X509Certificate serverCertificate, string targetHost, X509CertificateCollection serverRequestedCertificates)279 internal override X509Certificate OnLocalCertificateSelection(X509CertificateCollection clientCertificates, X509Certificate serverCertificate, string targetHost, X509CertificateCollection serverRequestedCertificates) 280 { 281 throw new NotSupportedException(); 282 } 283 OnRemoteCertificateValidation(X509Certificate certificate, int[] errors)284 internal override bool OnRemoteCertificateValidation(X509Certificate certificate, int[] errors) 285 { 286 if (this.ClientCertValidation != null) 287 { 288 return this.ClientCertValidation(certificate, errors); 289 } 290 291 return (errors != null && errors.Length == 0); 292 } 293 294 internal override bool HaveRemoteValidation2Callback { 295 get { return ClientCertValidation2 != null; } 296 } 297 OnRemoteCertificateValidation2(Mono.Security.X509.X509CertificateCollection collection)298 internal override ValidationResult OnRemoteCertificateValidation2 (Mono.Security.X509.X509CertificateCollection collection) 299 { 300 CertificateValidationCallback2 cb = ClientCertValidation2; 301 if (cb != null) 302 return cb (collection); 303 return null; 304 } 305 RaiseClientCertificateValidation( X509Certificate certificate, int[] certificateErrors)306 internal bool RaiseClientCertificateValidation( 307 X509Certificate certificate, 308 int[] certificateErrors) 309 { 310 return base.RaiseRemoteCertificateValidation(certificate, certificateErrors); 311 } 312 OnLocalPrivateKeySelection(X509Certificate certificate, string targetHost)313 internal override AsymmetricAlgorithm OnLocalPrivateKeySelection(X509Certificate certificate, string targetHost) 314 { 315 if (this.PrivateKeySelection != null) 316 { 317 return this.PrivateKeySelection(certificate, targetHost); 318 } 319 320 return null; 321 } 322 RaisePrivateKeySelection( X509Certificate certificate, string targetHost)323 internal AsymmetricAlgorithm RaisePrivateKeySelection( 324 X509Certificate certificate, 325 string targetHost) 326 { 327 return base.RaiseLocalPrivateKeySelection(certificate, targetHost); 328 } 329 330 #endregion 331 } 332 } 333