disable broken tests on net_4_0
[mcs.git] / class / System.ServiceModel / Mono.Security.Protocol.Tls / SslStreamBase.cs
blob988749b005bf68eac60da6a435e631655b49e608
1 // Transport Security Layer (TLS)
2 // Copyright (c) 2003-2004 Carlos Guzman Alvarez
3 // Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
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.
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 using System.Threading;
34 namespace Mono.Security.Protocol.Tls
36 public abstract class SslStreamBase: Stream, IDisposable
38 private delegate void AsyncHandshakeDelegate(InternalAsyncResult asyncResult, bool fromWrite);
40 #region Fields
42 static ManualResetEvent record_processing = new ManualResetEvent (true);
44 private const int WaitTimeOut = 5 * 60 * 1000;
46 internal Stream innerStream;
47 internal MemoryStream inputBuffer;
48 internal Context context;
49 internal RecordProtocol protocol;
50 internal bool ownsStream;
51 private volatile bool disposed;
52 private bool checkCertRevocationStatus;
53 private object negotiate;
54 private object read;
55 private object write;
56 private ManualResetEvent negotiationComplete;
58 #endregion
61 #region Constructors
63 protected SslStreamBase(
64 Stream stream,
65 bool ownsStream)
67 if (stream == null)
69 throw new ArgumentNullException("stream is null.");
71 if (!stream.CanRead || !stream.CanWrite)
73 throw new ArgumentNullException("stream is not both readable and writable.");
76 this.inputBuffer = new MemoryStream();
77 this.innerStream = stream;
78 this.ownsStream = ownsStream;
79 this.negotiate = new object();
80 this.read = new object();
81 this.write = new object();
82 this.negotiationComplete = new ManualResetEvent(false);
85 #endregion
87 #region Handshakes
88 private void AsyncHandshakeCallback(IAsyncResult asyncResult)
90 InternalAsyncResult internalResult = asyncResult.AsyncState as InternalAsyncResult;
92 try
94 try
96 this.OnNegotiateHandshakeCallback(asyncResult);
98 catch (TlsException ex)
100 this.protocol.SendAlert(ex.Alert);
102 throw new IOException("The authentication or decryption has failed.", ex);
104 catch (Exception ex)
106 this.protocol.SendAlert(AlertDescription.InternalError);
108 throw new IOException("The authentication or decryption has failed.", ex);
111 if (internalResult.ProceedAfterHandshake)
113 //kick off the read or write process (whichever called us) after the handshake is complete
114 if (internalResult.FromWrite)
116 InternalBeginWrite(internalResult);
118 else
120 InternalBeginRead(internalResult);
122 negotiationComplete.Set();
124 else
126 negotiationComplete.Set();
127 internalResult.SetComplete();
131 catch (Exception ex)
133 negotiationComplete.Set();
134 internalResult.SetComplete(ex);
138 internal bool MightNeedHandshake
142 if (this.context.HandshakeState == HandshakeState.Finished)
144 return false;
146 else
148 lock (this.negotiate)
150 return (this.context.HandshakeState != HandshakeState.Finished);
156 internal void NegotiateHandshake()
158 if (this.MightNeedHandshake)
160 InternalAsyncResult ar = new InternalAsyncResult(null, null, null, 0, 0, false, false);
162 //if something already started negotiation, wait for it.
163 //otherwise end it ourselves.
164 if (!BeginNegotiateHandshake(ar))
166 this.negotiationComplete.WaitOne();
168 else
170 this.EndNegotiateHandshake(ar);
175 #endregion
177 #region Abstracts/Virtuals
179 internal abstract IAsyncResult OnBeginNegotiateHandshake(AsyncCallback callback, object state);
180 internal abstract void OnNegotiateHandshakeCallback(IAsyncResult asyncResult);
182 internal abstract X509Certificate OnLocalCertificateSelection(X509CertificateCollection clientCertificates,
183 X509Certificate serverCertificate,
184 string targetHost,
185 X509CertificateCollection serverRequestedCertificates);
187 internal abstract bool OnRemoteCertificateValidation(X509Certificate certificate, int[] errors);
189 internal abstract AsymmetricAlgorithm OnLocalPrivateKeySelection(X509Certificate certificate, string targetHost);
191 #endregion
193 #region Event Methods
195 internal X509Certificate RaiseLocalCertificateSelection(X509CertificateCollection certificates,
196 X509Certificate remoteCertificate,
197 string targetHost,
198 X509CertificateCollection requestedCertificates)
200 return OnLocalCertificateSelection(certificates, remoteCertificate, targetHost, requestedCertificates);
203 internal bool RaiseRemoteCertificateValidation(X509Certificate certificate, int[] errors)
205 return OnRemoteCertificateValidation(certificate, errors);
208 internal AsymmetricAlgorithm RaiseLocalPrivateKeySelection(
209 X509Certificate certificate,
210 string targetHost)
212 return OnLocalPrivateKeySelection(certificate, targetHost);
214 #endregion
216 #region Security Properties
218 public bool CheckCertRevocationStatus
220 get { return this.checkCertRevocationStatus; }
221 set { this.checkCertRevocationStatus = value; }
224 public CipherAlgorithmType CipherAlgorithm
228 if (this.context.HandshakeState == HandshakeState.Finished)
230 return this.context.Current.Cipher.CipherAlgorithmType;
233 return CipherAlgorithmType.None;
237 public int CipherStrength
241 if (this.context.HandshakeState == HandshakeState.Finished)
243 return this.context.Current.Cipher.EffectiveKeyBits;
246 return 0;
250 public HashAlgorithmType HashAlgorithm
254 if (this.context.HandshakeState == HandshakeState.Finished)
256 return this.context.Current.Cipher.HashAlgorithmType;
259 return HashAlgorithmType.None;
263 public int HashStrength
267 if (this.context.HandshakeState == HandshakeState.Finished)
269 return this.context.Current.Cipher.HashSize * 8;
272 return 0;
276 public int KeyExchangeStrength
280 if (this.context.HandshakeState == HandshakeState.Finished)
282 return this.context.ServerSettings.Certificates[0].RSA.KeySize;
285 return 0;
289 public ExchangeAlgorithmType KeyExchangeAlgorithm
293 if (this.context.HandshakeState == HandshakeState.Finished)
295 return this.context.Current.Cipher.ExchangeAlgorithmType;
298 return ExchangeAlgorithmType.None;
302 public SecurityProtocolType SecurityProtocol
306 if (this.context.HandshakeState == HandshakeState.Finished)
308 return this.context.SecurityProtocol;
311 return 0;
315 public X509Certificate ServerCertificate
319 if (this.context.HandshakeState == HandshakeState.Finished)
321 if (this.context.ServerSettings.Certificates != null &&
322 this.context.ServerSettings.Certificates.Count > 0)
324 return new X509Certificate(this.context.ServerSettings.Certificates[0].RawData);
328 return null;
332 // this is used by Mono's certmgr tool to download certificates
333 internal Mono.Security.X509.X509CertificateCollection ServerCertificates
335 get { return context.ServerSettings.Certificates; }
338 #endregion
340 #region Internal Async Result/State Class
342 private class InternalAsyncResult : IAsyncResult
344 private object locker = new object ();
345 private AsyncCallback _userCallback;
346 private object _userState;
347 private Exception _asyncException;
348 private ManualResetEvent handle;
349 private bool completed;
350 private int _bytesRead;
351 private bool _fromWrite;
352 private bool _proceedAfterHandshake;
354 private byte[] _buffer;
355 private int _offset;
356 private int _count;
358 public InternalAsyncResult(AsyncCallback userCallback, object userState, byte[] buffer, int offset, int count, bool fromWrite, bool proceedAfterHandshake)
360 _userCallback = userCallback;
361 _userState = userState;
362 _buffer = buffer;
363 _offset = offset;
364 _count = count;
365 _fromWrite = fromWrite;
366 _proceedAfterHandshake = proceedAfterHandshake;
369 public bool ProceedAfterHandshake
371 get { return _proceedAfterHandshake; }
374 public bool FromWrite
376 get { return _fromWrite; }
379 public byte[] Buffer
381 get { return _buffer; }
384 public int Offset
386 get { return _offset; }
389 public int Count
391 get { return _count; }
394 public int BytesRead
396 get { return _bytesRead; }
399 public object AsyncState
401 get { return _userState; }
404 public Exception AsyncException
406 get { return _asyncException; }
409 public bool CompletedWithError
411 get {
412 if (IsCompleted == false)
413 return false;
414 return null != _asyncException;
418 public WaitHandle AsyncWaitHandle
420 get {
421 lock (locker) {
422 if (handle == null)
423 handle = new ManualResetEvent (completed);
425 return handle;
429 public bool CompletedSynchronously
431 get { return false; }
434 public bool IsCompleted
436 get {
437 lock (locker)
438 return completed;
442 private void SetComplete(Exception ex, int bytesRead)
444 lock (locker) {
445 if (completed)
446 return;
448 completed = true;
449 _asyncException = ex;
450 _bytesRead = bytesRead;
451 if (handle != null)
452 handle.Set ();
454 if (_userCallback != null)
455 _userCallback.BeginInvoke (this, null, null);
458 public void SetComplete(Exception ex)
460 SetComplete(ex, 0);
463 public void SetComplete(int bytesRead)
465 SetComplete(null, bytesRead);
468 public void SetComplete()
470 SetComplete(null, 0);
473 #endregion
475 #region Stream Overrides and Async Stream Operations
477 private bool BeginNegotiateHandshake(InternalAsyncResult asyncResult)
481 lock (this.negotiate)
483 if (this.context.HandshakeState == HandshakeState.None)
485 this.OnBeginNegotiateHandshake(new AsyncCallback(AsyncHandshakeCallback), asyncResult);
487 return true;
489 else
491 return false;
495 catch (TlsException ex)
497 this.negotiationComplete.Set();
498 this.protocol.SendAlert(ex.Alert);
500 throw new IOException("The authentication or decryption has failed.", ex);
502 catch (Exception ex)
504 this.negotiationComplete.Set();
505 this.protocol.SendAlert(AlertDescription.InternalError);
507 throw new IOException("The authentication or decryption has failed.", ex);
511 private void EndNegotiateHandshake(InternalAsyncResult asyncResult)
513 if (asyncResult.IsCompleted == false)
514 asyncResult.AsyncWaitHandle.WaitOne();
516 if (asyncResult.CompletedWithError)
518 throw asyncResult.AsyncException;
522 public override IAsyncResult BeginRead(
523 byte[] buffer,
524 int offset,
525 int count,
526 AsyncCallback callback,
527 object state)
529 this.checkDisposed();
531 if (buffer == null)
533 throw new ArgumentNullException("buffer is a null reference.");
535 if (offset < 0)
537 throw new ArgumentOutOfRangeException("offset is less than 0.");
539 if (offset > buffer.Length)
541 throw new ArgumentOutOfRangeException("offset is greater than the length of buffer.");
543 if (count < 0)
545 throw new ArgumentOutOfRangeException("count is less than 0.");
547 if (count > (buffer.Length - offset))
549 throw new ArgumentOutOfRangeException("count is less than the length of buffer minus the value of the offset parameter.");
552 InternalAsyncResult asyncResult = new InternalAsyncResult(callback, state, buffer, offset, count, false, true);
554 if (this.MightNeedHandshake)
556 if (! BeginNegotiateHandshake(asyncResult))
558 //we made it down here so the handshake was not started.
559 //another thread must have started it in the mean time.
560 //wait for it to complete and then perform our original operation
561 this.negotiationComplete.WaitOne();
563 InternalBeginRead(asyncResult);
566 else
568 InternalBeginRead(asyncResult);
571 return asyncResult;
574 // bigger than max record length for SSL/TLS
575 private byte[] recbuf = new byte[16384];
577 private void InternalBeginRead(InternalAsyncResult asyncResult)
581 int preReadSize = 0;
583 lock (this.read)
585 // If actual buffer is fully read, reset it
586 bool shouldReset = this.inputBuffer.Position == this.inputBuffer.Length && this.inputBuffer.Length > 0;
588 // If the buffer isn't fully read, but does have data, we need to immediately
589 // read the info from the buffer and let the user know that they have more data.
590 bool shouldReadImmediately = (this.inputBuffer.Length > 0) && (asyncResult.Count > 0);
592 if (shouldReset)
594 this.resetBuffer();
596 else if (shouldReadImmediately)
598 preReadSize = this.inputBuffer.Read(asyncResult.Buffer, asyncResult.Offset, asyncResult.Count);
602 // This is explicitly done outside the synclock to avoid
603 // any potential deadlocks in the delegate call.
604 if (0 < preReadSize)
606 asyncResult.SetComplete(preReadSize);
608 else if (!this.context.ConnectionEnd)
610 // this will read data from the network until we have (at least) one
611 // record to send back to the caller
612 this.innerStream.BeginRead(recbuf, 0, recbuf.Length,
613 new AsyncCallback(InternalReadCallback), new object[] { recbuf, asyncResult });
615 else
617 // We're done with the connection so we need to let the caller know with 0 bytes read
618 asyncResult.SetComplete(0);
621 catch (TlsException ex)
623 this.protocol.SendAlert(ex.Alert);
625 throw new IOException("The authentication or decryption has failed.", ex);
627 catch (Exception ex)
629 throw new IOException("IO exception during read.", ex);
634 private MemoryStream recordStream = new MemoryStream();
636 // read encrypted data until we have enough to decrypt (at least) one
637 // record and return are the records (may be more than one) we have
638 private void InternalReadCallback(IAsyncResult result)
640 if (this.disposed)
641 return;
643 object[] state = (object[])result.AsyncState;
644 byte[] recbuf = (byte[])state[0];
645 InternalAsyncResult internalResult = (InternalAsyncResult)state[1];
649 int n = innerStream.EndRead(result);
650 if (n > 0)
652 // Add the just received data to the waiting data
653 recordStream.Write(recbuf, 0, n);
655 else
657 // 0 length data means this read operation is done (lost connection in the case of a network stream).
658 internalResult.SetComplete(0);
659 return;
662 bool dataToReturn = false;
663 long pos = recordStream.Position;
665 recordStream.Position = 0;
666 byte[] record = null;
668 // don't try to decode record unless we have at least 5 bytes
669 // i.e. type (1), protocol (2) and length (2)
670 if (recordStream.Length >= 5)
672 record = this.protocol.ReceiveRecord(recordStream);
675 // a record of 0 length is valid (and there may be more record after it)
676 while (record != null)
678 // we probably received more stuff after the record, and we must keep it!
679 long remainder = recordStream.Length - recordStream.Position;
680 byte[] outofrecord = null;
681 if (remainder > 0)
683 outofrecord = new byte[remainder];
684 recordStream.Read(outofrecord, 0, outofrecord.Length);
687 lock (this.read)
689 long position = this.inputBuffer.Position;
691 if (record.Length > 0)
693 // Write new data to the inputBuffer
694 this.inputBuffer.Seek(0, SeekOrigin.End);
695 this.inputBuffer.Write(record, 0, record.Length);
697 // Restore buffer position
698 this.inputBuffer.Seek(position, SeekOrigin.Begin);
699 dataToReturn = true;
703 recordStream.SetLength(0);
704 record = null;
706 if (remainder > 0)
708 recordStream.Write(outofrecord, 0, outofrecord.Length);
709 // type (1), protocol (2) and length (2)
710 if (recordStream.Length >= 5)
712 // try to see if another record is available
713 recordStream.Position = 0;
714 record = this.protocol.ReceiveRecord(recordStream);
715 if (record == null)
716 pos = recordStream.Length;
718 else
719 pos = remainder;
721 else
722 pos = 0;
725 if (!dataToReturn && (n > 0))
727 // there is no record to return to caller and (possibly) more data waiting
728 // so continue reading from network (and appending to stream)
729 recordStream.Position = recordStream.Length;
730 this.innerStream.BeginRead(recbuf, 0, recbuf.Length,
731 new AsyncCallback(InternalReadCallback), state);
733 else
735 // we have record(s) to return -or- no more available to read from network
736 // reset position for further reading
737 recordStream.Position = pos;
739 int bytesRead = 0;
740 lock (this.read)
742 bytesRead = this.inputBuffer.Read(internalResult.Buffer, internalResult.Offset, internalResult.Count);
745 internalResult.SetComplete(bytesRead);
748 catch (Exception ex)
750 internalResult.SetComplete(ex);
755 private void InternalBeginWrite(InternalAsyncResult asyncResult)
759 // Send the buffer as a TLS record
761 lock (this.write)
763 byte[] record = this.protocol.EncodeRecord(
764 ContentType.ApplicationData, asyncResult.Buffer, asyncResult.Offset, asyncResult.Count);
766 this.innerStream.BeginWrite(
767 record, 0, record.Length, new AsyncCallback(InternalWriteCallback), asyncResult);
770 catch (TlsException ex)
772 this.protocol.SendAlert(ex.Alert);
773 this.Close();
775 throw new IOException("The authentication or decryption has failed.", ex);
777 catch (Exception ex)
779 throw new IOException("IO exception during Write.", ex);
783 private void InternalWriteCallback(IAsyncResult ar)
785 if (this.disposed)
786 return;
788 InternalAsyncResult internalResult = (InternalAsyncResult)ar.AsyncState;
792 this.innerStream.EndWrite(ar);
793 internalResult.SetComplete();
795 catch (Exception ex)
797 internalResult.SetComplete(ex);
801 public override IAsyncResult BeginWrite(
802 byte[] buffer,
803 int offset,
804 int count,
805 AsyncCallback callback,
806 object state)
808 this.checkDisposed();
810 if (buffer == null)
812 throw new ArgumentNullException("buffer is a null reference.");
814 if (offset < 0)
816 throw new ArgumentOutOfRangeException("offset is less than 0.");
818 if (offset > buffer.Length)
820 throw new ArgumentOutOfRangeException("offset is greater than the length of buffer.");
822 if (count < 0)
824 throw new ArgumentOutOfRangeException("count is less than 0.");
826 if (count > (buffer.Length - offset))
828 throw new ArgumentOutOfRangeException("count is less than the length of buffer minus the value of the offset parameter.");
832 InternalAsyncResult asyncResult = new InternalAsyncResult(callback, state, buffer, offset, count, true, true);
834 if (this.MightNeedHandshake)
836 if (! BeginNegotiateHandshake(asyncResult))
838 //we made it down here so the handshake was not started.
839 //another thread must have started it in the mean time.
840 //wait for it to complete and then perform our original operation
841 this.negotiationComplete.WaitOne();
843 InternalBeginWrite(asyncResult);
846 else
848 InternalBeginWrite(asyncResult);
851 return asyncResult;
854 public override int EndRead(IAsyncResult asyncResult)
856 this.checkDisposed();
858 InternalAsyncResult internalResult = asyncResult as InternalAsyncResult;
859 if (internalResult == null)
861 throw new ArgumentNullException("asyncResult is null or was not obtained by calling BeginRead.");
864 // Always wait until the read is complete
865 if (!asyncResult.IsCompleted)
867 if (!asyncResult.AsyncWaitHandle.WaitOne (WaitTimeOut, false))
868 throw new TlsException (AlertDescription.InternalError, "Couldn't complete EndRead");
871 if (internalResult.CompletedWithError)
873 throw internalResult.AsyncException;
876 return internalResult.BytesRead;
879 public override void EndWrite(IAsyncResult asyncResult)
881 this.checkDisposed();
883 InternalAsyncResult internalResult = asyncResult as InternalAsyncResult;
884 if (internalResult == null)
886 throw new ArgumentNullException("asyncResult is null or was not obtained by calling BeginWrite.");
890 if (!asyncResult.IsCompleted)
892 if (!internalResult.AsyncWaitHandle.WaitOne (WaitTimeOut, false))
893 throw new TlsException (AlertDescription.InternalError, "Couldn't complete EndWrite");
896 if (internalResult.CompletedWithError)
898 throw internalResult.AsyncException;
902 public override void Close()
904 #if NET_2_0
905 base.Close ();
906 #else
907 ((IDisposable)this).Dispose();
908 #endif
911 public override void Flush()
913 this.checkDisposed();
915 this.innerStream.Flush();
918 public int Read(byte[] buffer)
920 return this.Read(buffer, 0, buffer.Length);
923 public override int Read(byte[] buffer, int offset, int count)
925 this.checkDisposed ();
927 if (buffer == null)
929 throw new ArgumentNullException ("buffer");
931 if (offset < 0)
933 throw new ArgumentOutOfRangeException("offset is less than 0.");
935 if (offset > buffer.Length)
937 throw new ArgumentOutOfRangeException("offset is greater than the length of buffer.");
939 if (count < 0)
941 throw new ArgumentOutOfRangeException("count is less than 0.");
943 if (count > (buffer.Length - offset))
945 throw new ArgumentOutOfRangeException("count is less than the length of buffer minus the value of the offset parameter.");
948 if (this.context.HandshakeState != HandshakeState.Finished)
950 this.NegotiateHandshake (); // Handshake negotiation
953 lock (this.read) {
954 try {
955 record_processing.Reset ();
956 // do we already have some decrypted data ?
957 if (this.inputBuffer.Position > 0) {
958 // or maybe we used all the buffer before ?
959 if (this.inputBuffer.Position == this.inputBuffer.Length) {
960 this.inputBuffer.SetLength (0);
961 } else {
962 int n = this.inputBuffer.Read (buffer, offset, count);
963 if (n > 0) {
964 record_processing.Set ();
965 return n;
970 bool needMoreData = false;
971 while (true) {
972 // we first try to process the read with the data we already have
973 if ((recordStream.Position == 0) || needMoreData) {
974 needMoreData = false;
975 // if we loop, then it either means we need more data
976 byte[] recbuf = new byte[16384];
977 int n = 0;
978 if (count == 1) {
979 int value = innerStream.ReadByte ();
980 if (value >= 0) {
981 recbuf[0] = (byte) value;
982 n = 1;
984 } else {
985 n = innerStream.Read (recbuf, 0, recbuf.Length);
987 if (n > 0) {
988 // Add the new received data to the waiting data
989 if ((recordStream.Length > 0) && (recordStream.Position != recordStream.Length))
990 recordStream.Seek (0, SeekOrigin.End);
991 recordStream.Write (recbuf, 0, n);
992 } else {
993 // or that the read operation is done (lost connection in the case of a network stream).
994 record_processing.Set ();
995 return 0;
999 bool dataToReturn = false;
1001 recordStream.Position = 0;
1002 byte[] record = null;
1004 // don't try to decode record unless we have at least 5 bytes
1005 // i.e. type (1), protocol (2) and length (2)
1006 if (recordStream.Length >= 5) {
1007 record = this.protocol.ReceiveRecord (recordStream);
1008 needMoreData = (record == null);
1011 // a record of 0 length is valid (and there may be more record after it)
1012 while (record != null) {
1013 // we probably received more stuff after the record, and we must keep it!
1014 long remainder = recordStream.Length - recordStream.Position;
1015 byte[] outofrecord = null;
1016 if (remainder > 0) {
1017 outofrecord = new byte[remainder];
1018 recordStream.Read (outofrecord, 0, outofrecord.Length);
1021 long position = this.inputBuffer.Position;
1023 if (record.Length > 0) {
1024 // Write new data to the inputBuffer
1025 this.inputBuffer.Seek (0, SeekOrigin.End);
1026 this.inputBuffer.Write (record, 0, record.Length);
1028 // Restore buffer position
1029 this.inputBuffer.Seek (position, SeekOrigin.Begin);
1030 dataToReturn = true;
1033 recordStream.SetLength (0);
1034 record = null;
1036 if (remainder > 0) {
1037 recordStream.Write (outofrecord, 0, outofrecord.Length);
1040 if (dataToReturn) {
1041 // we have record(s) to return -or- no more available to read from network
1042 // reset position for further reading
1043 int i = inputBuffer.Read (buffer, offset, count);
1044 record_processing.Set ();
1045 return i;
1050 catch (TlsException ex)
1052 throw new IOException("The authentication or decryption has failed.", ex);
1054 catch (Exception ex)
1056 throw new IOException("IO exception during read.", ex);
1061 public override long Seek(long offset, SeekOrigin origin)
1063 throw new NotSupportedException();
1066 public override void SetLength(long value)
1068 throw new NotSupportedException();
1071 public void Write(byte[] buffer)
1073 this.Write(buffer, 0, buffer.Length);
1076 public override void Write(byte[] buffer, int offset, int count)
1078 this.checkDisposed ();
1080 if (buffer == null)
1082 throw new ArgumentNullException ("buffer");
1084 if (offset < 0)
1086 throw new ArgumentOutOfRangeException("offset is less than 0.");
1088 if (offset > buffer.Length)
1090 throw new ArgumentOutOfRangeException("offset is greater than the length of buffer.");
1092 if (count < 0)
1094 throw new ArgumentOutOfRangeException("count is less than 0.");
1096 if (count > (buffer.Length - offset))
1098 throw new ArgumentOutOfRangeException("count is less than the length of buffer minus the value of the offset parameter.");
1101 if (this.context.HandshakeState != HandshakeState.Finished)
1103 this.NegotiateHandshake ();
1106 lock (this.write)
1110 // Send the buffer as a TLS record
1111 byte[] record = this.protocol.EncodeRecord (ContentType.ApplicationData, buffer, offset, count);
1112 this.innerStream.Write (record, 0, record.Length);
1114 catch (TlsException ex)
1116 this.protocol.SendAlert(ex.Alert);
1117 this.Close();
1118 throw new IOException("The authentication or decryption has failed.", ex);
1120 catch (Exception ex)
1122 throw new IOException("IO exception during Write.", ex);
1127 public override bool CanRead
1129 get { return this.innerStream.CanRead; }
1132 public override bool CanSeek
1134 get { return false; }
1137 public override bool CanWrite
1139 get { return this.innerStream.CanWrite; }
1142 public override long Length
1144 get { throw new NotSupportedException(); }
1147 public override long Position
1151 throw new NotSupportedException();
1155 throw new NotSupportedException();
1158 #endregion
1160 #region IDisposable Members and Finalizer
1162 ~SslStreamBase()
1164 this.Dispose(false);
1167 #if !NET_2_0
1168 public void Dispose()
1170 this.Dispose(true);
1171 GC.SuppressFinalize(this);
1174 protected virtual void Dispose (bool disposing)
1175 #else
1176 protected override void Dispose (bool disposing)
1177 #endif
1179 if (!this.disposed)
1181 if (disposing)
1183 if (this.innerStream != null)
1185 if (this.context.HandshakeState == HandshakeState.Finished &&
1186 !this.context.ConnectionEnd)
1188 // Write close notify
1189 this.protocol.SendAlert(AlertDescription.CloseNotify);
1192 if (this.ownsStream)
1194 // Close inner stream
1195 this.innerStream.Close();
1198 this.ownsStream = false;
1199 this.innerStream = null;
1202 this.disposed = true;
1203 #if NET_2_0
1204 base.Dispose (disposing);
1205 #endif
1209 #endregion
1211 #region Misc Methods
1213 private void resetBuffer()
1215 this.inputBuffer.SetLength(0);
1216 this.inputBuffer.Position = 0;
1219 internal void checkDisposed()
1221 if (this.disposed)
1223 throw new ObjectDisposedException("The Stream is closed.");
1227 #endregion