using System; using System.IO; using System.Net.Sockets; namespace Org.BouncyCastle.Tls { public class DtlsTransport : DatagramTransport { private readonly DtlsRecordLayer m_recordLayer; private readonly bool m_ignoreCorruptRecords; internal DtlsTransport(DtlsRecordLayer recordLayer, bool ignoreCorruptRecords) { m_recordLayer = recordLayer; m_ignoreCorruptRecords = ignoreCorruptRecords; } /// public virtual int GetReceiveLimit() { return m_recordLayer.GetReceiveLimit(); } /// public virtual int GetSendLimit() { return m_recordLayer.GetSendLimit(); } /// public virtual int Receive(byte[] buf, int off, int len, int waitMillis) { if (null == buf) throw new ArgumentNullException("buf"); if (off < 0 || off >= buf.Length) throw new ArgumentException("invalid offset: " + off, "off"); if (len < 0 || len > buf.Length - off) throw new ArgumentException("invalid length: " + len, "len"); #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER return Receive(buf.AsSpan(off, len), waitMillis); #else if (waitMillis < 0) throw new ArgumentException("cannot be negative", "waitMillis"); try { return m_recordLayer.Receive(buf, off, len, waitMillis); } catch (TlsFatalAlert fatalAlert) { if (m_ignoreCorruptRecords && AlertDescription.bad_record_mac == fatalAlert.AlertDescription) return -1; m_recordLayer.Fail(fatalAlert.AlertDescription); throw; } catch (TlsTimeoutException) { throw; } catch (SocketException e) { if (TlsUtilities.IsTimeout(e)) throw; m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } // TODO[tls-port] Can we support interrupted IO on .NET? //catch (InterruptedIOException) //{ // throw; //} catch (IOException) { m_recordLayer.Fail(AlertDescription.internal_error); throw; } catch (Exception e) { m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } #endif } /// public virtual int ReceivePending(byte[] buf, int off, int len) { if (null == buf) throw new ArgumentNullException("buf"); if (off < 0 || off >= buf.Length) throw new ArgumentException("invalid offset: " + off, "off"); if (len < 0 || len > buf.Length - off) throw new ArgumentException("invalid length: " + len, "len"); #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER return ReceivePending(buf.AsSpan(off, len)); #else try { return m_recordLayer.ReceivePending(buf, off, len); } catch (TlsFatalAlert fatalAlert) { if (m_ignoreCorruptRecords && AlertDescription.bad_record_mac == fatalAlert.AlertDescription) return -1; m_recordLayer.Fail(fatalAlert.AlertDescription); throw; } catch (TlsTimeoutException) { throw; } catch (SocketException e) { if (TlsUtilities.IsTimeout(e)) throw; m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } // TODO[tls-port] Can we support interrupted IO on .NET? //catch (InterruptedIOException) //{ // throw; //} catch (IOException) { m_recordLayer.Fail(AlertDescription.internal_error); throw; } catch (Exception e) { m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } #endif } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER /// public virtual int Receive(Span buffer, int waitMillis) { if (waitMillis < 0) throw new ArgumentException("cannot be negative", nameof(waitMillis)); try { return m_recordLayer.Receive(buffer, waitMillis); } catch (TlsFatalAlert fatalAlert) { if (m_ignoreCorruptRecords && AlertDescription.bad_record_mac == fatalAlert.AlertDescription) return -1; m_recordLayer.Fail(fatalAlert.AlertDescription); throw; } catch (TlsTimeoutException) { throw; } catch (SocketException e) { if (TlsUtilities.IsTimeout(e)) throw; m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } // TODO[tls-port] Can we support interrupted IO on .NET? //catch (InterruptedIOException) //{ // throw; //} catch (IOException) { m_recordLayer.Fail(AlertDescription.internal_error); throw; } catch (Exception e) { m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } } /// public virtual int ReceivePending(Span buffer) { try { return m_recordLayer.ReceivePending(buffer); } catch (TlsFatalAlert fatalAlert) { if (m_ignoreCorruptRecords && AlertDescription.bad_record_mac == fatalAlert.AlertDescription) return -1; m_recordLayer.Fail(fatalAlert.AlertDescription); throw; } catch (TlsTimeoutException) { throw; } catch (SocketException e) { if (TlsUtilities.IsTimeout(e)) throw; m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } // TODO[tls-port] Can we support interrupted IO on .NET? //catch (InterruptedIOException) //{ // throw; //} catch (IOException) { m_recordLayer.Fail(AlertDescription.internal_error); throw; } catch (Exception e) { m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } } #endif /// public virtual void Send(byte[] buf, int off, int len) { if (null == buf) throw new ArgumentNullException("buf"); if (off < 0 || off >= buf.Length) throw new ArgumentException("invalid offset: " + off, "off"); if (len < 0 || len > buf.Length - off) throw new ArgumentException("invalid length: " + len, "len"); #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER Send(buf.AsSpan(off, len)); #else try { m_recordLayer.Send(buf, off, len); } catch (TlsFatalAlert fatalAlert) { m_recordLayer.Fail(fatalAlert.AlertDescription); throw; } catch (TlsTimeoutException) { throw; } catch (SocketException e) { if (TlsUtilities.IsTimeout(e)) throw; m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } // TODO[tls-port] Can we support interrupted IO on .NET? //catch (InterruptedIOException) //{ // throw; //} catch (IOException) { m_recordLayer.Fail(AlertDescription.internal_error); throw; } catch (Exception e) { m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } #endif } #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER public virtual void Send(ReadOnlySpan buffer) { try { m_recordLayer.Send(buffer); } catch (TlsFatalAlert fatalAlert) { m_recordLayer.Fail(fatalAlert.AlertDescription); throw; } catch (TlsTimeoutException) { throw; } catch (SocketException e) { if (TlsUtilities.IsTimeout(e)) throw; m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } // TODO[tls-port] Can we support interrupted IO on .NET? //catch (InterruptedIOException) //{ // throw; //} catch (IOException) { m_recordLayer.Fail(AlertDescription.internal_error); throw; } catch (Exception e) { m_recordLayer.Fail(AlertDescription.internal_error); throw new TlsFatalAlert(AlertDescription.internal_error, e); } } #endif /// public virtual void Close() { m_recordLayer.Close(); } } }