From 7f6c31db9a9199b4107d31d1d8bf8165a6b8876a Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Thu, 16 Jan 2020 23:37:21 +0000 Subject: [PATCH 01/13] Started adding Tls Primatives --- .../Infrastructure/Endianness.cs | 90 +++++++++++++++++++ .../Tls/BulkCiphers/AdditionalInfo.cs | 21 +++++ .../Tls/BulkCiphers/ISymmertricalCipher.cs | 20 +++++ .../Protocols/Tls/Records/RecordType.cs | 14 +++ .../Protocols/Tls/TlsVersion.cs | 14 +++ 5 files changed, 159 insertions(+) create mode 100644 src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmertricalCipher.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/Records/RecordType.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/TlsVersion.cs diff --git a/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs b/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs new file mode 100644 index 00000000..82db74fa --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; + +namespace Bedrock.Framework.Experimental.Infrastructure +{ + public static class Endianness + { + public static unsafe T FromNetworkOrder(T value) where T : unmanaged + { + if (BitConverter.IsLittleEndian) return Reverse(value); + return value; + } + + public static unsafe T ToNetworkOrder(T value) where T : unmanaged + { + if (BitConverter.IsLittleEndian) return Reverse(value); + return value; + } + + public static unsafe T Reverse(T value) where T : unmanaged + { + var len = sizeof(T); + if (len == 1) + { + return value; + } + else if (len == 2) + { + var val = Unsafe.Read(&value); + val = (ushort)((val >> 8) | (val << 8)); + return Unsafe.Read(&val); + } + else if (len == 4) + { + var val = Unsafe.Read(&value); + val = (val << 24) + | ((val & 0xFF00) << 8) + | ((val & 0xFF0000) >> 8) + | (val >> 24); + return Unsafe.Read(&val); + } + else if (len == 8) + { + var val = Unsafe.Read(&value); + val = (val << 56) + | ((val & 0xFF00) << 40) + | ((val & 0xFF0000) << 24) + | ((val & 0xFF000000) << 8) + | ((val & 0xFF00000000) >> 8) + | ((val & 0xFF0000000000) >> 24) + | ((val & 0xFF000000000000) >> 40) + | (val >> 56); + return Unsafe.Read(&val); + } + else if (len < 512) + { + var val = stackalloc byte[len]; + Unsafe.Write(val, value); + int to = len >> 1, dest = len - 1; + for (var i = 0; i < to; i++) + { + var tmp = val[i]; + val[i] = val[dest]; + val[dest--] = tmp; + } + return Unsafe.Read(val); + } + else + { + var val = new byte[len]; + fixed (void* valPointer = val) + { + Unsafe.Write(valPointer, value); + int to = len >> 1, dest = len - 1; + for (var i = 0; i < to; i++) + { + var tmp = val[i]; + val[i] = val[dest]; + val[dest--] = tmp; + } + + return Unsafe.Read(valPointer); + } + } + } + + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs new file mode 100644 index 00000000..50b6fb79 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs @@ -0,0 +1,21 @@ +using Bedrock.Framework.Experimental.Infrastructure; +using Bedrock.Framework.Experimental.Protocols.Tls.Records; +using System.Net; +using System.Runtime.InteropServices; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers +{ + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct AdditionalInfo + { + private ulong _sequenceNumber; + private RecordType _recordType; + private TlsVersion _tlsVersion; + private ushort _plainTextLength; + + public ulong SequenceNumber { get => Endianness.FromNetworkOrder(_sequenceNumber); set => _sequenceNumber = Endianness.ToNetworkOrder(value); } + public RecordType RecordType { get => _recordType; set => _recordType = value; } + public TlsVersion TlsVersion { get => Endianness.FromNetworkOrder(_tlsVersion); set => _tlsVersion = Endianness.ToNetworkOrder(value); } + public ushort PlainTextLength { get => Endianness.FromNetworkOrder(_plainTextLength); set => _plainTextLength = Endianness.ToNetworkOrder(value); } + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmertricalCipher.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmertricalCipher.cs new file mode 100644 index 00000000..10e63259 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmertricalCipher.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers +{ + internal interface ISymmertricalCipher : IDisposable + { + Memory IV { get; } + int TagSize { get; } + void Init(KeyMode mode); + int Update(ReadOnlySpan input, Span output); + int Update(Span inOutput); + int Finish(Span inOuput); + int Finish(ReadOnlySpan input, Span output); + void AddAdditionalInfo(in AdditionalInfo addInfo); + void GetTag(Span tagOutput); + void SetTag(ReadOnlySpan tagInput); + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/Records/RecordType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/Records/RecordType.cs new file mode 100644 index 00000000..2f512a0e --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/Records/RecordType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.Records +{ + internal enum RecordType : byte + { + ChangeCipherSpec = 0x14, + Alert = 0x15, + Handshake = 0x16, + Application = 0x17, + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsVersion.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsVersion.cs new file mode 100644 index 00000000..2938edbc --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsVersion.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls +{ + public enum TlsVersion + { + Tls1 = 0x0301, + Tls11 = 0x0302, + Tls12 = 0x0303, + Tls13 = 0x0304, + } +} From 59432348be2fb36365968e387d218d9a81164e8c Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Thu, 16 Jan 2020 23:46:46 +0000 Subject: [PATCH 02/13] clean up reverse --- .../Infrastructure/Endianness.cs | 20 ++++--------------- .../Protocols/Tls/BulkCiphers/KeyMode.cs | 12 +++++++++++ 2 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/KeyMode.cs diff --git a/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs b/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs index 82db74fa..04aab5ef 100644 --- a/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs +++ b/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers.Binary; using System.Collections.Generic; using System.Runtime.CompilerServices; using System.Text; @@ -28,30 +29,17 @@ public static unsafe T Reverse(T value) where T : unmanaged } else if (len == 2) { - var val = Unsafe.Read(&value); - val = (ushort)((val >> 8) | (val << 8)); + var val = BinaryPrimitives.ReverseEndianness(Unsafe.As(ref value)); return Unsafe.Read(&val); } else if (len == 4) { - var val = Unsafe.Read(&value); - val = (val << 24) - | ((val & 0xFF00) << 8) - | ((val & 0xFF0000) >> 8) - | (val >> 24); + var val = BinaryPrimitives.ReverseEndianness(Unsafe.As(ref value)); return Unsafe.Read(&val); } else if (len == 8) { - var val = Unsafe.Read(&value); - val = (val << 56) - | ((val & 0xFF00) << 40) - | ((val & 0xFF0000) << 24) - | ((val & 0xFF000000) << 8) - | ((val & 0xFF00000000) >> 8) - | ((val & 0xFF0000000000) >> 24) - | ((val & 0xFF000000000000) >> 40) - | (val >> 56); + var val = BinaryPrimitives.ReverseEndianness(Unsafe.As(ref value)); return Unsafe.Read(&val); } else if (len < 512) diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/KeyMode.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/KeyMode.cs new file mode 100644 index 00000000..47ac8297 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/KeyMode.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers +{ + internal enum KeyMode + { + Encryption = 1, + Decryption = 0, + } +} From cbc3d81243031ab8581c7e0ab4c520d0a1e36506 Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Thu, 16 Jan 2020 23:50:55 +0000 Subject: [PATCH 03/13] Update to reduce unsafe surface area --- .../Infrastructure/Endianness.cs | 50 +++++++++++-------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs b/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs index 04aab5ef..a629eb19 100644 --- a/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs +++ b/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs @@ -20,9 +20,9 @@ public static unsafe T ToNetworkOrder(T value) where T : unmanaged return value; } - public static unsafe T Reverse(T value) where T : unmanaged + public static T Reverse(T value) where T : unmanaged { - var len = sizeof(T); + var len = Unsafe.SizeOf(); if (len == 1) { return value; @@ -30,37 +30,24 @@ public static unsafe T Reverse(T value) where T : unmanaged else if (len == 2) { var val = BinaryPrimitives.ReverseEndianness(Unsafe.As(ref value)); - return Unsafe.Read(&val); + return Unsafe.As(ref val); } else if (len == 4) { var val = BinaryPrimitives.ReverseEndianness(Unsafe.As(ref value)); - return Unsafe.Read(&val); + return Unsafe.As(ref val); } else if (len == 8) { var val = BinaryPrimitives.ReverseEndianness(Unsafe.As(ref value)); - return Unsafe.Read(&val); + return Unsafe.As(ref val); } else if (len < 512) { - var val = stackalloc byte[len]; - Unsafe.Write(val, value); - int to = len >> 1, dest = len - 1; - for (var i = 0; i < to; i++) + unsafe { - var tmp = val[i]; - val[i] = val[dest]; - val[dest--] = tmp; - } - return Unsafe.Read(val); - } - else - { - var val = new byte[len]; - fixed (void* valPointer = val) - { - Unsafe.Write(valPointer, value); + var val = stackalloc byte[len]; + Unsafe.Write(val, value); int to = len >> 1, dest = len - 1; for (var i = 0; i < to; i++) { @@ -68,8 +55,27 @@ public static unsafe T Reverse(T value) where T : unmanaged val[i] = val[dest]; val[dest--] = tmp; } + return Unsafe.Read(val); + } + } + else + { + var val = new byte[len]; + unsafe + { + fixed (void* valPointer = val) + { + Unsafe.Write(valPointer, value); + int to = len >> 1, dest = len - 1; + for (var i = 0; i < to; i++) + { + var tmp = val[i]; + val[i] = val[dest]; + val[dest--] = tmp; + } - return Unsafe.Read(valPointer); + return Unsafe.Read(valPointer); + } } } } From 5d1520c9f5b9af1c60886e37d72368ab0be1387e Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Fri, 17 Jan 2020 00:00:29 +0000 Subject: [PATCH 04/13] Fixed to using sizeof to reduce Jitter Size --- .../Infrastructure/Endianness.cs | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs b/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs index a629eb19..70ed3315 100644 --- a/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs +++ b/src/Bedrock.Framework.Experimental/Infrastructure/Endianness.cs @@ -20,65 +20,60 @@ public static unsafe T ToNetworkOrder(T value) where T : unmanaged return value; } - public static T Reverse(T value) where T : unmanaged + public static unsafe T Reverse(T value) where T : unmanaged { - var len = Unsafe.SizeOf(); - if (len == 1) + if (sizeof(T) == 1) { return value; } - else if (len == 2) + else if (sizeof(T) == 2) { var val = BinaryPrimitives.ReverseEndianness(Unsafe.As(ref value)); return Unsafe.As(ref val); } - else if (len == 4) + else if (sizeof(T) == 4) { var val = BinaryPrimitives.ReverseEndianness(Unsafe.As(ref value)); return Unsafe.As(ref val); } - else if (len == 8) + else if (sizeof(T) == 8) { var val = BinaryPrimitives.ReverseEndianness(Unsafe.As(ref value)); return Unsafe.As(ref val); } - else if (len < 512) + else if (sizeof(T) < 512) { - unsafe + var len = sizeof(T); + var val = stackalloc byte[len]; + Unsafe.Write(val, value); + int to = len >> 1, dest = len - 1; + for (var i = 0; i < to; i++) { - var val = stackalloc byte[len]; - Unsafe.Write(val, value); - int to = len >> 1, dest = len - 1; - for (var i = 0; i < to; i++) - { - var tmp = val[i]; - val[i] = val[dest]; - val[dest--] = tmp; - } - return Unsafe.Read(val); + var tmp = val[i]; + val[i] = val[dest]; + val[dest--] = tmp; } + return Unsafe.Read(val); } else { + var len = sizeof(T); var val = new byte[len]; - unsafe + + fixed (void* valPointer = val) { - fixed (void* valPointer = val) + Unsafe.Write(valPointer, value); + int to = len >> 1, dest = len - 1; + for (var i = 0; i < to; i++) { - Unsafe.Write(valPointer, value); - int to = len >> 1, dest = len - 1; - for (var i = 0; i < to; i++) - { - var tmp = val[i]; - val[i] = val[dest]; - val[dest--] = tmp; - } - - return Unsafe.Read(valPointer); + var tmp = val[i]; + val[i] = val[dest]; + val[dest--] = tmp; } + + return Unsafe.Read(valPointer); } } } - } } From 8040a57dab025a157e807fd8732635df8db607c8 Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Fri, 17 Jan 2020 00:17:18 +0000 Subject: [PATCH 05/13] Update to add the extra infra for the bulk ciphers --- .../Tls/BulkCiphers/AeadBulkCipher.cs | 64 +++++++++++++++++++ .../Tls/BulkCiphers/BulkCipherType.cs | 15 +++++ .../Tls/BulkCiphers/IBulkCipherKeyProvider.cs | 13 ++++ ...rtricalCipher.cs => ISymmetricalCipher.cs} | 2 +- 4 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AeadBulkCipher.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherType.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/IBulkCipherKeyProvider.cs rename src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/{ISymmertricalCipher.cs => ISymmetricalCipher.cs} (91%) diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AeadBulkCipher.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AeadBulkCipher.cs new file mode 100644 index 00000000..b6658513 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AeadBulkCipher.cs @@ -0,0 +1,64 @@ +using Bedrock.Framework.Experimental.Protocols.Tls.Records; +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO.Pipelines; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers +{ + internal abstract class AeadBulkCipher : IDisposable + { + protected const int AdditionalInfoHeaderSize = 13; + protected ulong _sequenceNumber; + protected ISymmetricalCipher _key; + + public int Overhead => _key.TagSize; + + public abstract void Decrypt(ref ReadOnlySequence messageBuffer, PipeWriter writer, RecordType recordType, TlsVersion tlsVersion); + public abstract void Encrypt(ref PipeWriter writer, ReadOnlySequence plainText, RecordType recordType, TlsVersion tlsVersion); + public void SetKey(ISymmetricalCipher key) => _key = key; + public virtual void IncrementSequence() => _sequenceNumber++; + + protected void WriteTag(ref PipeWriter writer) + { + var tagBuffer = writer.GetSpan(_key.TagSize); + _key.GetTag(tagBuffer.Slice(0, _key.TagSize)); + writer.Advance(_key.TagSize); + } + + protected void Decrypt(ref ReadOnlySequence messageBuffer, PipeWriter writer) + { + if (messageBuffer.IsSingleSegment) + { + var writeBuffer = writer.GetSpan(messageBuffer.FirstSpan.Length); + writer.Advance(_key.Finish(messageBuffer.FirstSpan, writeBuffer)); + IncrementSequence(); + return; + } + var bytesRemaining = messageBuffer.Length; + foreach (var b in messageBuffer) + { + if (b.Length == 0) continue; + var writeBuffer = writer.GetSpan(b.Length); + bytesRemaining -= b.Length; + if (bytesRemaining == 0) + { + writer.Advance(_key.Finish(b.Span, writeBuffer)); + break; + } + writer.Advance(_key.Update(b.Span,writeBuffer)); + } + IncrementSequence(); + } + + public void Dispose() + { + _key?.Dispose(); + _key = null; + GC.SuppressFinalize(this); + } + + ~AeadBulkCipher() => Dispose(); + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherType.cs new file mode 100644 index 00000000..f6f3c3c3 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherType.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers +{ + internal enum BulkCipherType + { + AES_128_GCM, + AES_256_GCM, + CHACHA20_POLY1305, + AES_128_CCM, + AES_128_CCM_8, + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/IBulkCipherKeyProvider.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/IBulkCipherKeyProvider.cs new file mode 100644 index 00000000..78a38cc8 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/IBulkCipherKeyProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers +{ + internal interface IBulkCipherKeyProvider : IDisposable + { + T GetCipher(BulkCipherType cipherType, ReadOnlyMemory keyStorage) where T : AeadBulkCipher, new(); + ISymmetricalCipher GetCipherKey(BulkCipherType cipherType, ReadOnlyMemory keyStorage); + (int keySize, int ivSize) GetCipherSize(BulkCipherType cipherType); + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmertricalCipher.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmetricalCipher.cs similarity index 91% rename from src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmertricalCipher.cs rename to src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmetricalCipher.cs index 10e63259..1b9b69e2 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmertricalCipher.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmetricalCipher.cs @@ -4,7 +4,7 @@ namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers { - internal interface ISymmertricalCipher : IDisposable + internal interface ISymmetricalCipher : IDisposable { Memory IV { get; } int TagSize { get; } From 05aa957b91e47c8f326f6368d1d08d8bc0ef4885 Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Fri, 17 Jan 2020 00:52:17 +0000 Subject: [PATCH 06/13] Better layout --- .../Tls/ApplicationLayerProtocolType.cs | 22 +++++++ .../Tls/BulkCiphers/AdditionalInfo.cs | 9 ++- .../Tls/BulkCiphers/AeadBulkCipher.cs | 64 ------------------- .../Protocols/Tls/BulkCiphers/BulkCipher.cs | 47 ++++++++++++++ .../Tls/BulkCiphers/BulkCipherKey.cs | 20 ++++++ .../{KeyMode.cs => BulkCipherKeyMode.cs} | 4 +- .../Tls/BulkCiphers/BulkCipherProvider.cs | 13 ++++ .../Tls/BulkCiphers/BulkCipherType.cs | 2 +- .../Tls/BulkCiphers/IBulkCipherKeyProvider.cs | 13 ---- .../Tls/BulkCiphers/ISymmetricalCipher.cs | 20 ------ .../Protocols/Tls/Certificates/Certificate.cs | 20 ++++++ .../Tls/Certificates/CertificateType.cs | 16 +++++ .../Tls/Certificates/SignatureScheme.cs | 30 +++++++++ .../Protocols/Tls/Hashs/Hash.cs | 27 ++++++++ .../Protocols/Tls/Hashs/HashProvider.cs | 13 ++++ .../Protocols/Tls/Hashs/HashType.cs | 14 ++++ .../Protocols/Tls/KeyExchanges/ECCurveType.cs | 14 ++++ .../Protocols/Tls/KeyExchanges/KeyExchange.cs | 28 ++++++++ .../Tls/KeyExchanges/KeyExchangeProvider.cs | 14 ++++ .../Tls/KeyExchanges/KeyExchangeType.cs | 13 ++++ .../Protocols/Tls/KeyExchanges/NamedGroup.cs | 29 +++++++++ .../Protocols/Tls/Records/RecordType.cs | 14 ---- .../Protocols/Tls/TlsFrameType.cs | 16 +++++ .../{TlsVersion.cs => TlsProtocolVersion.cs} | 7 +- 24 files changed, 348 insertions(+), 121 deletions(-) create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/ApplicationLayerProtocolType.cs delete mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AeadBulkCipher.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherKey.cs rename src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/{KeyMode.cs => BulkCipherKeyMode.cs} (78%) create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherProvider.cs delete mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/IBulkCipherKeyProvider.cs delete mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmetricalCipher.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/Certificate.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/CertificateType.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/SignatureScheme.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/Hash.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/HashProvider.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/HashType.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/ECCurveType.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchange.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchangeProvider.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchangeType.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/NamedGroup.cs delete mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/Records/RecordType.cs create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/TlsFrameType.cs rename src/Bedrock.Framework.Experimental/Protocols/Tls/{TlsVersion.cs => TlsProtocolVersion.cs} (57%) diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/ApplicationLayerProtocolType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/ApplicationLayerProtocolType.cs new file mode 100644 index 00000000..e981faeb --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/ApplicationLayerProtocolType.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls +{ + internal enum ApplicationLayerProtocolType + { + None = -1, + Http1_1 = 0, + Spdy1 = 1, + Spdy2 = 2, + Spdy3 = 3, + Turn = 4, + Stun = 5, + Http2_Tls = 6, + Http2_Tcp = 7, + WebRtc = 8, + Confidential_WebRtc = 9, + Ftp = 10 + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs index 50b6fb79..889c83cb 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs @@ -1,5 +1,4 @@ using Bedrock.Framework.Experimental.Infrastructure; -using Bedrock.Framework.Experimental.Protocols.Tls.Records; using System.Net; using System.Runtime.InteropServices; @@ -9,13 +8,13 @@ namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers internal struct AdditionalInfo { private ulong _sequenceNumber; - private RecordType _recordType; - private TlsVersion _tlsVersion; + private TlsFrameType _recordType; + private TlsProtocolVersion _tlsVersion; private ushort _plainTextLength; public ulong SequenceNumber { get => Endianness.FromNetworkOrder(_sequenceNumber); set => _sequenceNumber = Endianness.ToNetworkOrder(value); } - public RecordType RecordType { get => _recordType; set => _recordType = value; } - public TlsVersion TlsVersion { get => Endianness.FromNetworkOrder(_tlsVersion); set => _tlsVersion = Endianness.ToNetworkOrder(value); } + public TlsFrameType RecordType { get => _recordType; set => _recordType = value; } + public TlsProtocolVersion TlsVersion { get => Endianness.FromNetworkOrder(_tlsVersion); set => _tlsVersion = Endianness.ToNetworkOrder(value); } public ushort PlainTextLength { get => Endianness.FromNetworkOrder(_plainTextLength); set => _plainTextLength = Endianness.ToNetworkOrder(value); } } } diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AeadBulkCipher.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AeadBulkCipher.cs deleted file mode 100644 index b6658513..00000000 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AeadBulkCipher.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Bedrock.Framework.Experimental.Protocols.Tls.Records; -using System; -using System.Buffers; -using System.Collections.Generic; -using System.IO.Pipelines; -using System.Text; - -namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers -{ - internal abstract class AeadBulkCipher : IDisposable - { - protected const int AdditionalInfoHeaderSize = 13; - protected ulong _sequenceNumber; - protected ISymmetricalCipher _key; - - public int Overhead => _key.TagSize; - - public abstract void Decrypt(ref ReadOnlySequence messageBuffer, PipeWriter writer, RecordType recordType, TlsVersion tlsVersion); - public abstract void Encrypt(ref PipeWriter writer, ReadOnlySequence plainText, RecordType recordType, TlsVersion tlsVersion); - public void SetKey(ISymmetricalCipher key) => _key = key; - public virtual void IncrementSequence() => _sequenceNumber++; - - protected void WriteTag(ref PipeWriter writer) - { - var tagBuffer = writer.GetSpan(_key.TagSize); - _key.GetTag(tagBuffer.Slice(0, _key.TagSize)); - writer.Advance(_key.TagSize); - } - - protected void Decrypt(ref ReadOnlySequence messageBuffer, PipeWriter writer) - { - if (messageBuffer.IsSingleSegment) - { - var writeBuffer = writer.GetSpan(messageBuffer.FirstSpan.Length); - writer.Advance(_key.Finish(messageBuffer.FirstSpan, writeBuffer)); - IncrementSequence(); - return; - } - var bytesRemaining = messageBuffer.Length; - foreach (var b in messageBuffer) - { - if (b.Length == 0) continue; - var writeBuffer = writer.GetSpan(b.Length); - bytesRemaining -= b.Length; - if (bytesRemaining == 0) - { - writer.Advance(_key.Finish(b.Span, writeBuffer)); - break; - } - writer.Advance(_key.Update(b.Span,writeBuffer)); - } - IncrementSequence(); - } - - public void Dispose() - { - _key?.Dispose(); - _key = null; - GC.SuppressFinalize(this); - } - - ~AeadBulkCipher() => Dispose(); - } -} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs new file mode 100644 index 00000000..3db3f125 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs @@ -0,0 +1,47 @@ +using System; +using System.Buffers; +using System.Collections.Generic; +using System.IO.Pipelines; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers +{ + internal abstract class BulkCipher : IDisposable + { + protected const int AdditionalInfoHeaderSize = 13; + protected ulong _sequenceNumber; + protected BulkCipherKey _key; + protected int _blockShifter; + + public int Overhead => _key.TagSize + sizeof(ulong); + + public abstract void Decrypt(PipeWriter pipeWriter, ReadOnlySequence cipherText, TlsFrameType recordType, TlsProtocolVersion tlsVersion); + public abstract void Encrypt(PipeWriter pipeWriter, ReadOnlySpan plainText, TlsFrameType recordType); + public abstract void Encrypt(PipeWriter pipeWriter, ReadOnlySequence plainText, TlsFrameType recordType); + + public void SetKey(BulkCipherKey key) + { + _key = key; + _blockShifter = (int)Math.Log(_key.BlockSize, 2); + } + + public virtual void IncrementSequence() => _sequenceNumber++; + + protected int WriteTag(ref PipeWriter writer) + { + var span = writer.GetSpan(_key.TagSize); + _key.GetTag(span); + writer.Advance(span.Length); + return _key.TagSize; + } + + public void Dispose() + { + _key?.Dispose(); + _key = null; + GC.SuppressFinalize(this); + } + + ~BulkCipher() => Dispose(); + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherKey.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherKey.cs new file mode 100644 index 00000000..66e39543 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherKey.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers +{ + internal abstract class BulkCipherKey : IDisposable + { + public abstract Memory IV { get; } + public abstract int BlockSize { get; } + public abstract int TagSize { get; } + public abstract void Init(KeyMode mode); + public abstract int Update(ReadOnlySpan input, Span output); + public abstract int Finish(ReadOnlySpan input, Span output); + public abstract void AddAdditionalInfo(ref AdditionalInfo addInfo); + public abstract int GetTag(Span span); + public abstract void SetTag(ReadOnlySpan tagSpan); + public abstract void Dispose(); + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/KeyMode.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherKeyMode.cs similarity index 78% rename from src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/KeyMode.cs rename to src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherKeyMode.cs index 47ac8297..6f31c9a3 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/KeyMode.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherKeyMode.cs @@ -6,7 +6,7 @@ namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers { internal enum KeyMode { - Encryption = 1, - Decryption = 0, + Encrypt = 1, + Decrypt = 0, } } diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherProvider.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherProvider.cs new file mode 100644 index 00000000..c5a6528c --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers +{ + internal abstract class BulkCipherProvider + { + public abstract BulkCipher GetCipher(BulkCipherType cipherType, Memory keyStorage) where T : BulkCipher, new(); + public abstract BulkCipherKey GetCipherKey(BulkCipherType cipherType, Memory keyStorage); + public abstract (int keySize, int ivSize) GetCipherSize(BulkCipherType cipherType); + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherType.cs index f6f3c3c3..a5cda1e7 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherType.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherType.cs @@ -4,7 +4,7 @@ namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers { - internal enum BulkCipherType + enum BulkCipherType { AES_128_GCM, AES_256_GCM, diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/IBulkCipherKeyProvider.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/IBulkCipherKeyProvider.cs deleted file mode 100644 index 78a38cc8..00000000 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/IBulkCipherKeyProvider.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers -{ - internal interface IBulkCipherKeyProvider : IDisposable - { - T GetCipher(BulkCipherType cipherType, ReadOnlyMemory keyStorage) where T : AeadBulkCipher, new(); - ISymmetricalCipher GetCipherKey(BulkCipherType cipherType, ReadOnlyMemory keyStorage); - (int keySize, int ivSize) GetCipherSize(BulkCipherType cipherType); - } -} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmetricalCipher.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmetricalCipher.cs deleted file mode 100644 index 1b9b69e2..00000000 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/ISymmetricalCipher.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers -{ - internal interface ISymmetricalCipher : IDisposable - { - Memory IV { get; } - int TagSize { get; } - void Init(KeyMode mode); - int Update(ReadOnlySpan input, Span output); - int Update(Span inOutput); - int Finish(Span inOuput); - int Finish(ReadOnlySpan input, Span output); - void AddAdditionalInfo(in AdditionalInfo addInfo); - void GetTag(Span tagOutput); - void SetTag(ReadOnlySpan tagInput); - } -} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/Certificate.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/Certificate.cs new file mode 100644 index 00000000..c2289665 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/Certificate.cs @@ -0,0 +1,20 @@ +using Bedrock.Framework.Experimental.Protocols.Tls.Hashs; +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.Certificates +{ + internal abstract class Certificate + { + public abstract CertificateType CertificateType { get; } + public abstract byte[] CertificateData { get; } + public abstract byte[][] CertificateChain { get; } + public abstract int SignatureSize { get; } + public abstract SignatureScheme SelectAlgorithm(ReadOnlySequence buffer); + public abstract bool SupportsScheme(SignatureScheme scheme); + internal abstract int SignHash(HashProvider provider, SignatureScheme scheme, Span message, Span output); + public abstract int Decrypt(SignatureScheme scheme, ReadOnlySpan encryptedData, Span output); + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/CertificateType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/CertificateType.cs new file mode 100644 index 00000000..6f394c4c --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/CertificateType.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.Certificates +{ + //https://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-16 + //TLS SignatureAlgorithm Registry + internal enum CertificateType + { + anonymous = 0, + rsa = 1, + dsa = 2, + ecdsa = 3, + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/SignatureScheme.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/SignatureScheme.cs new file mode 100644 index 00000000..0f2c44ac --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/SignatureScheme.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.Certificates +{ + internal enum SignatureScheme : ushort + { + none = 0, + /* RSASSA-PKCS1-v1_5 algorithms */ + rsa_pkcs1_sha1 = 0x0201, + rsa_pkcs1_sha256 = 0x0401, + rsa_pkcs1_sha384 = 0x0501, + rsa_pkcs1_sha512 = 0x0601, + + /* ECDSA algorithms */ + ecdsa_secp256r1_sha256 = 0x0403, + ecdsa_secp384r1_sha384 = 0x0503, + ecdsa_secp521r1_sha512 = 0x0603, + + /* RSASSA-PSS algorithms */ + rsa_pss_sha256 = 0x0804, + rsa_pss_sha384 = 0x0805, + rsa_pss_sha512 = 0x0806, + + /* EdDSA algorithms */ + ed25519 = 0x0807, + ed448 = 0x0808, + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/Hash.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/Hash.cs new file mode 100644 index 00000000..3f9e6685 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/Hash.cs @@ -0,0 +1,27 @@ +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.Hashs +{ + internal abstract class Hash + { + public abstract void HashData(ReadOnlySpan data); + public abstract int HashSize { get; } + public abstract int InterimHash(Span output); + public abstract int Finish(Span output); + public abstract HashType HashType { get; } + + public void HashData(SequenceReader reader) + { + while (!reader.End) + { + HashData(reader.CurrentSpan); + reader.Advance(reader.CurrentSpan.Length); + } + } + + public void HashData(ReadOnlySequence sequence) => HashData(new SequenceReader(sequence)); + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/HashProvider.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/HashProvider.cs new file mode 100644 index 00000000..818e54be --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/HashProvider.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.Hashs +{ + internal abstract class HashProvider + { + public abstract int HashSize(HashType hashType); + public abstract Hash GetHash(HashType hashType); + public abstract void HmacData(HashType hashType, ReadOnlySpan key, ReadOnlySpan message, Span result); + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/HashType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/HashType.cs new file mode 100644 index 00000000..9a3275b2 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/Hashs/HashType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.Hashs +{ + //Numbers from https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 + internal enum HashType : byte + { + SHA256 = 4, + SHA384 = 5, + SHA512 = 6, + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/ECCurveType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/ECCurveType.cs new file mode 100644 index 00000000..2ca64044 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/ECCurveType.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.KeyExchanges +{ + //http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml + internal enum ECCurveType : byte + { + explicit_prime = 1, + explicit_char2 = 2, + named_curve = 3, + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchange.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchange.cs new file mode 100644 index 00000000..e4c9f615 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchange.cs @@ -0,0 +1,28 @@ +using Bedrock.Framework.Experimental.Protocols.Tls.Certificates; +using Bedrock.Framework.Experimental.Protocols.Tls.Hashs; +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.KeyExchanges +{ + internal abstract class KeyExchange : IDisposable + { + public abstract bool RequiresServerKeyExchange { get; } + public abstract void SetPeerKey(ReadOnlySequence peerKey, Certificate certificate, SignatureScheme scheme); + public abstract void SetPeerKey(ReadOnlySequence sharedKey); + public abstract int KeyExchangeSize { get; } + public abstract int WritePublicKey(Span keyBuffer); + public abstract NamedGroup NamedGroup { get; } + public abstract void DeriveSecret(HashProvider hashProvider, HashType hashType, ReadOnlySpan salt, Span output); + public abstract void DeriveMasterSecret(HashProvider hashProvider, HashType hashType, ReadOnlySpan seed, Span output); + public abstract void Dispose(); + + public void SetPeerKey(SequenceReader peerKey, Certificate certificate, SignatureScheme scheme) + { + var buffer = peerKey.Sequence.Slice(peerKey.Position); + SetPeerKey(buffer, certificate, scheme); + } + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchangeProvider.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchangeProvider.cs new file mode 100644 index 00000000..59759293 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchangeProvider.cs @@ -0,0 +1,14 @@ +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.KeyExchanges +{ + internal abstract class KeyExchangeProvider + { + public abstract KeyExchange GetKeyExchange(KeyExchangeType keyExchange, ReadOnlySequence supportedGroups); + public abstract KeyExchange GetKeyExchangeFromKeyShareExtension(ReadOnlySequence keyShare); + public abstract KeyExchange GetKeyExchangeFromSupportedGroups(ReadOnlySequence supportedGroups); + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchangeType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchangeType.cs new file mode 100644 index 00000000..fc0b7288 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchangeType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.KeyExchanges +{ + internal enum KeyExchangeType + { + Rsa, + Ecdhe, + Dhe + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/NamedGroup.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/NamedGroup.cs new file mode 100644 index 00000000..b3e4528c --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/NamedGroup.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls.KeyExchanges +{ + //http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml + // + internal enum NamedGroup : ushort + { + None = 0, + + /* Elliptic Curve Groups (ECDHE) */ + secp256r1 = 0x0017, + secp384r1 = 0x0018, + secp521r1 = 0x0019, + + /* Elliptic curve functions */ + x25519 = 0x001D, + x448 = 0x001E, + + /* Finite Field Groups (DHE) */ + ffdhe2048 = 0x0100, + ffdhe3072 = 0x0101, + ffdhe4096 = 0x0102, + ffdhe6144 = 0x0103, + ffdhe8192 = 0x0104, + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/Records/RecordType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/Records/RecordType.cs deleted file mode 100644 index 2f512a0e..00000000 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/Records/RecordType.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Bedrock.Framework.Experimental.Protocols.Tls.Records -{ - internal enum RecordType : byte - { - ChangeCipherSpec = 0x14, - Alert = 0x15, - Handshake = 0x16, - Application = 0x17, - } -} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsFrameType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsFrameType.cs new file mode 100644 index 00000000..c8cd86d0 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsFrameType.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls +{ + internal enum TlsFrameType : byte + { + ChangeCipherSpec = 20, + Alert = 21, + Handshake = 22, + AppData = 23, + Invalid = 255, + Incomplete = 0, + } +} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsVersion.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsProtocolVersion.cs similarity index 57% rename from src/Bedrock.Framework.Experimental/Protocols/Tls/TlsVersion.cs rename to src/Bedrock.Framework.Experimental/Protocols/Tls/TlsProtocolVersion.cs index 2938edbc..12f07400 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsVersion.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsProtocolVersion.cs @@ -4,11 +4,14 @@ namespace Bedrock.Framework.Experimental.Protocols.Tls { - public enum TlsVersion + public enum TlsProtocolVersion : ushort { - Tls1 = 0x0301, + Ssl3 = 0x0301, Tls11 = 0x0302, Tls12 = 0x0303, Tls13 = 0x0304, + Tls13Draft18 = 0x7f12, + Tls13Draft22 = 0x7f16, + Tls13Draft23 = 0x7f17, } } From 7a81a179b5d4c8193013e98f7f68adf0bfc7654d Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Fri, 17 Jan 2020 18:29:43 +0000 Subject: [PATCH 07/13] Move to use IBufferWriter in BulkCipher --- .../Protocols/Tls/BulkCiphers/BulkCipher.cs | 8 ++++---- .../Protocols/Tls/BulkCiphers/BulkCipherProvider.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs index 3db3f125..affaec19 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs @@ -15,9 +15,9 @@ internal abstract class BulkCipher : IDisposable public int Overhead => _key.TagSize + sizeof(ulong); - public abstract void Decrypt(PipeWriter pipeWriter, ReadOnlySequence cipherText, TlsFrameType recordType, TlsProtocolVersion tlsVersion); - public abstract void Encrypt(PipeWriter pipeWriter, ReadOnlySpan plainText, TlsFrameType recordType); - public abstract void Encrypt(PipeWriter pipeWriter, ReadOnlySequence plainText, TlsFrameType recordType); + public abstract void Decrypt(IBufferWriter pipeWriter, ReadOnlySequence cipherText, TlsFrameType recordType, TlsProtocolVersion tlsVersion); + public abstract void Encrypt(IBufferWriter pipeWriter, ReadOnlySpan plainText, TlsFrameType recordType); + public abstract void Encrypt(IBufferWriter pipeWriter, ReadOnlySequence plainText, TlsFrameType recordType); public void SetKey(BulkCipherKey key) { @@ -27,7 +27,7 @@ public void SetKey(BulkCipherKey key) public virtual void IncrementSequence() => _sequenceNumber++; - protected int WriteTag(ref PipeWriter writer) + protected int WriteTag(IBufferWriter writer) { var span = writer.GetSpan(_key.TagSize); _key.GetTag(span); diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherProvider.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherProvider.cs index c5a6528c..a3ecaf60 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherProvider.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipherProvider.cs @@ -6,7 +6,7 @@ namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers { internal abstract class BulkCipherProvider { - public abstract BulkCipher GetCipher(BulkCipherType cipherType, Memory keyStorage) where T : BulkCipher, new(); + public abstract BulkCipher GetCipher(BulkCipherType cipherType, ReadOnlyMemory keyStorage) where T : BulkCipher, new(); public abstract BulkCipherKey GetCipherKey(BulkCipherType cipherType, Memory keyStorage); public abstract (int keySize, int ivSize) GetCipherSize(BulkCipherType cipherType); } From 187b867b704d86fffc19ed5d6b00346bf3faaa11 Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Fri, 17 Jan 2020 20:29:42 +0000 Subject: [PATCH 08/13] Add IANA ref for ALPN --- .../Protocols/Tls/ApplicationLayerProtocolType.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/ApplicationLayerProtocolType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/ApplicationLayerProtocolType.cs index e981faeb..6958b8bd 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/ApplicationLayerProtocolType.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/ApplicationLayerProtocolType.cs @@ -4,6 +4,7 @@ namespace Bedrock.Framework.Experimental.Protocols.Tls { + // from IANA registry https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids internal enum ApplicationLayerProtocolType { None = -1, From fa2a437aed54978ff659247ec863e9ba07ba013c Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Fri, 17 Jan 2020 20:34:13 +0000 Subject: [PATCH 09/13] Updated to change frametype to record type and add ref to RFC --- .../Protocols/Tls/BulkCiphers/AdditionalInfo.cs | 4 ++-- .../Protocols/Tls/BulkCiphers/BulkCipher.cs | 6 +++--- .../Protocols/Tls/TlsFrameType.cs | 16 ---------------- 3 files changed, 5 insertions(+), 21 deletions(-) delete mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/TlsFrameType.cs diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs index 889c83cb..0aee5bfa 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/AdditionalInfo.cs @@ -8,12 +8,12 @@ namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers internal struct AdditionalInfo { private ulong _sequenceNumber; - private TlsFrameType _recordType; + private TlsRecordType _recordType; private TlsProtocolVersion _tlsVersion; private ushort _plainTextLength; public ulong SequenceNumber { get => Endianness.FromNetworkOrder(_sequenceNumber); set => _sequenceNumber = Endianness.ToNetworkOrder(value); } - public TlsFrameType RecordType { get => _recordType; set => _recordType = value; } + public TlsRecordType RecordType { get => _recordType; set => _recordType = value; } public TlsProtocolVersion TlsVersion { get => Endianness.FromNetworkOrder(_tlsVersion); set => _tlsVersion = Endianness.ToNetworkOrder(value); } public ushort PlainTextLength { get => Endianness.FromNetworkOrder(_plainTextLength); set => _plainTextLength = Endianness.ToNetworkOrder(value); } } diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs index affaec19..0540e93c 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs @@ -15,9 +15,9 @@ internal abstract class BulkCipher : IDisposable public int Overhead => _key.TagSize + sizeof(ulong); - public abstract void Decrypt(IBufferWriter pipeWriter, ReadOnlySequence cipherText, TlsFrameType recordType, TlsProtocolVersion tlsVersion); - public abstract void Encrypt(IBufferWriter pipeWriter, ReadOnlySpan plainText, TlsFrameType recordType); - public abstract void Encrypt(IBufferWriter pipeWriter, ReadOnlySequence plainText, TlsFrameType recordType); + public abstract void Decrypt(IBufferWriter pipeWriter, ReadOnlySequence cipherText, TlsRecordType recordType, TlsProtocolVersion tlsVersion); + public abstract void Encrypt(IBufferWriter pipeWriter, ReadOnlySpan plainText, TlsRecordType recordType); + public abstract void Encrypt(IBufferWriter pipeWriter, ReadOnlySequence plainText, TlsRecordType recordType); public void SetKey(BulkCipherKey key) { diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsFrameType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsFrameType.cs deleted file mode 100644 index c8cd86d0..00000000 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsFrameType.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Bedrock.Framework.Experimental.Protocols.Tls -{ - internal enum TlsFrameType : byte - { - ChangeCipherSpec = 20, - Alert = 21, - Handshake = 22, - AppData = 23, - Invalid = 255, - Incomplete = 0, - } -} From 557164e9326084c13dcbb19040fd8fe5b51ef791 Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Fri, 17 Jan 2020 20:44:58 +0000 Subject: [PATCH 10/13] Fix for rename --- .../Protocols/Tls/TlsRecordType.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/TlsRecordType.cs diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsRecordType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsRecordType.cs new file mode 100644 index 00000000..83a99911 --- /dev/null +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/TlsRecordType.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Bedrock.Framework.Experimental.Protocols.Tls +{ + // From RFC 8446 Appendix B.1 https://tools.ietf.org/html/rfc8446#appendix-B.1 + internal enum TlsRecordType : byte + { + ChangeCipherSpec = 20, + Alert = 21, + Handshake = 22, + AppData = 23, + Invalid = 255, + Incomplete = 0, + } +} From cbfa9ab0d1566444574e3f4dcd9e37c5d7baac74 Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Sat, 18 Jan 2020 10:54:23 +0000 Subject: [PATCH 11/13] Removed custom certificate --- .../Protocols/Tls/Certificates/Certificate.cs | 20 ------------------- .../Protocols/Tls/KeyExchanges/KeyExchange.cs | 5 +++-- 2 files changed, 3 insertions(+), 22 deletions(-) delete mode 100644 src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/Certificate.cs diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/Certificate.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/Certificate.cs deleted file mode 100644 index c2289665..00000000 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/Certificate.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Bedrock.Framework.Experimental.Protocols.Tls.Hashs; -using System; -using System.Buffers; -using System.Collections.Generic; -using System.Text; - -namespace Bedrock.Framework.Experimental.Protocols.Tls.Certificates -{ - internal abstract class Certificate - { - public abstract CertificateType CertificateType { get; } - public abstract byte[] CertificateData { get; } - public abstract byte[][] CertificateChain { get; } - public abstract int SignatureSize { get; } - public abstract SignatureScheme SelectAlgorithm(ReadOnlySequence buffer); - public abstract bool SupportsScheme(SignatureScheme scheme); - internal abstract int SignHash(HashProvider provider, SignatureScheme scheme, Span message, Span output); - public abstract int Decrypt(SignatureScheme scheme, ReadOnlySpan encryptedData, Span output); - } -} diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchange.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchange.cs index e4c9f615..70e8bdf0 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchange.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/KeyExchanges/KeyExchange.cs @@ -3,6 +3,7 @@ using System; using System.Buffers; using System.Collections.Generic; +using System.Security.Cryptography.X509Certificates; using System.Text; namespace Bedrock.Framework.Experimental.Protocols.Tls.KeyExchanges @@ -10,7 +11,7 @@ namespace Bedrock.Framework.Experimental.Protocols.Tls.KeyExchanges internal abstract class KeyExchange : IDisposable { public abstract bool RequiresServerKeyExchange { get; } - public abstract void SetPeerKey(ReadOnlySequence peerKey, Certificate certificate, SignatureScheme scheme); + public abstract void SetPeerKey(ReadOnlySequence peerKey, X509Certificate2 certificate, SignatureScheme scheme); public abstract void SetPeerKey(ReadOnlySequence sharedKey); public abstract int KeyExchangeSize { get; } public abstract int WritePublicKey(Span keyBuffer); @@ -19,7 +20,7 @@ internal abstract class KeyExchange : IDisposable public abstract void DeriveMasterSecret(HashProvider hashProvider, HashType hashType, ReadOnlySpan seed, Span output); public abstract void Dispose(); - public void SetPeerKey(SequenceReader peerKey, Certificate certificate, SignatureScheme scheme) + public void SetPeerKey(SequenceReader peerKey, X509Certificate2 certificate, SignatureScheme scheme) { var buffer = peerKey.Sequence.Slice(peerKey.Position); SetPeerKey(buffer, certificate, scheme); From 53caa4f1d1625253cda6894f4a4ac397c307c38a Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Sat, 18 Jan 2020 21:14:29 +0000 Subject: [PATCH 12/13] Casing --- .../Protocols/Tls/Certificates/CertificateType.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/CertificateType.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/CertificateType.cs index 6f394c4c..9811e757 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/CertificateType.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/Certificates/CertificateType.cs @@ -8,9 +8,9 @@ namespace Bedrock.Framework.Experimental.Protocols.Tls.Certificates //TLS SignatureAlgorithm Registry internal enum CertificateType { - anonymous = 0, - rsa = 1, - dsa = 2, - ecdsa = 3, + Anonymous = 0, + Rsa = 1, + Dsa = 2, + Ecdsa = 3, } } From 75347638a97d06c8bcf99f563ec978c16a8fa4f2 Mon Sep 17 00:00:00 2001 From: Tim Seaward Date: Sat, 18 Jan 2020 22:30:12 +0000 Subject: [PATCH 13/13] Removed usings --- .../Protocols/Tls/BulkCiphers/BulkCipher.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs index 0540e93c..deef9ba9 100644 --- a/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs +++ b/src/Bedrock.Framework.Experimental/Protocols/Tls/BulkCiphers/BulkCipher.cs @@ -1,8 +1,5 @@ using System; using System.Buffers; -using System.Collections.Generic; -using System.IO.Pipelines; -using System.Text; namespace Bedrock.Framework.Experimental.Protocols.Tls.BulkCiphers {