diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 2aba11b..0000000 --- a/.editorconfig +++ /dev/null @@ -1,8 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 4 - -[Makefile] -indent_style = tab \ No newline at end of file diff --git a/.gitignore b/.gitignore index 144cfbc..f287a27 100644 --- a/.gitignore +++ b/.gitignore @@ -244,3 +244,5 @@ ModelManifest.xml # FAKE - F# Make .fake/ +/TestClient/*.user +/TestServer/*.user diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16da8a6..e3ddd13 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,8 +1,3 @@ - -![](doc/img.png) - ----- - # DTLS.Net contributor guide. @@ -10,7 +5,7 @@ If you discover a bug, or find an issue or area that you feel needs improvement: -* Navigate to the "Issues" tab on the project Github page https://github.com/CreatorDev/DTLS.Net/issues +* Navigate to the "Issues" tab on the project Github page https://github.com/kmiller77/DTLS.Net/issues * Click the "New Issue" button. @@ -83,7 +78,7 @@ Use the same email address that you used to sign up for your github account. ### Forking the repository. If you want to contribute to the project the best practice is to create a fork. To do so -navigate to *https://github.com/CreatorDev/DTLS.Net* and click on the *fork* button at the top right of the +navigate to https://github.com/kmiller77/DTLS.Net and click on the *fork* button at the top right of the screen. If you are a member of multiple organisations you will be presented with a selection screen which can be used to select where to create the fork. Click on your user account to create the fork. @@ -129,9 +124,6 @@ $ git checkout master -b dev-branch1 --track Once you have created your branch make your changes, then commit them to your new branch. -### Coding style. - -The DTLS.Net coding style guidelines can be found in the [coding style guide](doc/coding_style.md). ### Commit messages. diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 3f43964..56a51b4 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -1,3 +1,3 @@ Delme Thomas Tony Walsworth documentation - +Krissy Miller \ No newline at end of file diff --git a/DTLS.Net.sln b/DTLS.Net.sln index bba8748..2e92c8f 100644 --- a/DTLS.Net.sln +++ b/DTLS.Net.sln @@ -1,22 +1,15 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29509.3 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F03FE972-A21E-403E-B93F-28CA681083E3}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DTLS.Net", "DTLS.Net\DTLS.Net.csproj", "{B409CE38-996F-4D15-B336-FD1BAA5A7CC9}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{52BB0453-16F8-412F-AC41-A588994757CA}" - ProjectSection(SolutionItems) = preProject - global.json = global.json - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestClient", "TestClient\TestClient.csproj", "{2F493C3D-E4F0-4578-A3A9-42B7F6356915}" EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "DTLS.Net", "src\DTLS.Net\DTLS.Net.xproj", "{6D15ED53-D821-4909-8318-859D1F98F1DA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestServer", "TestServer\TestServer.csproj", "{0A1FB939-36AF-472E-9D7F-6555D3EF9BE4}" EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{296FC660-E501-4920-8F34-ADB6B9BCE099}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestServer", "test\TestServer\TestServer.xproj", "{A5380CE2-6DA3-44D2-B495-AF167CEF7520}" -EndProject -Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "TestClient", "test\TestClient\TestClient.xproj", "{EF71B497-E9D0-41D1-AEED-49F5532A4524}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetSnmpTestClient", "NetSnmpTestClient\NetSnmpTestClient.csproj", "{E9BD3CF2-8F1A-45D0-A7E2-B793B8F6A52A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -24,25 +17,27 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6D15ED53-D821-4909-8318-859D1F98F1DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6D15ED53-D821-4909-8318-859D1F98F1DA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6D15ED53-D821-4909-8318-859D1F98F1DA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6D15ED53-D821-4909-8318-859D1F98F1DA}.Release|Any CPU.Build.0 = Release|Any CPU - {A5380CE2-6DA3-44D2-B495-AF167CEF7520}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A5380CE2-6DA3-44D2-B495-AF167CEF7520}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A5380CE2-6DA3-44D2-B495-AF167CEF7520}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A5380CE2-6DA3-44D2-B495-AF167CEF7520}.Release|Any CPU.Build.0 = Release|Any CPU - {EF71B497-E9D0-41D1-AEED-49F5532A4524}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {EF71B497-E9D0-41D1-AEED-49F5532A4524}.Debug|Any CPU.Build.0 = Debug|Any CPU - {EF71B497-E9D0-41D1-AEED-49F5532A4524}.Release|Any CPU.ActiveCfg = Release|Any CPU - {EF71B497-E9D0-41D1-AEED-49F5532A4524}.Release|Any CPU.Build.0 = Release|Any CPU + {B409CE38-996F-4D15-B336-FD1BAA5A7CC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B409CE38-996F-4D15-B336-FD1BAA5A7CC9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B409CE38-996F-4D15-B336-FD1BAA5A7CC9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B409CE38-996F-4D15-B336-FD1BAA5A7CC9}.Release|Any CPU.Build.0 = Release|Any CPU + {2F493C3D-E4F0-4578-A3A9-42B7F6356915}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2F493C3D-E4F0-4578-A3A9-42B7F6356915}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2F493C3D-E4F0-4578-A3A9-42B7F6356915}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2F493C3D-E4F0-4578-A3A9-42B7F6356915}.Release|Any CPU.Build.0 = Release|Any CPU + {0A1FB939-36AF-472E-9D7F-6555D3EF9BE4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0A1FB939-36AF-472E-9D7F-6555D3EF9BE4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0A1FB939-36AF-472E-9D7F-6555D3EF9BE4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0A1FB939-36AF-472E-9D7F-6555D3EF9BE4}.Release|Any CPU.Build.0 = Release|Any CPU + {E9BD3CF2-8F1A-45D0-A7E2-B793B8F6A52A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E9BD3CF2-8F1A-45D0-A7E2-B793B8F6A52A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E9BD3CF2-8F1A-45D0-A7E2-B793B8F6A52A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E9BD3CF2-8F1A-45D0-A7E2-B793B8F6A52A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {6D15ED53-D821-4909-8318-859D1F98F1DA} = {F03FE972-A21E-403E-B93F-28CA681083E3} - {A5380CE2-6DA3-44D2-B495-AF167CEF7520} = {296FC660-E501-4920-8F34-ADB6B9BCE099} - {EF71B497-E9D0-41D1-AEED-49F5532A4524} = {296FC660-E501-4920-8F34-ADB6B9BCE099} + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {25A91A6B-0909-4602-9D97-CCAD8DD48A4D} EndGlobalSection EndGlobal diff --git a/src/DTLS.Net/Certificates/CertificateInfo.cs b/DTLS.Net/Certificates/CertificateInfo.cs similarity index 92% rename from src/DTLS.Net/Certificates/CertificateInfo.cs rename to DTLS.Net/Certificates/CertificateInfo.cs index 9a23111..7c16361 100644 --- a/src/DTLS.Net/Certificates/CertificateInfo.cs +++ b/DTLS.Net/Certificates/CertificateInfo.cs @@ -20,11 +20,6 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - namespace DTLS { public class CertificateInfo @@ -35,10 +30,6 @@ public class CertificateInfo public object PrivateKey { get; set; } - public CertificateInfo() - { - - } - + public CertificateInfo() { } } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/Certificates/CertificateSubject.cs b/DTLS.Net/Certificates/CertificateSubject.cs similarity index 80% rename from src/DTLS.Net/Certificates/CertificateSubject.cs rename to DTLS.Net/Certificates/CertificateSubject.cs index bd28f56..ebf03d0 100644 --- a/src/DTLS.Net/Certificates/CertificateSubject.cs +++ b/DTLS.Net/Certificates/CertificateSubject.cs @@ -22,10 +22,6 @@ products derived from this software without specific prior written permission. using Org.BouncyCastle.Asn1.X509; using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace DTLS { @@ -43,42 +39,44 @@ public class CertificateSubject public string Country { get; set; } - public CertificateSubject() - { - - } + public CertificateSubject() { } internal CertificateSubject(X509CertificateStructure cert) { - IList ids = cert.Subject.GetOidList(); - IList values = cert.Subject.GetValueList(); - for (int index = 0; index < ids.Count; index++) + if (cert == null) + { + throw new ArgumentNullException(nameof(cert)); + } + + var ids = cert.Subject.GetOidList(); + var values = cert.Subject.GetValueList(); + for (var index = 0; index < ids.Count; index++) { if (X509Name.CN.Equals(ids[index])) { - CommonName = (string)values[index]; + this.CommonName = (string)values[index]; } else if (X509Name.O.Equals(ids[index])) { - Organistion = (string)values[index]; + this.Organistion = (string)values[index]; } else if (X509Name.OU.Equals(ids[index])) { - OrganistionUnit = (string)values[index]; + this.OrganistionUnit = (string)values[index]; } else if (X509Name.L.Equals(ids[index])) { - Location = (string)values[index]; + this.Location = (string)values[index]; } else if (X509Name.ST.Equals(ids[index])) { - State = (string)values[index]; + this.State = (string)values[index]; } else if (X509Name.C.Equals(ids[index])) { - Country = (string)values[index]; + this.Country = (string)values[index]; } } - } + } } } diff --git a/DTLS.Net/Certificates/Certificates.cs b/DTLS.Net/Certificates/Certificates.cs new file mode 100644 index 0000000..bc8bae0 --- /dev/null +++ b/DTLS.Net/Certificates/Certificates.cs @@ -0,0 +1,518 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Pkcs; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Asn1.X509; +using Org.BouncyCastle.Asn1.X9; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Generators; +using Org.BouncyCastle.Crypto.Operators; +using Org.BouncyCastle.Crypto.Parameters; +using Org.BouncyCastle.Crypto.Prng; +using Org.BouncyCastle.Math; +using Org.BouncyCastle.OpenSsl; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using Org.BouncyCastle.X509; +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace DTLS +{ + public static class Certificates + { + + private static void AddStandardCertificateInfo(X509V3CertificateGenerator certificateGenerator, SecureRandom random, + CertificateSubject subject, CertificateSubject issuer, DateTime startDate, DateTime expiryDate) + { + if (certificateGenerator == null) + { + throw new ArgumentNullException(nameof(certificateGenerator)); + } + + if (random == null) + { + throw new ArgumentNullException(nameof(random)); + } + + if (subject == null) + { + throw new ArgumentNullException(nameof(subject)); + } + + if (issuer == null) + { + throw new ArgumentNullException(nameof(issuer)); + } + + var serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); + certificateGenerator.SetSerialNumber(serialNumber); + + certificateGenerator.SetIssuerDN(GetName(issuer)); + certificateGenerator.SetSubjectDN(GetName(subject)); + + certificateGenerator.SetNotBefore(startDate); + certificateGenerator.SetNotAfter(expiryDate); + } + + private static byte[] ExportCertificate(X509Certificate certificate, AsymmetricCipherKeyPair subjectKeyPair, TCertificateFormat certificateFormat) + { + if (certificate == null) + { + throw new ArgumentNullException(nameof(certificate)); + } + + if (subjectKeyPair == null) + { + throw new ArgumentNullException(nameof(subjectKeyPair)); + } + + byte[] result = null; + switch (certificateFormat) + { + case TCertificateFormat.NotSet: + { + break; + } + case TCertificateFormat.PEM: + { + using (var stream = new MemoryStream()) + { + using (var writer = new StreamWriter(stream)) + { + var pemWriter = new PemWriter(writer); + if (subjectKeyPair.Private is ECKeyParameters) + { + var priv = (ECPrivateKeyParameters)subjectKeyPair.Private; + var dp = priv.Parameters; + var orderBitLength = dp.N.BitLength; + ECPrivateKeyStructure ec; + X962Parameters x962; + if (priv.PublicKeyParamSet == null) + { + var ecP = new X9ECParameters(dp.Curve, dp.G, dp.N, dp.H, dp.GetSeed()); + x962 = new X962Parameters(ecP); + } + else + { + x962 = new X962Parameters(priv.PublicKeyParamSet); + } + ec = new ECPrivateKeyStructure(orderBitLength, priv.D, SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public).PublicKeyData, x962); + pemWriter.WriteObject(new Org.BouncyCastle.Utilities.IO.Pem.PemObject("EC PRIVATE KEY", ec.GetEncoded())); + } + else + { + pemWriter.WriteObject(new MiscPemGenerator(subjectKeyPair.Private)); + } + pemWriter.WriteObject(new MiscPemGenerator(subjectKeyPair.Public)); + pemWriter.WriteObject(new MiscPemGenerator(certificate)); + writer.Flush(); + result = stream.ToArray(); + } + } + } + break; + case TCertificateFormat.PFX: + { + //Asn1Sequence asn1Sequence = Asn1Sequence.GetInstance(Asn1Object.FromByteArray(certificate.GetEncoded())); + //asn1Sequence.GetObjects + //Org.BouncyCastle.Asn1.Pkcs.Pfx pfx = new Org.BouncyCastle.Asn1.Pkcs.Pfx(); + //Org.BouncyCastle.Asn1.Pkcs.PrivateKeyInfo info = Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private); + //result = pfx.GetEncoded(Asn1Encodable.Der); + break; + } + case TCertificateFormat.CER: + { + result = certificate.GetEncoded(); + break; + } + default: + { + break; + } + } + return result; + } + + private static AsymmetricCipherKeyPair GenerateKeys(X509V3CertificateGenerator certificateGenerator, SecureRandom random, + SignatureHashAlgorithm signatureAlgorithm) + { + if (certificateGenerator == null) + { + throw new ArgumentNullException(nameof(certificateGenerator)); + } + + if (random == null) + { + throw new ArgumentNullException(nameof(random)); + } + + if (signatureAlgorithm == null) + { + throw new ArgumentNullException(nameof(signatureAlgorithm)); + } + + AsymmetricCipherKeyPair result = null; + switch (signatureAlgorithm.Signature) + { + case TSignatureAlgorithm.Anonymous: + { + break; + } + case TSignatureAlgorithm.RSA: + { + var keyGenerationParameters = new KeyGenerationParameters(random, 2048); + var rsaKeyPairGenerator = new RsaKeyPairGenerator(); + rsaKeyPairGenerator.Init(keyGenerationParameters); + result = rsaKeyPairGenerator.GenerateKeyPair(); + break; + } + case TSignatureAlgorithm.DSA: + { + break; + } + case TSignatureAlgorithm.ECDSA: + { + //ECDomainParameters ellipticCurveParameters = EllipticCurveFactory.GetEllipticCurveParameters(TEllipticCurve.secp256r1); + var keyPairGenerator = new ECKeyPairGenerator(); + //keyPairGenerator.Init(new ECKeyGenerationParameters(ellipticCurveParameters, random)); + keyPairGenerator.Init(new ECKeyGenerationParameters(SecObjectIdentifiers.SecP256r1, random)); + result = keyPairGenerator.GenerateKeyPair(); + //certificateGenerator.AddExtension(X509Extensions.SubjectPublicKeyInfo) + //PrivateKey = (ECPrivateKeyParameters)keys.Private; + //PublicKey = (ECPublicKeyParameters)keys.Public; + break; + } + default: + { + break; + } + } + + certificateGenerator.SetPublicKey(result.Public); + return result; + } + + public static byte[] GenerateCertificate(CertificateSubject subject, CertificateInfo issuer, DateTime startDate, + DateTime expiryDate, SignatureHashAlgorithm signatureAlgorithm, TCertificateFormat certificateFormat) + { + if (subject == null) + { + throw new ArgumentNullException(nameof(subject)); + } + + if (issuer == null) + { + throw new ArgumentNullException(nameof(issuer)); + } + + if (signatureAlgorithm == null) + { + throw new ArgumentNullException(nameof(issuer)); + } + + if (!(issuer.PrivateKey is AsymmetricKeyParameter privateKey)) + { + return null; + } + + var randomGenerator = new CryptoApiRandomGenerator(); + var random = new SecureRandom(randomGenerator); + var certificateGenerator = new X509V3CertificateGenerator(); + AddStandardCertificateInfo(certificateGenerator, random, subject, issuer.Subject, startDate, expiryDate); + var subjectKeyPair = GenerateKeys(certificateGenerator, random, signatureAlgorithm); + + var algorithm = GetAlgorithm(signatureAlgorithm); + + certificateGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false)); + certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment)); + certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, false, new ExtendedKeyUsage(new KeyPurposeID[] { KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPClientAuth })); + var subjectKeyID = new byte[20]; + random.NextBytes(subjectKeyID, 0, 20); + certificateGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(subjectKeyID)); + if (issuer.SubjectKeyID != null) + { + certificateGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifier(issuer.SubjectKeyID)); + } + + //if ((subject.AlternativeNames != null) && (subject.AlternativeNames.Count > 0)) + //{ + // certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName, true, new SubjectAlternativeNames(false)); + // //SubjectAlternativeName + // //GeneralName.DirectoryName + // //GeneralName.IPAddress + //} + + var certificate = certificateGenerator.Generate(new Asn1SignatureFactory(algorithm, privateKey, random)); + return ExportCertificate(certificate, subjectKeyPair, certificateFormat); + } + + public static byte[] GenerateIntermediateCACertificate(CertificateSubject subject, CertificateInfo issuer, DateTime startDate, + DateTime expiryDate, SignatureHashAlgorithm signatureAlgorithm, TCertificateFormat certificateFormat) + { + if (subject == null) + { + throw new ArgumentNullException(nameof(subject)); + } + + if (issuer == null) + { + throw new ArgumentNullException(nameof(issuer)); + } + + if (signatureAlgorithm == null) + { + throw new ArgumentNullException(nameof(signatureAlgorithm)); + } + + if (!(issuer.PrivateKey is AsymmetricKeyParameter privateKey)) + { + return null; + } + + var randomGenerator = new CryptoApiRandomGenerator(); + var random = new SecureRandom(randomGenerator); + var certificateGenerator = new X509V3CertificateGenerator(); + AddStandardCertificateInfo(certificateGenerator, random, subject, issuer.Subject, startDate, expiryDate); + var subjectKeyPair = GenerateKeys(certificateGenerator, random, signatureAlgorithm); + + certificateGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(0)); + certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyCertSign)); + var subjectKeyID = new byte[20]; + random.NextBytes(subjectKeyID, 0, 20); + certificateGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(subjectKeyID)); + if (issuer.SubjectKeyID != null) + { + certificateGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifier(issuer.SubjectKeyID)); + } + + var algorithm = GetAlgorithm(signatureAlgorithm); + + var certificate = certificateGenerator.Generate(new Asn1SignatureFactory(algorithm, privateKey, random)); + + return ExportCertificate(certificate, subjectKeyPair, certificateFormat); + } + + public static byte[] GenerateRootCACertificate(CertificateSubject subject, DateTime startDate, DateTime expiryDate, + SignatureHashAlgorithm signatureAlgorithm, TCertificateFormat certificateFormat) + { + if (subject == null) + { + throw new ArgumentNullException(nameof(subject)); + } + + if (signatureAlgorithm == null) + { + throw new ArgumentNullException(nameof(signatureAlgorithm)); + } + + var randomGenerator = new CryptoApiRandomGenerator(); + var random = new SecureRandom(randomGenerator); + var certificateGenerator = new X509V3CertificateGenerator(); + AddStandardCertificateInfo(certificateGenerator, random, subject, subject, startDate, expiryDate); + var subjectKeyPair = GenerateKeys(certificateGenerator, random, signatureAlgorithm); + + certificateGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true)); + certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyCertSign)); + var subjectKeyID = new byte[20]; + random.NextBytes(subjectKeyID, 0, 20); + certificateGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(subjectKeyID)); + certificateGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifier(subjectKeyID)); + + var algorithm = GetAlgorithm(signatureAlgorithm); + // selfsign certificate + var certificate = certificateGenerator.Generate(new Asn1SignatureFactory(algorithm, subjectKeyPair.Private, random)); + + return ExportCertificate(certificate, subjectKeyPair, certificateFormat); + } + + private static string GetAlgorithm(SignatureHashAlgorithm signatureAlgorithm) + { + if (signatureAlgorithm == null) + { + throw new ArgumentNullException(nameof(signatureAlgorithm)); + } + + // eg "SHA256WithRSA", "SHA224WithECDSA",; + var result = new StringBuilder(); + result.Append(signatureAlgorithm.Hash.ToString()); + result.Append("With"); + result.Append(signatureAlgorithm.Signature.ToString()); + return result.ToString(); + } + + public static CertificateInfo GetCertificateInfo(byte[] certificate, TCertificateFormat certificateFormat) + { + if (certificate == null) + { + throw new ArgumentNullException(nameof(certificate)); + } + + CertificateInfo result = null; + X509CertificateStructure cert = null; + switch (certificateFormat) + { + case TCertificateFormat.NotSet: + { + break; + } + case TCertificateFormat.PEM: + { + var reader = new PemReader(new StreamReader(new MemoryStream(certificate))); + var pem = reader.ReadPemObject(); + while (pem != null) + { + if (pem.Type.EndsWith("CERTIFICATE")) + { + cert = X509CertificateStructure.GetInstance(pem.Content); + } + else if (pem.Type.EndsWith("PRIVATE KEY")) + { + if (result == null) + { + result = new CertificateInfo(); + } + + result.PrivateKey = GetPrivateKeyFromPEM(pem); + } + pem = reader.ReadPemObject(); + } + break; + } + case TCertificateFormat.PFX: + { + break; + } + case TCertificateFormat.CER: + { + cert = X509CertificateStructure.GetInstance(certificate); + break; + } + default: + { + break; + } + } + + if (cert != null) + { + if (result == null) + { + result = new CertificateInfo(); + } + + result.Subject = new CertificateSubject(cert); + var certX509 = new X509Certificate(cert); + var subjectKeyID = certX509.GetExtensionValue(X509Extensions.SubjectKeyIdentifier); + if (subjectKeyID != null) + { + var encodeKeyID = subjectKeyID.GetOctets(); + var keyID = new byte[encodeKeyID[1]]; + Buffer.BlockCopy(encodeKeyID, 2, keyID, 0, encodeKeyID[1]); + result.SubjectKeyID = keyID; + } + } + return result; + } + + private static X509Name GetName(CertificateSubject info) + { + if (info == null) + { + throw new ArgumentNullException(nameof(info)); + } + + var ids = new List(); + var values = new List(); + if (!string.IsNullOrEmpty(info.CommonName)) + { + ids.Add(X509Name.CN); + values.Add(info.CommonName); + } + if (!string.IsNullOrEmpty(info.Organistion)) + { + ids.Add(X509Name.O); + values.Add(info.Organistion); + } + if (!string.IsNullOrEmpty(info.OrganistionUnit)) + { + ids.Add(X509Name.OU); + values.Add(info.OrganistionUnit); + } + if (!string.IsNullOrEmpty(info.Location)) + { + ids.Add(X509Name.L); + values.Add(info.Location); + } + if (!string.IsNullOrEmpty(info.State)) + { + ids.Add(X509Name.ST); + values.Add(info.State); + } + if (!string.IsNullOrEmpty(info.Country)) + { + ids.Add(X509Name.C); + values.Add(info.Country); + } + return new X509Name(ids, values); + } + + internal static AsymmetricKeyParameter GetPrivateKeyFromPEM(Org.BouncyCastle.Utilities.IO.Pem.PemObject pem) + { + if (pem == null) + { + throw new ArgumentNullException(nameof(pem)); + } + + if (pem.Type.EndsWith("EC PRIVATE KEY")) + { + var sequence = Asn1Sequence.GetInstance(pem.Content); + var e = sequence.GetEnumerator(); + e.MoveNext(); + var version = ((DerInteger)e.Current).Value; + PrivateKeyInfo privateKeyInfo; + if (version.IntValue == 0) //V1 + { + privateKeyInfo = PrivateKeyInfo.GetInstance(sequence); + } + else + { + var ec = ECPrivateKeyStructure.GetInstance(sequence); + var algId = new AlgorithmIdentifier(X9ObjectIdentifiers.IdECPublicKey, ec.GetParameters()); + privateKeyInfo = new PrivateKeyInfo(algId, ec.ToAsn1Object()); + } + return PrivateKeyFactory.CreateKey(privateKeyInfo); + } + else if (pem.Type.EndsWith("PRIVATE KEY")) + { + return PrivateKeyFactory.CreateKey(pem.Content); + } + + return null; + } + + } +} diff --git a/src/DTLS.Net/Certificates/TCertificateFormat.cs b/DTLS.Net/Certificates/TCertificateFormat.cs similarity index 95% rename from src/DTLS.Net/Certificates/TCertificateFormat.cs rename to DTLS.Net/Certificates/TCertificateFormat.cs index a6312f5..1186c44 100644 --- a/src/DTLS.Net/Certificates/TCertificateFormat.cs +++ b/DTLS.Net/Certificates/TCertificateFormat.cs @@ -20,10 +20,6 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; namespace DTLS { diff --git a/DTLS.Net/CipherSuite/CipherSuites.cs b/DTLS.Net/CipherSuite/CipherSuites.cs new file mode 100644 index 0000000..346e57a --- /dev/null +++ b/DTLS.Net/CipherSuite/CipherSuites.cs @@ -0,0 +1,153 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using Org.BouncyCastle.Crypto; +using System; +using System.Collections.Generic; + +namespace DTLS +{ + internal class CipherSuites + { + private class CipherSuite + { + public TCipherSuite Suite { get; set; } + public TKeyExchangeAlgorithm KeyExchangeAlgorithm { get; set; } + //public TEncryptionAlgorithm EncryptionAlgorithm { get; set; } + public TSignatureAlgorithm SignatureAlgorithm { get; set; } + public Version MinVersion { get; set; } + public TPseudorandomFunction PRF { get; set; } + + public CipherSuite(TCipherSuite cipherSuite, TKeyExchangeAlgorithm keyExchangeAlgorithm, + TSignatureAlgorithm signatureAlgorithm, Version minVersion, TPseudorandomFunction prf) + { + this.Suite = cipherSuite; + this.KeyExchangeAlgorithm = keyExchangeAlgorithm; + this.SignatureAlgorithm = signatureAlgorithm; + this.MinVersion = minVersion ?? throw new ArgumentNullException(nameof(minVersion)); + this.PRF = prf; + } + } + + private static Dictionary _CipherSuites; + + static CipherSuites() => + _CipherSuites = new Dictionary + { + { TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, new CipherSuite(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, TKeyExchangeAlgorithm.ECDHE_ECDSA, TSignatureAlgorithm.ECDSA, DTLSRecord.Version1_2, TPseudorandomFunction.SHA256) }, + { TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, new CipherSuite(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TKeyExchangeAlgorithm.ECDHE_ECDSA, TSignatureAlgorithm.ECDSA, DTLSRecord.Version1_0, TPseudorandomFunction.SHA256) }, + { TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8, new CipherSuite(TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8, TKeyExchangeAlgorithm.PSK, TSignatureAlgorithm.Anonymous, DTLSRecord.Version1_2, TPseudorandomFunction.SHA256) }, + { TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256, new CipherSuite(TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256, TKeyExchangeAlgorithm.PSK, TSignatureAlgorithm.Anonymous, DTLSRecord.Version1_0, TPseudorandomFunction.SHA256) }, + { TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, new CipherSuite(TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, TKeyExchangeAlgorithm.ECDHE_PSK, TSignatureAlgorithm.Anonymous, DTLSRecord.Version1_0, TPseudorandomFunction.SHA256) }, + { TCipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, new CipherSuite(TCipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA, TKeyExchangeAlgorithm.RSA, TSignatureAlgorithm.Anonymous, DTLSRecord.Version1_0, TPseudorandomFunction.SHA256) } + }; + + + public static TKeyExchangeAlgorithm GetKeyExchangeAlgorithm(TCipherSuite cipherSuite) + { + if (_CipherSuites.TryGetValue(cipherSuite, out var suite)) + { + return suite.KeyExchangeAlgorithm; + } + + return TKeyExchangeAlgorithm.NotSet; + } + + public static TPseudorandomFunction GetPseudorandomFunction(Version version, TCipherSuite cipherSuite) + { + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + if (version < DTLSRecord.Version1_2) + { + return TPseudorandomFunction.Legacy; + } + + if (_CipherSuites.TryGetValue(cipherSuite, out var suite)) + { + return suite.PRF; + } + + throw new Exception($"Pseudorandom Function {cipherSuite} not found"); + } + + public static TSignatureAlgorithm GetSignatureAlgorithm(TCipherSuite cipherSuite) + { + if (_CipherSuites.TryGetValue(cipherSuite, out var suite)) + { + return suite.SignatureAlgorithm; + } + + return TSignatureAlgorithm.Anonymous; + } + + public static bool SuiteUsable(TCipherSuite cipherSuite, AsymmetricKeyParameter privateKey, PSKIdentities pskIdentities, bool haveValidatePSKCallback) + { + var result = false; + var keyExchangeAlgorithm = GetKeyExchangeAlgorithm(cipherSuite); + switch (keyExchangeAlgorithm) + { + case TKeyExchangeAlgorithm.NotSet: + { + break; + } + case TKeyExchangeAlgorithm.PSK: + case TKeyExchangeAlgorithm.ECDHE_PSK: + { + result = haveValidatePSKCallback || ((pskIdentities != null) && (pskIdentities.Count > 0)); + break; + } + case TKeyExchangeAlgorithm.ECDH_ECDSA: + case TKeyExchangeAlgorithm.ECDHE_ECDSA: + { + result = (privateKey != null); + break; + } + default: + { + break; + } + } + return result; + } + + public static bool SupportedVersion(TCipherSuite cipherSuite, Version version) + { + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + if (_CipherSuites.TryGetValue(cipherSuite, out var suite)) + { + return suite.MinVersion <= version; + } + return false; + } + + + + + } +} diff --git a/src/DTLS.Net/CipherSuite/SignatureHashAlgorithm.cs b/DTLS.Net/CipherSuite/SignatureHashAlgorithm.cs similarity index 91% rename from src/DTLS.Net/CipherSuite/SignatureHashAlgorithm.cs rename to DTLS.Net/CipherSuite/SignatureHashAlgorithm.cs index f731bfb..32284d4 100644 --- a/src/DTLS.Net/CipherSuite/SignatureHashAlgorithm.cs +++ b/DTLS.Net/CipherSuite/SignatureHashAlgorithm.cs @@ -20,18 +20,14 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { public class SignatureHashAlgorithm - { - public THashAlgorithm Hash { get; set; } + { + public THashAlgorithm Hash { get; set; } - public TSignatureAlgorithm Signature { get; set; } + public TSignatureAlgorithm Signature { get; set; } - } + } } diff --git a/DTLS.Net/CipherSuite/TCipherSuite.cs b/DTLS.Net/CipherSuite/TCipherSuite.cs new file mode 100644 index 0000000..43c5df1 --- /dev/null +++ b/DTLS.Net/CipherSuite/TCipherSuite.cs @@ -0,0 +1,78 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + + +namespace DTLS +{ + public enum TCipherSuite + { + TLS_NULL_WITH_NULL_NULL = 0, + + TLS_RSA_WITH_NULL_MD5 = 0x01, + TLS_RSA_WITH_NULL_SHA = 0x02, + TLS_RSA_WITH_NULL_SHA256 = 0x3B, + TLS_RSA_WITH_RC4_128_MD5 = 0x04, + TLS_RSA_WITH_RC4_128_SHA = 0x05, + TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x0A, + TLS_RSA_WITH_AES_128_CBC_SHA = 0x2F, + TLS_RSA_WITH_AES_256_CBC_SHA = 0x35, + TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x3C, + TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x3D, + + TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x0D, + TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x10, + TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x13, + TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x16, + TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x30, + TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x31, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x32, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x33, + TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x36, + TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x37, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x38, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x39, + TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x3E, + TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x3F, + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x40, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x67, + TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x68, + TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x69, + TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x6A, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x6B, + + TLS_DH_anon_WITH_RC4_128_MD5 = 0x18, + TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x1B, + TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x34, + TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x3A, + TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x6C, + TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x6D, + + TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023, + TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8, + TLS_PSK_WITH_AES_128_CBC_SHA256 = 0xAE, + TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037 + + } +} + + diff --git a/src/DTLS.Net/CipherSuite/THashAlgorithm.cs b/DTLS.Net/CipherSuite/THashAlgorithm.cs similarity index 91% rename from src/DTLS.Net/CipherSuite/THashAlgorithm.cs rename to DTLS.Net/CipherSuite/THashAlgorithm.cs index a148543..9575ab2 100644 --- a/src/DTLS.Net/CipherSuite/THashAlgorithm.cs +++ b/DTLS.Net/CipherSuite/THashAlgorithm.cs @@ -20,10 +20,6 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { @@ -33,13 +29,13 @@ namespace DTLS // sha512(6), (255) //} HashAlgorithm; public enum THashAlgorithm - { - None = 0, - MD5 = 1, - SHA1 = 2, - SHA224 = 3, - SHA256 = 4, - SHA384 = 5, - SHA512 = 6 - } + { + None = 0, + MD5 = 1, + SHA1 = 2, + SHA224 = 3, + SHA256 = 4, + SHA384 = 5, + SHA512 = 6 + } } diff --git a/src/DTLS.Net/CipherSuite/TKeyExchangeAlgorithm.cs b/DTLS.Net/CipherSuite/TKeyExchangeAlgorithm.cs similarity index 89% rename from src/DTLS.Net/CipherSuite/TKeyExchangeAlgorithm.cs rename to DTLS.Net/CipherSuite/TKeyExchangeAlgorithm.cs index e9eee68..004c1c0 100644 --- a/src/DTLS.Net/CipherSuite/TKeyExchangeAlgorithm.cs +++ b/DTLS.Net/CipherSuite/TKeyExchangeAlgorithm.cs @@ -20,24 +20,20 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - // enum { rsa, diffie_hellman } KeyExchangeAlgorithm; + // enum { rsa, diffie_hellman } KeyExchangeAlgorithm; internal enum TKeyExchangeAlgorithm - { - NotSet, - //RSA, - //DiffieHellman - PSK, - ECDH_ECDSA, + { + NotSet, + RSA, + //DiffieHellman + PSK, + ECDH_ECDSA, ECDHE_ECDSA, - ECDHE_PSK + ECDHE_PSK - } + } } diff --git a/src/DTLS.Net/CipherSuite/TPseudorandomFunction.cs b/DTLS.Net/CipherSuite/TPseudorandomFunction.cs similarity index 94% rename from src/DTLS.Net/CipherSuite/TPseudorandomFunction.cs rename to DTLS.Net/CipherSuite/TPseudorandomFunction.cs index 4c4b163..79846f6 100644 --- a/src/DTLS.Net/CipherSuite/TPseudorandomFunction.cs +++ b/DTLS.Net/CipherSuite/TPseudorandomFunction.cs @@ -20,10 +20,6 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { @@ -31,7 +27,7 @@ internal enum TPseudorandomFunction { NotSet = 0, Legacy = 1, - SHA256 =2, + SHA256 = 2, SHA384 = 3, } } diff --git a/src/DTLS.Net/CipherSuite/TSignatureAlgorithm.cs b/DTLS.Net/CipherSuite/TSignatureAlgorithm.cs similarity index 93% rename from src/DTLS.Net/CipherSuite/TSignatureAlgorithm.cs rename to DTLS.Net/CipherSuite/TSignatureAlgorithm.cs index 63fb740..7ffa537 100644 --- a/src/DTLS.Net/CipherSuite/TSignatureAlgorithm.cs +++ b/DTLS.Net/CipherSuite/TSignatureAlgorithm.cs @@ -20,20 +20,16 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { //enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } // SignatureAlgorithm; public enum TSignatureAlgorithm - { - Anonymous = 0, - RSA = 1, - DSA = 2, - ECDSA = 3 - } + { + Anonymous = 0, + RSA = 1, + DSA = 2, + ECDSA = 3 + } } diff --git a/DTLS.Net/Client.cs b/DTLS.Net/Client.cs new file mode 100644 index 0000000..17c141e --- /dev/null +++ b/DTLS.Net/Client.cs @@ -0,0 +1,1127 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using DTLS.Net; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Tls; +using Org.BouncyCastle.Utilities.IO.Pem; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Threading; +using System.Threading.Tasks; + +namespace DTLS +{ + public class Client : IDisposable +#if NET6_0_OR_GREATER + , IAsyncDisposable +#endif + { + private static readonly Version _SupportedVersion = DTLSRecord.Version1_2; + private readonly HandshakeInfo _HandshakeInfo = new(); + private readonly DTLSRecords _Records = new(); + private readonly List _FragmentedRecordList = []; + private readonly CancellationTokenSource _Cts = new(); + + //The maximum safe UDP payload is 508 bytes. Except on an IPv6-only route, where the maximum payload is 1,212 bytes. + //https://stackoverflow.com/questions/1098897/what-is-the-largest-safe-udp-packet-size-on-the-internet#:~:text=The%20maximum%20safe%20UDP%20payload%20is%20508%20bytes.&text=Except%20on%20an%20IPv6%2Donly,bytes%20may%20be%20preferred%20instead. + private static int _MaxPacketSize = 1212; + [System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Need to hold onto the task so it's not GC'd")] + private Task _ReceiveTask; + [System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "Need to hold onto the task so it's not GC'd")] + private Task _ProcessRecordTask; + private Action _DataReceivedFunction; + private Socket _Socket; + private bool _Terminate; + private EndPoint _ServerEndPoint; + private ushort? _ServerEpoch; + private long _ServerSequenceNumber; + private ushort? _EncyptedServerEpoch; + private ushort _Epoch; + private ushort _MessageSequence; + private TlsCipher _Cipher; + private Version _Version = _SupportedVersion; + private bool _SendCertificate; + private IHandshakeMessage _ClientKeyExchange; + private Certificate _Certificate; + private AsymmetricKeyParameter _PrivateKey; + private PSKIdentity _PSKIdentity; + + private byte[] _ReceivedData = []; + private byte[] _RecvDataBuffer = []; + private bool _IsFragment = false; + private bool _ConnectionComplete = false; + private bool _Disposed = false; + private long _SequenceNumber = -1; //really only 48 bit + + public EndPoint LocalEndPoint { get; } + + public PSKIdentities PSKIdentities { get; } + + public List SupportedCipherSuites { get; } + public byte[] ServerCertificate { get; set; } + + private CngKey _PrivateKeyRsa; + public CngKey PublicKey { get; set; } + + public Client(EndPoint localEndPoint) + : this(localEndPoint, []) + { + SupportedCipherSuites = []; + if (localEndPoint.AddressFamily != AddressFamily.InterNetworkV6) + { + _MaxPacketSize = 508; + } + } + + public Client(EndPoint localEndPoint, List supportedCipherSuites) + { + LocalEndPoint = localEndPoint ?? throw new ArgumentNullException(nameof(localEndPoint)); + SupportedCipherSuites = supportedCipherSuites ?? throw new ArgumentNullException(nameof(supportedCipherSuites)); + PSKIdentities = new PSKIdentities(); + _HandshakeInfo.ClientRandom = new RandomData(); + _HandshakeInfo.ClientRandom.Generate(); + } + + private void ChangeEpoch() + { + ++_Epoch; + _SequenceNumber = -1; + } + + private long NextSequenceNumber() => ++_SequenceNumber; + + private async Task ProcessHandshakeAsync(DTLSRecord record) + { + if (record == null) + { + throw new ArgumentNullException(nameof(record)); + } + + var data = record.Fragment; + if (_EncyptedServerEpoch == record.Epoch) + { + var count = 0; + while ((_Cipher == null) && (count < 500)) + { + await Task.Delay(10).ConfigureAwait(false); + count++; + } + + if (_Cipher == null) + { + throw new Exception("Need Cipher for Encrypted Session"); + } + + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + data = _Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); + } + + using (var tempStream = new MemoryStream(data)) + { + var handshakeRec = HandshakeRecord.Deserialise(tempStream); + if (handshakeRec.Length > (handshakeRec.FragmentLength + handshakeRec.FragmentOffset)) + { + _IsFragment = true; + _FragmentedRecordList.Add(data); + return; + } + else if (_IsFragment) + { + _FragmentedRecordList.Add(data); + data = []; + foreach (var rec in _FragmentedRecordList) + { + data = [.. data, .. rec.Skip(HandshakeRecord.RECORD_OVERHEAD)]; + } + + var tempHandshakeRec = new HandshakeRecord() + { + Length = handshakeRec.Length, + MessageSeq = handshakeRec.MessageSeq, + MessageType = handshakeRec.MessageType, + FragmentLength = handshakeRec.Length, + FragmentOffset = 0 + }; + + var tempHandshakeBytes = new byte[HandshakeRecord.RECORD_OVERHEAD]; + using (var updateStream = new MemoryStream(tempHandshakeBytes)) + { + tempHandshakeRec.Serialise(updateStream); + } + + data = [.. tempHandshakeBytes, .. data]; + } + } + + using (var stream = new MemoryStream(data)) + { + var handshakeRecord = HandshakeRecord.Deserialise(stream); + switch (handshakeRecord.MessageType) + { + case THandshakeType.HelloRequest: + { + break; + } + case THandshakeType.ClientHello: + { + break; + } + case THandshakeType.ServerHello: + { + var serverHello = ServerHello.Deserialise(stream); + _HandshakeInfo.UpdateHandshakeHash(data); + _ServerEpoch = record.Epoch; + _HandshakeInfo.CipherSuite = (TCipherSuite)serverHello.CipherSuite; + _HandshakeInfo.Extensions = serverHello.Extensions; + _HandshakeInfo.ServerRandom = serverHello.Random; + _Version = serverHello.ServerVersion <= _Version ? serverHello.ServerVersion : _SupportedVersion; + break; + } + case THandshakeType.HelloVerifyRequest: + { + var helloVerifyRequest = HelloVerifyRequest.Deserialise(stream); + _Version = helloVerifyRequest.ServerVersion; + await SendHelloAsync(helloVerifyRequest.Cookie).ConfigureAwait(false); + break; + } + case THandshakeType.Certificate: + { + var cert = Certificate.Deserialise(stream, TCertificateType.X509); + _HandshakeInfo.UpdateHandshakeHash(data); + ServerCertificate = cert.Cert; + break; + } + case THandshakeType.ServerKeyExchange: + { + _HandshakeInfo.UpdateHandshakeHash(data); + var keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(_HandshakeInfo.CipherSuite); + byte[] preMasterSecret = null; + IKeyExchange keyExchange = null; + if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) + { + var serverKeyExchange = ECDHEServerKeyExchange.Deserialise(stream, _Version); + var keyExchangeECDHE = new ECDHEKeyExchange + { + CipherSuite = _HandshakeInfo.CipherSuite, + Curve = serverKeyExchange.EllipticCurve, + KeyExchangeAlgorithm = keyExchangeAlgorithm, + ClientRandom = _HandshakeInfo.ClientRandom, + ServerRandom = _HandshakeInfo.ServerRandom + }; + keyExchangeECDHE.GenerateEphemeralKey(); + var clientKeyExchange = new ECDHEClientKeyExchange(keyExchangeECDHE.PublicKey); + _ClientKeyExchange = clientKeyExchange; + preMasterSecret = keyExchangeECDHE.GetPreMasterSecret(serverKeyExchange.PublicKeyBytes); + keyExchange = keyExchangeECDHE; + } + else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK) + { + var serverKeyExchange = ECDHEPSKServerKeyExchange.Deserialise(stream); + var keyExchangeECDHE = new ECDHEKeyExchange + { + CipherSuite = _HandshakeInfo.CipherSuite, + Curve = serverKeyExchange.EllipticCurve, + KeyExchangeAlgorithm = keyExchangeAlgorithm, + ClientRandom = _HandshakeInfo.ClientRandom, + ServerRandom = _HandshakeInfo.ServerRandom + }; + keyExchangeECDHE.GenerateEphemeralKey(); + var clientKeyExchange = new ECDHEPSKClientKeyExchange(keyExchangeECDHE.PublicKey); + if (serverKeyExchange.PSKIdentityHint != null) + { + var key = PSKIdentities.GetKey(serverKeyExchange.PSKIdentityHint); + if (key != null) + { + _PSKIdentity = new PSKIdentity() { Identity = serverKeyExchange.PSKIdentityHint, Key = key }; + } + } + _PSKIdentity ??= PSKIdentities.GetRandom(); + + clientKeyExchange.PSKIdentity = _PSKIdentity.Identity; + _ClientKeyExchange = clientKeyExchange; + var otherSecret = keyExchangeECDHE.GetPreMasterSecret(serverKeyExchange.PublicKeyBytes); + preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key); + keyExchange = keyExchangeECDHE; + } + else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK) + { + var serverKeyExchange = PSKServerKeyExchange.Deserialise(stream); + var clientKeyExchange = new PSKClientKeyExchange(); + if (serverKeyExchange.PSKIdentityHint != null) + { + var key = PSKIdentities.GetKey(serverKeyExchange.PSKIdentityHint); + if (key != null) + { + _PSKIdentity = new PSKIdentity() { Identity = serverKeyExchange.PSKIdentityHint, Key = key }; + } + } + _PSKIdentity ??= PSKIdentities.GetRandom(); + + var otherSecret = new byte[_PSKIdentity.Key.Length]; + clientKeyExchange.PSKIdentity = _PSKIdentity.Identity; + _ClientKeyExchange = clientKeyExchange; + preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key); + } + _Cipher = TLSUtils.AssignCipher(preMasterSecret, true, _Version, _HandshakeInfo); + break; + } + case THandshakeType.CertificateRequest: + { + _HandshakeInfo.UpdateHandshakeHash(data); + _SendCertificate = true; + break; + } + case THandshakeType.ServerHelloDone: + { + _HandshakeInfo.UpdateHandshakeHash(data); + var keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(_HandshakeInfo.CipherSuite); + byte[] premasterSecret = []; + if (_Cipher == null) + { + if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK) + { + var clientKeyExchange = new PSKClientKeyExchange(); + _PSKIdentity = PSKIdentities.GetRandom(); + var otherSecret = new byte[_PSKIdentity.Key.Length]; + clientKeyExchange.PSKIdentity = _PSKIdentity.Identity; + _ClientKeyExchange = clientKeyExchange; + premasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key); + } + else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.RSA) + { + var clientKeyExchange = new RSAClientKeyExchange(); + _ClientKeyExchange = clientKeyExchange; + premasterSecret = TLSUtils.GetRsaPreMasterSecret(_Version); + clientKeyExchange.PremasterSecret = TLSUtils.GetEncryptedRsaPreMasterSecret(ServerCertificate, premasterSecret); + } + else + { + throw new NotImplementedException($"Key Exchange Algorithm {keyExchangeAlgorithm} Not Implemented"); + } + } + + if (_SendCertificate) + { + await SendHandshakeMessageAsync(_Certificate, false).ConfigureAwait(false); + } + + await SendHandshakeMessageAsync(_ClientKeyExchange, false).ConfigureAwait(false); + _Cipher = TLSUtils.AssignCipher(premasterSecret, true, _Version, _HandshakeInfo); + + if (_SendCertificate) + { + var signatureHashAlgorithm = new SignatureHashAlgorithm() { Signature = TSignatureAlgorithm.ECDSA, Hash = THashAlgorithm.SHA256 }; + if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.RSA) + { + signatureHashAlgorithm = new SignatureHashAlgorithm() { Signature = TSignatureAlgorithm.RSA, Hash = THashAlgorithm.SHA1 }; + } + + var certVerify = new CertificateVerify + { + SignatureHashAlgorithm = signatureHashAlgorithm, + Signature = TLSUtils.Sign(_PrivateKey, _PrivateKeyRsa, true, _Version, _HandshakeInfo, signatureHashAlgorithm, _HandshakeInfo.GetHash(_Version)) + }; + + await SendHandshakeMessageAsync(certVerify, false).ConfigureAwait(false); + } + + await SendChangeCipherSpecAsync().ConfigureAwait(false); + var handshakeHash = _HandshakeInfo.GetHash(_Version); + var finished = new Finished + { + VerifyData = TLSUtils.GetVerifyData(_Version, _HandshakeInfo, true, true, handshakeHash) + }; + + await SendHandshakeMessageAsync(finished, true).ConfigureAwait(false); + break; + } + case THandshakeType.NewSessionTicket: + { + _HandshakeInfo.UpdateHandshakeHash(data); + break; + } + case THandshakeType.CertificateVerify: + { + break; + } + case THandshakeType.ClientKeyExchange: + { + break; + } + case THandshakeType.Finished: + { + var serverFinished = Finished.Deserialise(stream); + var handshakeHash = _HandshakeInfo.GetHash(_Version); + var calculatedVerifyData = TLSUtils.GetVerifyData(_Version, _HandshakeInfo, true, false, handshakeHash); + if (serverFinished.VerifyData.SequenceEqual(calculatedVerifyData)) + { + _ConnectionComplete = true; + } + break; + } + default: + { + break; + } + } + } + + _IsFragment = false; + _FragmentedRecordList.RemoveAll(x => true); + } + + private async Task ProcessRecordAsync(DTLSRecord record) + { + try + { + if (record == null) + { + throw new ArgumentNullException(nameof(record)); + } + + switch (record.RecordType) + { + case TRecordType.ChangeCipherSpec: + { + _ReceivedData = []; + if (_ServerEpoch.HasValue) + { + _ServerEpoch++; + _ServerSequenceNumber = 0; + _EncyptedServerEpoch = _ServerEpoch; + } + break; + } + case TRecordType.Alert: + { + _ReceivedData = []; + AlertRecord alertRecord; + try + { + if ((_Cipher == null) || (!_EncyptedServerEpoch.HasValue)) + { + alertRecord = AlertRecord.Deserialise(record.Fragment); + } + else + { + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + var data = _Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Alert, record.Fragment, 0, record.Fragment.Length); + alertRecord = AlertRecord.Deserialise(data); + } + } + catch + { + alertRecord = new AlertRecord + { + AlertLevel = TAlertLevel.Fatal + }; + } + if (alertRecord.AlertLevel == TAlertLevel.Fatal) + { + _ConnectionComplete = true; + } + else if ((alertRecord.AlertLevel == TAlertLevel.Warning) || (alertRecord.AlertDescription == TAlertDescription.CloseNotify)) + { + if (alertRecord.AlertDescription == TAlertDescription.CloseNotify) + { + await SendAlertAsync(TAlertLevel.Warning, TAlertDescription.CloseNotify).ConfigureAwait(false); + _ConnectionComplete = true; + } + } + break; + } + case TRecordType.Handshake: + { + _ReceivedData = []; + await ProcessHandshakeAsync(record).ConfigureAwait(false); + _ServerSequenceNumber = record.SequenceNumber + 1; + break; + } + case TRecordType.ApplicationData: + { + if (_Cipher != null) + { + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + var data = _Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.ApplicationData, record.Fragment, 0, record.Fragment.Length); + _DataReceivedFunction?.Invoke(record.RemoteEndPoint, data); + _ReceivedData = data; + } + _ServerSequenceNumber = record.SequenceNumber + 1; + break; + } + default: + break; + } + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + } + } + + private async Task ProcessRecordsAsync() + { + while (!_Terminate) + { + var record = _Records.PeekRecord(); + while (record != null) + { + if (_ServerEpoch.HasValue && (_ServerSequenceNumber != record.SequenceNumber || _ServerEpoch != record.Epoch)) + { + record = null; + } + else + { + _Records.RemoveRecord(); + await ProcessRecordAsync(record).ConfigureAwait(false); + record = _Records.PeekRecord(); + } + } + + await Task.Delay(100).ConfigureAwait(false); + } + } + + private void ReceiveCallback(byte[] recvData, EndPoint ip) + { + if (recvData == null) + { + throw new ArgumentNullException(nameof(recvData)); + } + + if (ip == null) + { + throw new ArgumentNullException(nameof(ip)); + } + + if (!recvData.Any()) + { + //nothing received? return? + return; + } + + if (recvData.Length < 13) + { + _RecvDataBuffer = [.. _RecvDataBuffer, .. recvData]; + return; + } + + var length = BitConverter.ToUInt16(recvData.Skip(11).Take(2).Reverse().ToArray(), 0); + if (recvData.Length < length) + { + _RecvDataBuffer = [.. _RecvDataBuffer, .. recvData]; + return; + } + + var fullData = _RecvDataBuffer.Concat(recvData).ToArray(); + _RecvDataBuffer = []; + + using (var stream = new MemoryStream(fullData)) + { + while (stream.Position < stream.Length) + { + var record = DTLSRecord.Deserialise(stream); + record.RemoteEndPoint = ip; + _Records.Add(record); + } + } + } + + private async Task SetupSocketAsync() + { + var addressFamily = LocalEndPoint.AddressFamily; + var soc = new Socket(addressFamily, SocketType.Dgram, ProtocolType.Udp); + if (addressFamily == AddressFamily.InterNetworkV6) + { + soc.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, true); + } + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + { + // do not throw SocketError.ConnectionReset by ignoring ICMP Port Unreachable + const int SIO_UDP_CONNRESET = -1744830452; + soc.IOControl(SIO_UDP_CONNRESET, [0], null); + } + + await soc.ConnectAsync(_ServerEndPoint).ConfigureAwait(false); + return soc; + } + + public async Task SendAsync(byte[] data) => + await SendAsync(data, TimeSpan.FromSeconds(1)).ConfigureAwait(false); + + public async Task SendAsync(byte[] data, TimeSpan timeout) + { + if (data == null) + { + throw new ArgumentNullException(nameof(data)); + } + + if (_Socket == null) + { + throw new Exception("Socket Cannot be Null"); + } + + if (_Cipher == null) + { + throw new Exception("Cipher Cannot be Null"); + } + + var record = new DTLSRecord + { + RecordType = TRecordType.ApplicationData, + Epoch = _Epoch, + SequenceNumber = NextSequenceNumber(), + Version = _Version + }; + + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + record.Fragment = _Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.ApplicationData, data, 0, data.Length); + + var recordSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; + var recordBytes = new byte[recordSize]; + using (var stream = new MemoryStream(recordBytes)) + { + record.Serialise(stream); + } + +#if NET6_0_OR_GREATER + var ct = new CancellationTokenSource(timeout).Token; + await _Socket.SendAsync(new ReadOnlyMemory(recordBytes), SocketFlags.None, ct).ConfigureAwait(false); +#else + await _Socket.SendAsync(recordBytes, timeout).ConfigureAwait(false); +#endif + } + + public async Task SendAndGetResponseAsync(byte[] data, TimeSpan timeout) + { + await SendAsync(data, timeout).ConfigureAwait(false); + return await ReceiveDataAsync(timeout).ConfigureAwait(false); + } + + public async Task SendAndGetResonseAsync(byte[] data) => + await SendAndGetResponseAsync(data, TimeSpan.FromSeconds(5)).ConfigureAwait(false); + + public async Task ReceiveDataAsync() => + await ReceiveDataAsync(TimeSpan.FromSeconds(5)).ConfigureAwait(false); + + public async Task ReceiveDataAsync(TimeSpan timeout) + { + var startTime = DateTime.Now; + while ((_ReceivedData == null || !_ReceivedData.Any())) + { + if ((DateTime.Now - startTime) >= timeout) + { + throw new TimeoutException(); + } + + await Task.Delay(100).ConfigureAwait(false); + } + + return _ReceivedData; + } + + private async Task SendAlertAsync(TAlertLevel alertLevel, TAlertDescription alertDescription) => + await SendAlertAsync(alertLevel, alertDescription, TimeSpan.FromSeconds(1)).ConfigureAwait(false); + + private async Task SendAlertAsync(TAlertLevel alertLevel, TAlertDescription alertDescription, TimeSpan timeout) + { + if (_Socket == null) + { + throw new Exception("Soket Cannot be Null"); + } + + var record = new DTLSRecord + { + RecordType = TRecordType.Alert, + Epoch = _Epoch, + SequenceNumber = NextSequenceNumber(), + Version = _Version + }; + + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + + var data = new byte[2]; + data[0] = (byte)alertLevel; + data[1] = (byte)alertDescription; + record.Fragment = _Cipher == null ? data : _Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.ApplicationData, data, 0, data.Length); + var recordSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; + var recordBytes = new byte[recordSize]; + using (var stream = new MemoryStream(recordBytes)) + { + record.Serialise(stream); + } + + await _Socket.SendAsync(recordBytes, timeout).ConfigureAwait(false); + } + + private async Task SendChangeCipherSpecAsync() => + await SendChangeCipherSpecAsync(TimeSpan.FromSeconds(1)).ConfigureAwait(false); + + private async Task SendChangeCipherSpecAsync(TimeSpan timeout) + { + if (_Socket == null) + { + throw new Exception("Socket Cannot be Null"); + } + + var bytes = GetChangeCipherSpec(); + await _Socket.SendAsync(bytes, timeout).ConfigureAwait(false); + ChangeEpoch(); + } + + private byte[] GetChangeCipherSpec() + { + var size = 1; + var responseSize = DTLSRecord.RECORD_OVERHEAD + size; + var response = new byte[responseSize]; + var record = new DTLSRecord + { + RecordType = TRecordType.ChangeCipherSpec, + Epoch = _Epoch, + SequenceNumber = NextSequenceNumber(), + Fragment = new byte[size], + Version = _Version + }; + + record.Fragment[0] = 1; + using (var stream = new MemoryStream(response)) + { + record.Serialise(stream); + } + return response; + } + + private List GetBytes(IHandshakeMessage handshakeMessage, bool encrypt) + { + if (handshakeMessage == null) + { + throw new ArgumentNullException(nameof(handshakeMessage)); + } + + var size = handshakeMessage.CalculateSize(_Version); + var maxPayloadSize = _MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD; + + if (size > maxPayloadSize) + { + var wholeMessage = new List(); + + var record = new DTLSRecord + { + RecordType = TRecordType.Handshake, + Epoch = _Epoch, + Version = _Version + }; + + var handshakeRecord = new HandshakeRecord + { + MessageType = handshakeMessage.MessageType, + MessageSeq = _MessageSequence + }; + + if (!(handshakeMessage.MessageType == THandshakeType.HelloVerifyRequest + || (handshakeMessage.MessageType == THandshakeType.ClientHello && (handshakeMessage as ClientHello).Cookie == null))) + { + record.Fragment = new byte[HandshakeRecord.RECORD_OVERHEAD + size]; + handshakeRecord.Length = (uint)size; + handshakeRecord.FragmentLength = (uint)size; + handshakeRecord.FragmentOffset = 0u; + using (var stream = new MemoryStream(record.Fragment)) + { + handshakeRecord.Serialise(stream); + handshakeMessage.Serialise(stream, _Version); + } + + _HandshakeInfo.UpdateHandshakeHash(record.Fragment); + } + + var dataMessage = new byte[size]; + using (var stream = new MemoryStream(dataMessage)) + { + handshakeMessage.Serialise(stream, _Version); + } + + var dataMessageFragments = dataMessage.ChunkBySize(maxPayloadSize); + handshakeRecord.FragmentOffset = 0U; + dataMessageFragments.ForEach(x => + { + handshakeRecord.Length = (uint)size; + handshakeRecord.FragmentLength = (uint)x.Count(); + record.SequenceNumber = NextSequenceNumber(); + + var baseMessage = new byte[HandshakeRecord.RECORD_OVERHEAD]; + using (var stream = new MemoryStream(baseMessage)) + { + handshakeRecord.Serialise(stream); + } + + record.Fragment = [.. baseMessage, .. x]; + + var responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + x.Count(); + if ((_Cipher != null) && encrypt) + { + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + record.Fragment = _Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); + responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; + } + var response = new byte[responseSize]; + using (var stream = new MemoryStream(response)) + { + record.Serialise(stream); + } + + wholeMessage.Add(response); + handshakeRecord.FragmentOffset += (uint)x.Count(); + }); + + _MessageSequence++; + return wholeMessage; + } + else + { + var record = new DTLSRecord + { + RecordType = TRecordType.Handshake, + Epoch = _Epoch, + SequenceNumber = NextSequenceNumber(), + Fragment = new byte[HandshakeRecord.RECORD_OVERHEAD + size], + Version = _Version + }; + + var handshakeRecord = new HandshakeRecord + { + MessageType = handshakeMessage.MessageType, + MessageSeq = _MessageSequence + }; + _MessageSequence++; + handshakeRecord.Length = (uint)size; + handshakeRecord.FragmentLength = (uint)size; + using (var stream = new MemoryStream(record.Fragment)) + { + handshakeRecord.Serialise(stream); + handshakeMessage.Serialise(stream, _Version); + } + + if (!(handshakeMessage.MessageType == THandshakeType.HelloVerifyRequest + || (handshakeMessage.MessageType == THandshakeType.ClientHello && (handshakeMessage as ClientHello).Cookie == null))) + { + _HandshakeInfo.UpdateHandshakeHash(record.Fragment); + } + + var responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + size; + if ((_Cipher != null) && encrypt) + { + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + record.Fragment = _Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); + responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; + } + + var response = new byte[responseSize]; + using (var stream = new MemoryStream(response)) + { + record.Serialise(stream); + } + + return [response]; + } + } + + private async Task SendHelloAsync(byte[] cookie) + { + var clientHello = new ClientHello + { + ClientVersion = _Version, + Random = _HandshakeInfo.ClientRandom, + Cookie = cookie + }; + + var cipherSuites = new ushort[SupportedCipherSuites.Count]; + var index = 0; + foreach (var item in SupportedCipherSuites) + { + cipherSuites[index] = (ushort)item; + index++; + } + clientHello.CipherSuites = cipherSuites; + clientHello.CompressionMethods = new byte[1]; + clientHello.CompressionMethods[0] = 0; + + clientHello.Extensions = + [ + new Extension() { ExtensionType = TExtensionType.SessionTicketTLS }, + //new Extension() { ExtensionType = TExtensionType.EncryptThenMAC }, + new Extension() { ExtensionType = TExtensionType.ExtendedMasterSecret }, + ]; + + var ellipticCurvesExtension = new EllipticCurvesExtension(); + for (var curve = 0; curve < (int)TEllipticCurve.secp521r1; curve++) + { + if (EllipticCurveFactory.SupportedCurve((TEllipticCurve)curve)) + { + ellipticCurvesExtension.SupportedCurves.Add((TEllipticCurve)curve); + + } + } + clientHello.Extensions.Add(new Extension(ellipticCurvesExtension)); + var cllipticCurvePointFormatsExtension = new EllipticCurvePointFormatsExtension(); + cllipticCurvePointFormatsExtension.SupportedPointFormats.Add(TEllipticCurvePointFormat.Uncompressed); + clientHello.Extensions.Add(new Extension(cllipticCurvePointFormatsExtension)); + var signatureAlgorithmsExtension = new SignatureAlgorithmsExtension(); + signatureAlgorithmsExtension.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash = THashAlgorithm.SHA1, Signature = TSignatureAlgorithm.RSA }); + clientHello.Extensions.Add(new Extension(signatureAlgorithmsExtension)); + await SendHandshakeMessageAsync(clientHello, false, TimeSpan.FromSeconds(1)).ConfigureAwait(false); + } + + private async Task SendHandshakeMessageAsync(IHandshakeMessage handshakeMessage, bool encrypt) => + await SendHandshakeMessageAsync(handshakeMessage, encrypt, TimeSpan.FromSeconds(1)).ConfigureAwait(false); + + private async Task SendHandshakeMessageAsync(IHandshakeMessage handshakeMessage, bool encrypt, TimeSpan timeout) + { + if (handshakeMessage == null) + { + throw new ArgumentNullException(nameof(handshakeMessage)); + } + + if (_Socket == null) + { + throw new Exception("Socket Cannot be Null"); + } + + var byteArrayList = GetBytes(handshakeMessage, encrypt); + foreach (var byteArray in byteArrayList) + { + Console.WriteLine($"Sending {handshakeMessage.MessageType} {byteArray.Length}"); + await _Socket.SendAsync(byteArray, timeout).ConfigureAwait(false); + } + } + + public async Task ConnectToServerAsync(EndPoint serverEndPoint) + { + if (serverEndPoint == null) + { + throw new ArgumentNullException(nameof(serverEndPoint)); + } + + await ConnectToServerAsync(serverEndPoint, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5)).ConfigureAwait(false); + } + + public async Task ConnectToServerAsync(EndPoint serverEndPoint, TimeSpan receiveTimeout, TimeSpan connectionTimeout) + { + _ServerEndPoint = serverEndPoint ?? throw new ArgumentNullException(nameof(serverEndPoint)); + if (SupportedCipherSuites.Count == 0) + { + SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); //Test 1.2 + SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 + SupportedCipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8); //Test 1.2 + SupportedCipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 + SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 + SupportedCipherSuites.Add(TCipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA); + } + + _Socket = await SetupSocketAsync().ConfigureAwait(false); + _ProcessRecordTask = Task.Run(() => ProcessRecordsAsync().ConfigureAwait(false), _Cts.Token); //fire and forget + _ReceiveTask = Task.Run(() => StartReceiveAsync(_Socket, receiveTimeout).ConfigureAwait(false), _Cts.Token); // fire and forget + await SendHelloAsync(null).ConfigureAwait(false); + + var startTime = DateTime.Now; + while (!_ConnectionComplete) + { + if ((DateTime.Now - startTime) >= connectionTimeout) + { + throw new TimeoutException("Could Not Connect To Server"); + } + + await Task.Delay(100).ConfigureAwait(false); + } + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "Other methods are available but RSA is just for windows")] + public void LoadX509Certificate(X509Chain chain) + { + if (chain == null) + { + throw new ArgumentNullException(nameof(chain)); + } + + var mainCert = chain.ChainElements[0].Certificate; + + var privateRsa = mainCert.GetRSAPrivateKey() ?? throw new Exception("Unable to get RSA Private Key"); + var privateRsaCng = privateRsa as RSACng ?? throw new Exception("Private Key is not an RSACng"); + _PrivateKeyRsa = privateRsaCng.Key; + + var publicRsa = mainCert.GetRSAPublicKey() ?? throw new Exception("Unable to get RSA Public Key"); + var publicRsaCng = new RSACng(); + publicRsaCng.ImportParameters(publicRsa.ExportParameters(false)); + PublicKey = publicRsaCng.Key; + + var certChain = new List(); + foreach (var element in chain.ChainElements) + { + certChain.Add(element.Certificate.GetRawCertData()); + } + + _Certificate = new Certificate + { + CertChain = certChain, + CertificateType = TCertificateType.X509 + }; + } + + public void LoadCertificateFromPem(string filename) + { + if (string.IsNullOrWhiteSpace(filename)) + { + throw new ArgumentNullException(nameof(filename)); + } + + using (var stream = File.OpenRead(filename)) + { + LoadCertificateFromPem(stream); + } + } + + public void LoadCertificateFromPem(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var chain = new List(); + var reader = new PemReader(new StreamReader(stream)); + var pem = reader.ReadPemObject(); + + while (pem != null) + { + if (pem.Type.EndsWith("CERTIFICATE")) + { + chain.Add(pem.Content); + } + else if (pem.Type.EndsWith("PRIVATE KEY")) + { + _PrivateKey = Certificates.GetPrivateKeyFromPEM(pem); + } + pem = reader.ReadPemObject(); + } + _Certificate = new Certificate + { + CertChain = chain, + CertificateType = TCertificateType.X509 + }; + } + + private async Task StartReceiveAsync(Socket socket, TimeSpan timeout) + { + if (socket == null) + { + throw new ArgumentNullException(nameof(socket)); + } + + while (!_Terminate) + { + var available = socket.Available; + if (available > 0) + { +#if NET6_0_OR_GREATER + var buffer = new Memory(new byte[available]); + var ct = new CancellationTokenSource(timeout).Token; + var recvd = await socket.ReceiveAsync(buffer, SocketFlags.None, ct).ConfigureAwait(false); + if (recvd < available) + { + buffer = buffer[..recvd]; + } + + ReceiveCallback(buffer.ToArray(), socket.RemoteEndPoint); +#else + var buffer = new byte[available]; + var recvd = await socket.ReceiveAsync(buffer, timeout).ConfigureAwait(false); + if (recvd < available) + { + buffer = buffer.Take(recvd).ToArray(); + } + + ReceiveCallback(buffer, socket.RemoteEndPoint); +#endif + } + else + { + await Task.Delay(100).ConfigureAwait(false); + } + } + } + + public void SetDataReceivedFunction(Action function) => _DataReceivedFunction = function; + + public void SetVersion(Version version) => _Version = version ?? throw new ArgumentNullException(nameof(version)); + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Dipose methods call this one")] + private async Task Dispose(bool disposing) + { + //prevent multiple calls to Dispose + if (_Disposed) + { + return; + } + + if (disposing) + { + _Terminate = true; + + if (_Socket != null) + { + await SendAlertAsync(TAlertLevel.Fatal, TAlertDescription.CloseNotify).ConfigureAwait(false); + _Socket.Dispose(); + _Socket = null; + } + + _Cts.Cancel(); + _ReceiveTask = null; + _ProcessRecordTask = null; + } + + //Tell the GC not to call the finalizer later + GC.SuppressFinalize(this); + _Disposed = true; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Called in private Dispose")] + public void Dispose() => Dispose(true).GetAwaiter().GetResult(); + +#if NET6_0_OR_GREATER + [System.Diagnostics.CodeAnalysis.SuppressMessage("Usage", "CA1816:Dispose methods should call SuppressFinalize", Justification = "Called in private Dispose")] + public async ValueTask DisposeAsync() => await Dispose(true); +#endif + + ~Client() + { + Dispose(false).GetAwaiter().GetResult(); + } + } +} diff --git a/DTLS.Net/DTLS.Net.csproj b/DTLS.Net/DTLS.Net.csproj new file mode 100644 index 0000000..595eeb9 --- /dev/null +++ b/DTLS.Net/DTLS.Net.csproj @@ -0,0 +1,51 @@ + + + + net8;net7;net6;netstandard2.1;netstandard2.0 + true + latest + false + DTLS2.Net + kdurkin77 + DTLS2.Net + Library for a DTLS Client and Server Implementation. Not all features are supported. This package was built on top of CreatorDev's DTLS.Net - https://github.com/CreatorDev/DTLS.Net + DTLS, RSA, PSK, X509Certificate2 + https://github.com/kdurkin77/DTLS2.Net + https://github.com/kdurkin77/DTLS2.Net + GitHub + LICENSE + DTLS2.Net + true + false + DTLS.Net.snk + DTLS2.Net + 1.1.5 + + Bug Fix - .NET8 was getting an error when getting the public key when loading an RSA certifiticate. Updated to use the newer method + + + + + + + + + + + + + + + + + + + + + + True + + + + + diff --git a/DTLS.Net/DTLS.Net.snk b/DTLS.Net/DTLS.Net.snk new file mode 100644 index 0000000..6bac29a Binary files /dev/null and b/DTLS.Net/DTLS.Net.snk differ diff --git a/DTLS.Net/DTLSContext.cs b/DTLS.Net/DTLSContext.cs new file mode 100644 index 0000000..7274653 --- /dev/null +++ b/DTLS.Net/DTLSContext.cs @@ -0,0 +1,129 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using Org.BouncyCastle.Crypto.Prng; +using Org.BouncyCastle.Crypto.Tls; +using Org.BouncyCastle.Security; +using Org.BouncyCastle.Utilities; +using System; + +using BcTls = Org.BouncyCastle.Crypto.Tls; + +namespace DTLS +{ + internal class DTLSContext : TlsContext + { + private class DTLSSecurityParameters : SecurityParameters + { + private readonly HandshakeInfo _HandshakeInfo; + private readonly byte[] _ClientRandom; + private readonly byte[] _ServerRandom; + private readonly int _PrfAlgorithm; + + public override int CipherSuite => (int)this._HandshakeInfo.CipherSuite; + public override byte[] ClientRandom => this._ClientRandom; + public override byte[] MasterSecret => this._HandshakeInfo.MasterSecret; + public override int PrfAlgorithm => this._PrfAlgorithm; + public override byte[] ServerRandom => this._ServerRandom; + public override bool IsExtendedMasterSecret => this._HandshakeInfo.Extensions.Exists(e => e.ExtensionType == TExtensionType.ExtendedMasterSecret); + + public DTLSSecurityParameters(Version version, HandshakeInfo handshakeInfo) + { + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + this._HandshakeInfo = handshakeInfo; + if (handshakeInfo != null) + { + this._ClientRandom = handshakeInfo.ClientRandom.Serialise(); + this._ServerRandom = handshakeInfo.ServerRandom.Serialise(); + } + + switch (CipherSuites.GetPseudorandomFunction(version, handshakeInfo.CipherSuite)) + { + case TPseudorandomFunction.NotSet: + { + break; + } + case TPseudorandomFunction.Legacy: + { + this._PrfAlgorithm = BcTls.PrfAlgorithm.tls_prf_legacy; + break; + } + case TPseudorandomFunction.SHA256: + { + this._PrfAlgorithm = BcTls.PrfAlgorithm.tls_prf_sha256; + break; + } + case TPseudorandomFunction.SHA384: + { + this._PrfAlgorithm = BcTls.PrfAlgorithm.tls_prf_sha384; + break; + } + default: + { + break; + } + } + } + } + + public ProtocolVersion ClientVersion { get; private set; } + public bool IsServer { get; private set; } + public IRandomGenerator NonceRandomGenerator { get; private set; } + public SecureRandom SecureRandom { get; set; } + public SecurityParameters SecurityParameters { get; private set; } + public ProtocolVersion ServerVersion { get; private set; } + public object UserObject + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } + + public DTLSContext() { } + + public DTLSContext(bool client, Version version, HandshakeInfo handshakeInfo) + { + this.IsServer = !client; + if (version == DTLSRecord.Version1_2) + { + this.ClientVersion = ProtocolVersion.DTLSv12; + this.ServerVersion = ProtocolVersion.DTLSv12; + } + else + { + this.ClientVersion = ProtocolVersion.DTLSv10; + this.ServerVersion = ProtocolVersion.DTLSv10; + } + this.SecurityParameters = new DTLSSecurityParameters(version, handshakeInfo); + this.NonceRandomGenerator = new DigestRandomGenerator(TlsUtilities.CreateHash(HashAlgorithm.sha256)); + this.NonceRandomGenerator.AddSeedMaterial(Times.NanoTime()); + + } + + public byte[] ExportKeyingMaterial(string asciiLabel, byte[] context_value, int length) => throw new NotImplementedException(); + + public TlsSession ResumableSession => throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/DTLS.Net/EllipticCurves/ECDHE.cs b/DTLS.Net/EllipticCurves/ECDHE.cs similarity index 78% rename from src/DTLS.Net/EllipticCurves/ECDHE.cs rename to DTLS.Net/EllipticCurves/ECDHE.cs index bb908e6..c3ef232 100644 --- a/src/DTLS.Net/EllipticCurves/ECDHE.cs +++ b/DTLS.Net/EllipticCurves/ECDHE.cs @@ -20,10 +20,6 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; @@ -31,16 +27,16 @@ products derived from this software without specific prior written permission. namespace DTLS { - //Elliptic Curve Diffie-Hellman - internal class ECDHE - { - public AsymmetricCipherKeyPair GenerateEphemeralKey(TEllipticCurve curve) - { - ECDomainParameters ecParams = EllipticCurveFactory.GetEllipticCurveParameters(curve); - ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); - SecureRandom random = new SecureRandom(); - keyPairGenerator.Init(new ECKeyGenerationParameters(ecParams, random)); - return keyPairGenerator.GenerateKeyPair(); - } - } + //Elliptic Curve Diffie-Hellman + internal class ECDHE + { + public AsymmetricCipherKeyPair GenerateEphemeralKey(TEllipticCurve curve) + { + var ecParams = EllipticCurveFactory.GetEllipticCurveParameters(curve); + var keyPairGenerator = new ECKeyPairGenerator(); + var random = new SecureRandom(); + keyPairGenerator.Init(new ECKeyGenerationParameters(ecParams, random)); + return keyPairGenerator.GenerateKeyPair(); + } + } } diff --git a/src/DTLS.Net/EllipticCurves/EllipticCurve.cs b/DTLS.Net/EllipticCurves/EllipticCurve.cs similarity index 68% rename from src/DTLS.Net/EllipticCurves/EllipticCurve.cs rename to DTLS.Net/EllipticCurves/EllipticCurve.cs index 18853d4..19b379d 100644 --- a/src/DTLS.Net/EllipticCurves/EllipticCurve.cs +++ b/DTLS.Net/EllipticCurves/EllipticCurve.cs @@ -21,58 +21,32 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Numerics; namespace DTLS { - // either y² = x³ + ax + b (mod p) - // or y² + xy = x³ + ax² + b + // either y² = x³ + ax + b (mod p) + // or y² + xy = x³ + ax² + b - internal class EllipticCurve - { - private BigInteger _A; - private BigInteger _B; - private BigInteger _Order; - private BigInteger _Cofactor; + internal class EllipticCurve + { + public BigInteger A { get; } - private EllipticCurvePoint _BasePoint; + public BigInteger B { get; } - public BigInteger A - { - get { return _A; } - } + public BigInteger Order { get; } - public BigInteger B - { - get { return _B; } - } + public BigInteger Cofactor { get; } - public BigInteger Order - { - get { return _Order; } - } + public EllipticCurvePoint BasePoint { get; } - public BigInteger Cofactor - { - get { return _Cofactor; } - } - - public EllipticCurvePoint BasePoint - { - get { return _BasePoint; } - } - - public EllipticCurve(BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor, EllipticCurvePoint basePoint) - { - _A = a; - _B = b; - _Order = order; - _Cofactor = cofactor; - _BasePoint = basePoint; - } - - } + public EllipticCurve(BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor, EllipticCurvePoint basePoint) + { + this.A = a; + this.B = b; + this.Order = order; + this.Cofactor = cofactor; + this.BasePoint = basePoint ?? throw new ArgumentNullException(nameof(basePoint)); + } + } } diff --git a/DTLS.Net/EllipticCurves/EllipticCurveFactory.cs b/DTLS.Net/EllipticCurves/EllipticCurveFactory.cs new file mode 100644 index 0000000..3c15f1c --- /dev/null +++ b/DTLS.Net/EllipticCurves/EllipticCurveFactory.cs @@ -0,0 +1,245 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using Org.BouncyCastle.Asn1; +using Org.BouncyCastle.Asn1.Sec; +using Org.BouncyCastle.Crypto.EC; +using Org.BouncyCastle.Crypto.Parameters; +using System; +using System.Collections.Generic; +using System.Numerics; + +namespace DTLS +{ + internal class EllipticCurveFactory + { + private static readonly EllipticCurve _Secp192k1; + private static readonly EllipticCurve _Secp192r1; + private static readonly EllipticCurve _Secp224k1; + private static readonly EllipticCurve _Secp224r1; + private static readonly EllipticCurve _Secp256k1; + private static readonly EllipticCurve _Secp256r1; + private static readonly EllipticCurve _Secp384r1; + private static readonly EllipticCurve _Secp521r1; + + private static Dictionary _SupportedCurves = new Dictionary(); + private static Dictionary _CurveParameters = new Dictionary(); + + + static EllipticCurveFactory() + { + BigInteger baseX; + BigInteger baseY; + BigInteger a; + BigInteger b; + BigInteger p; + BigInteger n; + BigInteger h; + + + baseX = new BigInteger(new byte[] { 0x7D, 0x6C, 0xE0, 0xEA, 0xB1, 0xD1, 0xA5, 0x1D, 0x34, 0xF4, 0xB7, 0x80, 0x02, 0x7D, 0xB0, 0x26, 0xAE, 0xE9, 0x57, 0xC0, 0x0E, 0xF1, 0x4F, 0xDB }); + baseY = new BigInteger(new byte[] { 0x9D, 0x2F, 0x5E, 0xD9, 0x88, 0xAA, 0x82, 0x40, 0x34, 0x86, 0xBE, 0x15, 0xD0, 0x63, 0x41, 0x84, 0xA7, 0x28, 0x56, 0x9C, 0x6D, 0x2F, 0x2F, 0x9B }); + a = new BigInteger(0); + b = new BigInteger(3); + p = new BigInteger(new byte[] { 0x37, 0xEE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + n = new BigInteger(new byte[] { 0x8D, 0xFD, 0xDE, 0x74, 0x6A, 0x46, 0x69, 0x0F, 0x17, 0xFC, 0xF2, 0x26, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + h = new BigInteger(1); + _Secp192k1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); + _SupportedCurves.Add(TEllipticCurve.secp192k1, _Secp192k1); + AddCurveParameters(TEllipticCurve.secp192k1, SecObjectIdentifiers.SecP192k1); + + baseX = new BigInteger(new byte[] { 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4, 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C, 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18 }); + baseY = new BigInteger(new byte[] { 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73, 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63, 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07 }); + a = new BigInteger(new byte[] { 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + b = new BigInteger(new byte[] { 0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE, 0x49, 0x30, 0x24, 0x72, 0xAB, 0xE9, 0xA7, 0x0F, 0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64 }); + p = new BigInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + n = new BigInteger(new byte[] { 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14, 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + h = new BigInteger(1); + _Secp192r1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); + _SupportedCurves.Add(TEllipticCurve.secp192r1, _Secp192r1); + AddCurveParameters(TEllipticCurve.secp192r1, SecObjectIdentifiers.SecP192r1); + + + baseX = new BigInteger(new byte[] { 0x5C, 0xA4, 0xB7, 0xB6, 0x0E, 0x65, 0x7E, 0x0F, 0xA9, 0x75, 0x70, 0xE4, 0xE9, 0x67, 0xA4, 0x69, 0xA1, 0x28, 0xFC, 0x30, 0xDF, 0x99, 0xF0, 0x4D, 0x33, 0x5B, 0x45, 0xA1 }); + baseY = new BigInteger(new byte[] { 0xA5, 0x61, 0x6D, 0x55, 0xDB, 0x4B, 0xCA, 0xE2, 0x59, 0xBD, 0xB0, 0xC0, 0xF7, 0x19, 0xE3, 0xF7, 0xD6, 0xFB, 0xCA, 0x82, 0x42, 0x34, 0xBA, 0x7F, 0xED, 0x9F, 0x08, 0x7E }); + a = new BigInteger(0); + b = new BigInteger(5); + p = new BigInteger(new byte[] { 0x6D, 0xE5, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + n = new BigInteger(new byte[] { 0xF7, 0xB1, 0x9F, 0x76, 0x71, 0xA9, 0xF0, 0xCA, 0x84, 0x61, 0xEC, 0xD2, 0xE8, 0xDC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }); + h = new BigInteger(1); + _Secp224k1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); + _SupportedCurves.Add(TEllipticCurve.secp224k1, _Secp224k1); + AddCurveParameters(TEllipticCurve.secp224k1, SecObjectIdentifiers.SecP224k1); + + + baseX = new BigInteger(new byte[] { 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34, 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A, 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B, 0xBD, 0x0C, 0x0E, 0xB7 }); + baseY = new BigInteger(new byte[] { 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44, 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD, 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5, 0x88, 0x63, 0x37, 0xBD }); + a = new BigInteger(new byte[] { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + b = new BigInteger(new byte[] { 0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27, 0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50, 0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C, 0x85, 0x0A, 0x05, 0xB4 }); + p = new BigInteger(new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + n = new BigInteger(new byte[] { 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13, 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + h = new BigInteger(1); + _Secp224r1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); + _SupportedCurves.Add(TEllipticCurve.secp224r1, _Secp224r1); + AddCurveParameters(TEllipticCurve.secp224r1, SecObjectIdentifiers.SecP224r1); + + baseX = new BigInteger(new byte[] { 0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59, 0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02, 0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55, 0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79 }); + baseY = new BigInteger(new byte[] { 0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C, 0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD, 0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D, 0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48 }); + a = new BigInteger(0); + b = new BigInteger(7); + p = new BigInteger(new byte[] { 0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + n = new BigInteger(new byte[] { 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + h = new BigInteger(1); + _Secp256k1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); + _SupportedCurves.Add(TEllipticCurve.secp256k1, _Secp256k1); + AddCurveParameters(TEllipticCurve.secp256k1, SecObjectIdentifiers.SecP256k1); + + baseX = new BigInteger(new byte[] { 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4, 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77, 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8, 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B }); + baseY = new BigInteger(new byte[] { 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB, 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B, 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E, 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F }); + a = new BigInteger(new byte[] { 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }); + b = new BigInteger(new byte[] { 0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B, 0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65, 0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3, 0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A }); + p = new BigInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }); + n = new BigInteger(new byte[] { 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }); + h = new BigInteger(1); + _Secp256r1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); + _SupportedCurves.Add(TEllipticCurve.secp256r1, _Secp256r1); + AddCurveParameters(TEllipticCurve.secp256r1, SecObjectIdentifiers.SecP256r1); + + baseX = new BigInteger(new byte[] { 0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A, 0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55, 0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59, 0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E, 0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E, 0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA }); + baseY = new BigInteger(new byte[] { 0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A, 0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A, 0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9, 0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8, 0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D, 0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36 }); + a = new BigInteger(new byte[] { 0xFC, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + b = new BigInteger(new byte[] { 0xEF, 0x2A, 0xEC, 0xD3, 0xED, 0xC8, 0x85, 0x2A, 0x9D, 0xD1, 0x2E, 0x8A, 0x8D, 0x39, 0x56, 0xC6, 0x5A, 0x87, 0x13, 0x50, 0x8F, 0x08, 0x14, 0x03, 0x12, 0x41, 0x81, 0xFE, 0x6E, 0x9C, 0x1D, 0x18, 0x19, 0x2D, 0xF8, 0xE3, 0x6B, 0x05, 0x8E, 0x98, 0xE4, 0xE7, 0x3E, 0xE2, 0xA7, 0x2F, 0x31, 0xB3 }); + p = new BigInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + n = new BigInteger(new byte[] { 0x73, 0x29, 0xC5, 0xCC, 0x6A, 0x19, 0xEC, 0xEC, 0x7A, 0xA7, 0xB0, 0x48, 0xB2, 0x0D, 0x1A, 0x58, 0xDF, 0x2D, 0x37, 0xF4, 0x81, 0x4D, 0x63, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); + h = new BigInteger(1); + _Secp384r1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); + AddCurveParameters(TEllipticCurve.secp384r1, SecObjectIdentifiers.SecP384r1); + _SupportedCurves.Add(TEllipticCurve.secp384r1, _Secp384r1); + + baseX = new BigInteger(new byte[] { 0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9, 0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33, 0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE, 0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1, 0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8, 0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C, 0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E, 0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85, 0xC6, 0x00 }); + baseY = new BigInteger(new byte[] { 0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88, 0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35, 0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5, 0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97, 0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17, 0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98, 0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C, 0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39, 0x18, 0x01 }); + a = new BigInteger(new byte[] { 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }); + b = new BigInteger(new byte[] { 0x00, 0x3F, 0x50, 0x6B, 0xD4, 0x1F, 0x45, 0xEF, 0xF1, 0x34, 0x2C, 0x3D, 0x88, 0xDF, 0x73, 0x35, 0x07, 0xBF, 0xB1, 0x3B, 0xBD, 0xC0, 0x52, 0x16, 0x7B, 0x93, 0x7E, 0xEC, 0x51, 0x39, 0x19, 0x56, 0xE1, 0x09, 0xF1, 0x8E, 0x91, 0x89, 0xB4, 0xB8, 0xF3, 0x15, 0xB3, 0x99, 0x5B, 0x72, 0xDA, 0xA2, 0xEE, 0x40, 0x85, 0xB6, 0xA0, 0x21, 0x9A, 0x92, 0x1F, 0x9A, 0x1C, 0x8E, 0x61, 0xB9, 0x3E, 0x95, 0x51, 0x00 }); + p = new BigInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }); + n = new BigInteger(new byte[] { 0x09, 0x64, 0x38, 0x91, 0x1E, 0xB7, 0x6F, 0xBB, 0xAE, 0x47, 0x9C, 0x89, 0xB8, 0xC9, 0xB5, 0x3B, 0xD0, 0xA5, 0x09, 0xF7, 0x48, 0x01, 0xCC, 0x7F, 0x6B, 0x96, 0x2F, 0xBF, 0x83, 0x87, 0x86, 0x51, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }); + h = new BigInteger(1); + _Secp521r1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); + AddCurveParameters(TEllipticCurve.secp521r1, SecObjectIdentifiers.SecP521r1); + _SupportedCurves.Add(TEllipticCurve.secp521r1, _Secp521r1); + + } + + private static void AddCurveParameters(TEllipticCurve curve, DerObjectIdentifier id) + { + if (id == null) + { + throw new ArgumentNullException(nameof(id)); + } + + var ecP = CustomNamedCurves.GetByOid(id); + _CurveParameters.Add(curve, new ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed())); + } + + + public static EllipticCurve GetEllipticCurve(TEllipticCurve curve) + { + EllipticCurve result = null; + switch (curve) + { + case TEllipticCurve.sect163k1: + break; + case TEllipticCurve.sect163r1: + break; + case TEllipticCurve.sect163r2: + break; + case TEllipticCurve.sect193r1: + break; + case TEllipticCurve.sect193r2: + break; + case TEllipticCurve.sect233k1: + break; + case TEllipticCurve.sect233r1: + break; + case TEllipticCurve.sect239k1: + break; + case TEllipticCurve.sect283k1: + break; + case TEllipticCurve.sect283r1: + break; + case TEllipticCurve.sect409k1: + break; + case TEllipticCurve.sect409r1: + break; + case TEllipticCurve.sect571k1: + break; + case TEllipticCurve.sect571r1: + break; + case TEllipticCurve.secp160k1: + break; + case TEllipticCurve.secp160r1: + break; + case TEllipticCurve.secp160r2: + break; + case TEllipticCurve.secp192k1: + result = _Secp192k1; + break; + case TEllipticCurve.secp192r1: + result = _Secp192r1; + break; + case TEllipticCurve.secp224k1: + result = _Secp224k1; + break; + case TEllipticCurve.secp224r1: + result = _Secp224r1; + break; + case TEllipticCurve.secp256k1: + result = _Secp256k1; + break; + case TEllipticCurve.secp256r1: + result = _Secp256r1; + break; + case TEllipticCurve.secp384r1: + result = _Secp384r1; + break; + case TEllipticCurve.secp521r1: + result = _Secp521r1; + break; + case TEllipticCurve.arbitrary_explicit_prime_curves: + break; + case TEllipticCurve.arbitrary_explicit_char2_curves: + break; + default: + break; + } + return result; + } + + public static bool SupportedCurve(TEllipticCurve curve) => _SupportedCurves.ContainsKey(curve); + + + internal static ECDomainParameters GetEllipticCurveParameters(TEllipticCurve curve) + { + _CurveParameters.TryGetValue(curve, out var result); + return result; + } + } +} diff --git a/src/DTLS.Net/EllipticCurves/EllipticCurvePoint.cs b/DTLS.Net/EllipticCurves/EllipticCurvePoint.cs similarity index 82% rename from src/DTLS.Net/EllipticCurves/EllipticCurvePoint.cs rename to DTLS.Net/EllipticCurves/EllipticCurvePoint.cs index 003fa2c..b0586df 100644 --- a/src/DTLS.Net/EllipticCurves/EllipticCurvePoint.cs +++ b/DTLS.Net/EllipticCurves/EllipticCurvePoint.cs @@ -20,28 +20,19 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Numerics; namespace DTLS { - internal class EllipticCurvePoint - { - private BigInteger _X; - private BigInteger _Y; - - - public BigInteger X { get { return _X; } set { _X = value; } } - public BigInteger Y { get { return _Y; } set { _Y = value; } } - - public EllipticCurvePoint(BigInteger x, BigInteger y) - { - _X = x; - _Y = y; - } - - } + internal class EllipticCurvePoint + { + public BigInteger X { get; set; } + public BigInteger Y { get; set; } + + public EllipticCurvePoint(BigInteger x, BigInteger y) + { + this.X = x; + this.Y = y; + } + } } diff --git a/src/DTLS.Net/EllipticCurves/PrimeFiniteFieldCurve.cs b/DTLS.Net/EllipticCurves/PrimeFiniteFieldCurve.cs similarity index 77% rename from src/DTLS.Net/EllipticCurves/PrimeFiniteFieldCurve.cs rename to DTLS.Net/EllipticCurves/PrimeFiniteFieldCurve.cs index d2b2bf7..b443e36 100644 --- a/src/DTLS.Net/EllipticCurves/PrimeFiniteFieldCurve.cs +++ b/DTLS.Net/EllipticCurves/PrimeFiniteFieldCurve.cs @@ -21,29 +21,25 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Numerics; namespace DTLS { - //Fp y² = x³ + ax + b (mod p) - - internal class PrimeFiniteFieldCurve : EllipticCurve - { - BigInteger _Prime; - - public BigInteger Prime - { - get { return _Prime; } - } - - public PrimeFiniteFieldCurve(BigInteger prime, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor, EllipticCurvePoint basePoint) - :base(a, b, order, cofactor, basePoint) - { - _Prime = prime; - } - - } + //Fp y² = x³ + ax + b (mod p) + + internal class PrimeFiniteFieldCurve : EllipticCurve + { + public BigInteger Prime { get; } + + public PrimeFiniteFieldCurve(BigInteger prime, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor, EllipticCurvePoint basePoint) + : base(a, b, order, cofactor, basePoint) + { + if (basePoint == null) + { + throw new ArgumentNullException(nameof(basePoint)); + } + + this.Prime = prime; + } + } } diff --git a/src/DTLS.Net/EllipticCurves/TEllipticCurve.cs b/DTLS.Net/EllipticCurves/TEllipticCurve.cs similarity index 74% rename from src/DTLS.Net/EllipticCurves/TEllipticCurve.cs rename to DTLS.Net/EllipticCurves/TEllipticCurve.cs index 74b22c6..7e1aaa5 100644 --- a/src/DTLS.Net/EllipticCurves/TEllipticCurve.cs +++ b/DTLS.Net/EllipticCurves/TEllipticCurve.cs @@ -20,26 +20,22 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - // RFC 4492 5.1.1 - internal enum TEllipticCurve - { - sect163k1 = 1, sect163r1 = 2, sect163r2 = 3, - sect193r1 = 4, sect193r2 = 5, sect233k1 = 6, - sect233r1 = 7, sect239k1 = 8, sect283k1 = 9, - sect283r1 = 10, sect409k1 = 11, sect409r1 = 12, - sect571k1 = 13, sect571r1 = 14, secp160k1 = 15, - secp160r1 = 16, secp160r2 = 17, secp192k1 = 18, - secp192r1 = 19, secp224k1 = 20, secp224r1 = 21, - secp256k1 = 22, secp256r1 = 23, secp384r1 = 24, - secp521r1 = 25, - arbitrary_explicit_prime_curves = 0xFF01, - arbitrary_explicit_char2_curves = 0xFF02, - } + // RFC 4492 5.1.1 + internal enum TEllipticCurve + { + sect163k1 = 1, sect163r1 = 2, sect163r2 = 3, + sect193r1 = 4, sect193r2 = 5, sect233k1 = 6, + sect233r1 = 7, sect239k1 = 8, sect283k1 = 9, + sect283r1 = 10, sect409k1 = 11, sect409r1 = 12, + sect571k1 = 13, sect571r1 = 14, secp160k1 = 15, + secp160r1 = 16, secp160r2 = 17, secp192k1 = 18, + secp192r1 = 19, secp224k1 = 20, secp224r1 = 21, + secp256k1 = 22, secp256r1 = 23, secp384r1 = 24, + secp521r1 = 25, + arbitrary_explicit_prime_curves = 0xFF01, + arbitrary_explicit_char2_curves = 0xFF02 + } } diff --git a/src/DTLS.Net/EllipticCurves/TEllipticCurveBasisType.cs b/DTLS.Net/EllipticCurves/TEllipticCurveBasisType.cs similarity index 91% rename from src/DTLS.Net/EllipticCurves/TEllipticCurveBasisType.cs rename to DTLS.Net/EllipticCurves/TEllipticCurveBasisType.cs index a511222..7b66895 100644 --- a/src/DTLS.Net/EllipticCurves/TEllipticCurveBasisType.cs +++ b/DTLS.Net/EllipticCurves/TEllipticCurveBasisType.cs @@ -20,17 +20,13 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - //enum { ec_basis_trinomial, ec_basis_pentanomial } ECBasisType; + //enum { ec_basis_trinomial, ec_basis_pentanomial } ECBasisType; internal enum TEllipticCurveBasisType - { - Trinomial, - Pentanomial - } + { + Trinomial, + Pentanomial + } } diff --git a/src/DTLS.Net/EllipticCurves/TEllipticCurveType.cs b/DTLS.Net/EllipticCurves/TEllipticCurveType.cs similarity index 87% rename from src/DTLS.Net/EllipticCurves/TEllipticCurveType.cs rename to DTLS.Net/EllipticCurves/TEllipticCurveType.cs index 7ed93ce..a7f7397 100644 --- a/src/DTLS.Net/EllipticCurves/TEllipticCurveType.cs +++ b/DTLS.Net/EllipticCurves/TEllipticCurveType.cs @@ -20,19 +20,15 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - //enum { explicit_prime (1), explicit_char2 (2), - // named_curve (3), reserved(248..255) } ECCurveType; + //enum { explicit_prime (1), explicit_char2 (2), + // named_curve (3), reserved(248..255) } ECCurveType; internal enum TEllipticCurveType - { - ExplicitPrime = 1, - ExplicitChar2 = 2, - NamedCurve = 3 - } + { + ExplicitPrime = 1, + ExplicitChar2 = 2, + NamedCurve = 3 + } } diff --git a/DTLS.Net/Extensions.cs b/DTLS.Net/Extensions.cs new file mode 100644 index 0000000..9070881 --- /dev/null +++ b/DTLS.Net/Extensions.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; + +namespace DTLS.Net +{ + public static class Extensions + { + public static async Task SendAsync(this Socket socket, byte[] buffer, TimeSpan timeout) + { + var timeoutMs = (int)timeout.TotalMilliseconds; +#if NETSTANDARD2_1 || NET6_0_OR_GREATER + using (var cts = new CancellationTokenSource()) + { + cts.CancelAfter(timeoutMs); + return await socket.SendAsync(buffer, SocketFlags.None, cts.Token).ConfigureAwait(false); + } +#else + return await Task.Factory.FromAsync( + socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, null, socket), + socket.EndReceive + ).TimeoutAfterAsync(timeoutMs) + .ConfigureAwait(false); +#endif + } + + public static async Task ReceiveAsync(this Socket socket, byte[] buffer, TimeSpan timeout) + { + var timeoutMs = (int)timeout.TotalMilliseconds; +#if NETSTANDARD2_1 || NET6_0_OR_GREATER + using (var cts = new CancellationTokenSource()) + { + cts.CancelAfter(timeoutMs); + return await socket.ReceiveAsync(buffer, SocketFlags.None, cts.Token).ConfigureAwait(false); + } +#else + return await Task.Factory.FromAsync( + socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, null, socket), + socket.EndReceive + ).TimeoutAfterAsync(timeoutMs) + .ConfigureAwait(false); +#endif + } + +#if !NETSTANDARD2_1 && !NET6_0_OR_GREATER + public static async Task TimeoutAfterAsync(this Task task, int timeout) + { + using (var timeoutCancellationTokenSource = new CancellationTokenSource()) + { + using (var completedTask = await Task.WhenAny(task, Task.Delay(timeout, timeoutCancellationTokenSource.Token)).ConfigureAwait(false)) + { + timeoutCancellationTokenSource.Cancel(); + if (completedTask == task) + { + return await task.ConfigureAwait(false); // Very important in order to propagate exceptions + } + + throw new TimeoutException(); + } + } + } +#endif + + public static IEnumerable> ChunkBySize(this IEnumerable source, int size) + { + if(source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if(size <= 0) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } + + var results = new List(); + using (var ie = source.GetEnumerator()) + { + while (ie.MoveNext()) + { + results.Add(ie.Current); + + if(results.Count >= size) + { + yield return results.ToArray(); + + results.Clear(); + } + } + + if (results.Any()) + { + yield return results.ToArray(); + } + } + } + + public static IEnumerable GetRange(this IEnumerable source, int index, int count) + { + if (index < 0) + { + throw new ArgumentOutOfRangeException(nameof(index)); + } + + if (count < 0) + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + + if (source.Count() - index < count) + { + throw new ArgumentOutOfRangeException("Source must be at least size index + count"); + } + + return source.Skip(index).Take(count); + } + + public static void ForEach(this IEnumerable source, Action action) + { + if(source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if(action == null) + { + throw new ArgumentNullException(nameof(action)); + } + + foreach(var element in source) + { + action(element); + } + } + } +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeInfo.cs b/DTLS.Net/HandshakeInfo.cs similarity index 65% rename from src/DTLS.Net/HandshakeInfo.cs rename to DTLS.Net/HandshakeInfo.cs index 71e67d1..c6f0d5c 100644 --- a/src/DTLS.Net/HandshakeInfo.cs +++ b/DTLS.Net/HandshakeInfo.cs @@ -20,22 +20,22 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using System; namespace DTLS { internal class HandshakeInfo { - private Org.BouncyCastle.Crypto.Digests.Sha1Digest _VerifyHandshakeSHA1; - private Org.BouncyCastle.Crypto.Digests.MD5Digest _VerifyHandshakeMD5; - private IDigest _VerifyHandshake; + private readonly Sha1Digest _VerifyHandshakeSHA1 = new Sha1Digest(); + private readonly MD5Digest _VerifyHandshakeMD5 = new MD5Digest(); + private readonly IDigest _VerifyHandshake = new Sha256Digest(); public TCipherSuite CipherSuite { get; set; } + public Extensions Extensions { get; set; } + public RandomData ClientRandom { get; set; } public RandomData ServerRandom { get; set; } @@ -46,52 +46,41 @@ internal class HandshakeInfo public ushort MessageSequence { get; set; } - public HandshakeInfo() - { - } - - public void InitaliseHandshakeHash(bool legacy) + public void UpdateHandshakeHash(byte[] data) { - if (legacy) + if(data == null) { - _VerifyHandshakeSHA1 = new Org.BouncyCastle.Crypto.Digests.Sha1Digest(); - _VerifyHandshakeMD5 = new Org.BouncyCastle.Crypto.Digests.MD5Digest(); + throw new ArgumentNullException(nameof(data)); } - else - _VerifyHandshake = new Org.BouncyCastle.Crypto.Digests.Sha256Digest(); + + this._VerifyHandshakeSHA1.BlockUpdate(data, 0, data.Length); + this._VerifyHandshakeMD5.BlockUpdate(data, 0, data.Length); + this._VerifyHandshake.BlockUpdate(data, 0, data.Length); } - public void UpdateHandshakeHash(byte[] data) + public byte[] GetHash(Version version) { - if (_VerifyHandshake == null) + if(version == null) { - if (_VerifyHandshakeSHA1 != null) - { - _VerifyHandshakeSHA1.BlockUpdate(data, 0, data.Length); - _VerifyHandshakeMD5.BlockUpdate(data, 0, data.Length); - } + throw new ArgumentNullException(nameof(version)); } - else - _VerifyHandshake.BlockUpdate(data, 0, data.Length); - } - public byte[] GetHash() - { byte[] handshakeHash; - if (_VerifyHandshake == null) + if (version < DTLSRecord.Version1_2) { - IDigest sha1 = new Org.BouncyCastle.Crypto.Digests.Sha1Digest(_VerifyHandshakeSHA1); - IDigest md5 = new Org.BouncyCastle.Crypto.Digests.MD5Digest(_VerifyHandshakeMD5); + IDigest sha1 = new Sha1Digest(this._VerifyHandshakeSHA1); + IDigest md5 = new MD5Digest(this._VerifyHandshakeMD5); handshakeHash = new byte[sha1.GetDigestSize() + md5.GetDigestSize()]; md5.DoFinal(handshakeHash, 0); sha1.DoFinal(handshakeHash, md5.GetDigestSize()); } else { - IDigest hash = new Org.BouncyCastle.Crypto.Digests.Sha256Digest((Org.BouncyCastle.Crypto.Digests.Sha256Digest)_VerifyHandshake); + IDigest hash = new Sha256Digest((Sha256Digest)this._VerifyHandshake); handshakeHash = new byte[hash.GetDigestSize()]; hash.DoFinal(handshakeHash, 0); } + return handshakeHash; } } diff --git a/DTLS.Net/HandshakeMessages/Certificate.cs b/DTLS.Net/HandshakeMessages/Certificate.cs new file mode 100644 index 0000000..c5a3a2a --- /dev/null +++ b/DTLS.Net/HandshakeMessages/Certificate.cs @@ -0,0 +1,160 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace DTLS +{ + + //opaque ASN.1Cert<1..2^24-1>; + //struct { + // ASN.1Cert certificate_list<0..2^24-1>; + //} Certificate; + + internal class Certificate : IHandshakeMessage + { + public byte[] Cert { get; set; } + + public List CertChain { get; set; } + + public TCertificateType CertificateType { get; set; } + + public THandshakeType MessageType => THandshakeType.Certificate; + + public int CalculateSize(Version version) + { + var result = 3; // overall Length + switch (this.CertificateType) + { + case TCertificateType.X509: + { + if (this.CertChain != null) + { + foreach (var item in this.CertChain) + { + result += (3 + item.Length); + } + } + break; + } + case TCertificateType.OpenPGP: + { + break; + } + case TCertificateType.RawPublicKey: + { + break; + } + case TCertificateType.Unknown: + { + break; + } + default: + { + break; + } + } + return result; + } + + public static Certificate Deserialise(Stream stream, TCertificateType certificateType) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new Certificate(); + var certificateChainLength = NetworkByteOrderConverter.ToInt24(stream); + if (certificateChainLength > 0) + { + result.CertificateType = certificateType; + if (certificateType == TCertificateType.X509) + { + result.CertChain = new List(); + while (certificateChainLength > 0) + { + var certificateLength = NetworkByteOrderConverter.ToInt24(stream); + var certificate = new byte[certificateLength]; + stream.Read(certificate, 0, certificateLength); + result.CertChain.Add(certificate); + certificateChainLength = certificateChainLength - certificateLength - 3; + } + + if (result.CertChain.Any()) + { + result.Cert = result.CertChain[0]; + } + } + else + { + throw new NotImplementedException(); + } + } + return result; + } + + public void Serialise(Stream stream, Version version) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + var totalLength = this.CalculateSize(version); + NetworkByteOrderConverter.WriteInt24(stream, totalLength-3); + switch (this.CertificateType) + { + case TCertificateType.X509: + { + if (this.CertChain != null) + { + foreach (var item in this.CertChain) + { + NetworkByteOrderConverter.WriteInt24(stream, item.Length); + stream.Write(item, 0, item.Length); + } + } + break; + } + case TCertificateType.OpenPGP: + case TCertificateType.RawPublicKey: + case TCertificateType.Unknown: + { + throw new NotImplementedException(); + } + default: + { + break; + } + } + } + } +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/CertificateRequest.cs b/DTLS.Net/HandshakeMessages/CertificateRequest.cs similarity index 69% rename from src/DTLS.Net/HandshakeMessages/CertificateRequest.cs rename to DTLS.Net/HandshakeMessages/CertificateRequest.cs index d1d58de..c91b0df 100644 --- a/src/DTLS.Net/HandshakeMessages/CertificateRequest.cs +++ b/DTLS.Net/HandshakeMessages/CertificateRequest.cs @@ -23,13 +23,9 @@ products derived from this software without specific prior written permission. using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; namespace DTLS { - - //enum //{ // rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4), @@ -56,34 +52,35 @@ namespace DTLS internal class CertificateRequest : IHandshakeMessage { - public THandshakeType MessageType - { - get { return THandshakeType.CertificateRequest; } - } + public THandshakeType MessageType => THandshakeType.CertificateRequest; public List CertificateTypes { get; private set; } public List SupportedAlgorithms { get; private set; } public List CertificateAuthorities { get; private set; } - public CertificateRequest() { - CertificateTypes = new List(); - SupportedAlgorithms = new List(); - CertificateAuthorities = new List(); + this.CertificateTypes = new List(); + this.SupportedAlgorithms = new List(); + this.CertificateAuthorities = new List(); } public int CalculateSize(Version version) { - int result = 3 + CertificateTypes.Count; + if(version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + var result = 3 + this.CertificateTypes.Count; if (version >= DTLSRecord.Version1_2) { result += 2; - result += (SupportedAlgorithms.Count * 2); + result += (this.SupportedAlgorithms.Count * 2); } - if (CertificateAuthorities.Count > 0) + if (this.CertificateAuthorities.Count > 0) { - foreach (byte[] item in CertificateAuthorities) + foreach (var item in this.CertificateAuthorities) { result += item.Length; } @@ -93,38 +90,50 @@ public int CalculateSize(Version version) public static CertificateRequest Deserialise(Stream stream, Version version) { - CertificateRequest result = new CertificateRequest(); - int certificateTypeCount = stream.ReadByte(); + if(stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + var result = new CertificateRequest(); + var certificateTypeCount = stream.ReadByte(); if (certificateTypeCount > 0) { - for (int index = 0; index < certificateTypeCount; index++) + for (var index = 0; index < certificateTypeCount; index++) { result.CertificateTypes.Add((TClientCertificateType)stream.ReadByte()); } } + if (version >= DTLSRecord.Version1_2) { - ushort length = NetworkByteOrderConverter.ToUInt16(stream); - ushort supportedAlgorithmsLength = (ushort)(length / 2); + var length = NetworkByteOrderConverter.ToUInt16(stream); + var supportedAlgorithmsLength = (ushort)(length / 2); if (supportedAlgorithmsLength > 0) { for (uint index = 0; index < supportedAlgorithmsLength; index++) { - THashAlgorithm hash = (THashAlgorithm)stream.ReadByte(); - TSignatureAlgorithm signature = (TSignatureAlgorithm)stream.ReadByte(); + var hash = (THashAlgorithm)stream.ReadByte(); + var signature = (TSignatureAlgorithm)stream.ReadByte(); result.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash = hash, Signature = signature }); } } } - ushort certificateAuthoritiesLength = NetworkByteOrderConverter.ToUInt16(stream); + + var certificateAuthoritiesLength = NetworkByteOrderConverter.ToUInt16(stream); if (certificateAuthoritiesLength > 0) { - int read = 0; + var read = 0; while(certificateAuthoritiesLength > read) { - ushort distinguishedNameLength = NetworkByteOrderConverter.ToUInt16(stream); + var distinguishedNameLength = NetworkByteOrderConverter.ToUInt16(stream); read += (2 + distinguishedNameLength); - byte[] distinguishedName = new byte[distinguishedNameLength]; + var distinguishedName = new byte[distinguishedNameLength]; stream.Read(distinguishedName, 0, distinguishedNameLength); result.CertificateAuthorities.Add(distinguishedName); } @@ -134,38 +143,50 @@ public static CertificateRequest Deserialise(Stream stream, Version version) public void Serialise(Stream stream, Version version) { - stream.WriteByte((byte)CertificateTypes.Count); - foreach (TClientCertificateType item in CertificateTypes) + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + stream.WriteByte((byte)this.CertificateTypes.Count); + foreach (var item in this.CertificateTypes) { stream.WriteByte((byte)item); } + if (version >= DTLSRecord.Version1_2) { - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)(SupportedAlgorithms.Count * 2)); - foreach (SignatureHashAlgorithm item in SupportedAlgorithms) + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)(this.SupportedAlgorithms.Count * 2)); + foreach (var item in this.SupportedAlgorithms) { stream.WriteByte((byte)item.Hash); stream.WriteByte((byte)item.Signature); } } + ushort certificateAuthoritiesSize = 0; - if (CertificateAuthorities.Count > 0) + if (this.CertificateAuthorities.Count > 0) { - foreach (byte[] item in CertificateAuthorities) + foreach (var item in this.CertificateAuthorities) { certificateAuthoritiesSize += (ushort)item.Length; } } + NetworkByteOrderConverter.WriteUInt16(stream, certificateAuthoritiesSize); - if (CertificateAuthorities.Count > 0) + if (this.CertificateAuthorities.Count > 0) { - foreach (byte[] item in CertificateAuthorities) + foreach (var item in this.CertificateAuthorities) { NetworkByteOrderConverter.WriteUInt16(stream, (ushort)item.Length); stream.Write(item, 0, item.Length); } } } - } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/CertificateVerify.cs b/DTLS.Net/HandshakeMessages/CertificateVerify.cs similarity index 64% rename from src/DTLS.Net/HandshakeMessages/CertificateVerify.cs rename to DTLS.Net/HandshakeMessages/CertificateVerify.cs index cfbf760..b4f5239 100644 --- a/src/DTLS.Net/HandshakeMessages/CertificateVerify.cs +++ b/DTLS.Net/HandshakeMessages/CertificateVerify.cs @@ -21,10 +21,7 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; namespace DTLS { @@ -53,53 +50,90 @@ namespace DTLS // } CertificateVerify; internal class CertificateVerify : IHandshakeMessage { - public THandshakeType MessageType - { - get { return THandshakeType.CertificateVerify; } - } + public THandshakeType MessageType => THandshakeType.CertificateVerify; public SignatureHashAlgorithm SignatureHashAlgorithm { get; set; } - public byte[] Signature { get; set; } + public byte[] Signature { get; set; } public int CalculateSize(Version version) { - int result = 4; - if (Signature != null) + if (version == null) { - result += Signature.Length; + throw new ArgumentNullException(nameof(version)); + } + + var result = 2; + if(version > DTLSRecord.Version1_0) + { + result += 2; + } + + if (this.Signature != null) + { + result += this.Signature.Length; } return result; } public static CertificateVerify Deserialise(Stream stream, Version version) { - CertificateVerify result = new CertificateVerify(); - THashAlgorithm hash = (THashAlgorithm)stream.ReadByte(); - TSignatureAlgorithm signature = (TSignatureAlgorithm)stream.ReadByte(); - result.SignatureHashAlgorithm = new SignatureHashAlgorithm() { Hash = hash, Signature = signature }; - ushort length = NetworkByteOrderConverter.ToUInt16(stream); + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + var result = new CertificateVerify(); + + if (version > DTLSRecord.Version1_0) + { + var hash = (THashAlgorithm)stream.ReadByte(); + var signature = (TSignatureAlgorithm)stream.ReadByte(); + result.SignatureHashAlgorithm = new SignatureHashAlgorithm() { Hash = hash, Signature = signature }; + } + + var length = NetworkByteOrderConverter.ToUInt16(stream); if (length > 0) { result.Signature = new byte[length]; stream.Read(result.Signature, 0, length); } + return result; } public void Serialise(Stream stream, Version version) { - stream.WriteByte((byte)SignatureHashAlgorithm.Hash); - stream.WriteByte((byte)SignatureHashAlgorithm.Signature); - if (Signature == null) + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + if (version > DTLSRecord.Version1_0) + { + stream.WriteByte((byte)this.SignatureHashAlgorithm.Hash); + stream.WriteByte((byte)this.SignatureHashAlgorithm.Signature); + } + + if (this.Signature == null) { - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)0); + NetworkByteOrderConverter.WriteUInt16(stream, 0); } else { - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)Signature.Length); - stream.Write(Signature, 0, Signature.Length); + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.Signature.Length); + stream.Write(this.Signature, 0, this.Signature.Length); } } } -} +} \ No newline at end of file diff --git a/DTLS.Net/HandshakeMessages/ClientHello.cs b/DTLS.Net/HandshakeMessages/ClientHello.cs new file mode 100644 index 0000000..a1d4d00 --- /dev/null +++ b/DTLS.Net/HandshakeMessages/ClientHello.cs @@ -0,0 +1,245 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using System; +using System.IO; +using System.Net; +using System.Security.Cryptography; + +namespace DTLS +{ + + //opaque SessionID<0..32>; + + // uint8 CipherSuite[2]; /* Cryptographic suite selector */ + + // enum { null(0), (255) } CompressionMethod; + + + // struct { + // ExtensionType extension_type; + // opaque extension_data<0..2^16-1>; + //} Extension; + + //enum { + // signature_algorithms(13), (65535) + //} ExtensionType; + + // struct { + //ProtocolVersion client_version; + //Random random; + //SessionID session_id; + //opaque cookie<0..2^8-1>; // New field + //CipherSuite cipher_suites<2..2^16-1>; + //CompressionMethod compression_methods<1..2^8-1>; + // select (extensions_present) { + // case false: + // struct {}; + // case true: + // Extension extensions<0..2^16-1>; + // }; + //} ClientHello; + internal class ClientHello: IHandshakeMessage + { + public THandshakeType MessageType => THandshakeType.ClientHello; + + public Version ClientVersion { get; set; } + + public RandomData Random { get; set; } + + public byte[] SessionID { get; set; } + + public byte[] Cookie { get; set; } + + public ushort[] CipherSuites { get; set; } + + public byte[] CompressionMethods { get; set; } + + public Extensions Extensions { get; set; } + + public int CalculateSize(Version version) + { + var result = 39; // Version (2 bytes) + Random (32 bytes) + SessionIDLength (1 byte) + _CompressionMethodsLength (1 byte) + // + CookieLength (1 byte) + CipherSuitesLength (2 bytes) + if (this.SessionID != null) + { + result += this.SessionID.Length; + } + + if (this.Cookie != null) + { + result += this.Cookie.Length; + } + + if (this.CipherSuites != null) + { + result += (this.CipherSuites.Length * 2); + } + + if (this.CompressionMethods != null) + { + result += this.CompressionMethods.Length; + } + + if (this.Extensions == null) + { + result += 2; + } + else + { + result += this.Extensions.CalculateSize(); + } + + return result; + } + + public byte[] CalculateCookie(EndPoint remoteEndPoint, byte[] secret) + { + if (remoteEndPoint == null) + { + throw new ArgumentNullException(nameof(remoteEndPoint)); + } + + if (secret == null) + { + throw new ArgumentNullException(nameof(secret)); + } + + //Cookie = HMAC(Secret, Client-IP, Client-Parameters) + //(version, random, session_id, cipher_suites, compression_method) + var result = new byte[32]; + var socketAddress = remoteEndPoint.Serialize(); + var socketAddressSize = socketAddress.Size; + var message = new byte[socketAddressSize + 34]; + for (var index = 0; index < socketAddressSize; index++) + { + message[0] = socketAddress[index]; + } + NetworkByteOrderConverter.WriteUInt32(message, socketAddressSize, this.Random.UnixTime); + Buffer.BlockCopy(this.Random.RandomBytes, 0, message, socketAddressSize + 4, 28); + var hmac = new HMACSHA256(secret); + var hash = hmac.ComputeHash(message); + Buffer.BlockCopy(hash, 0, result, 0, 32); + return result; + } + + public static ClientHello Deserialise(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new ClientHello + { + ClientVersion = new Version(255 - stream.ReadByte(), 255 - stream.ReadByte()), + Random = RandomData.Deserialise(stream) + }; + + var length = stream.ReadByte(); + if (length > 0) + { + result.SessionID = new byte[length]; + stream.Read(result.SessionID, 0, length); + } + + length = stream.ReadByte(); + if (length > 0) + { + result.Cookie = new byte[length]; + stream.Read(result.Cookie, 0, length); + } + + var cipherSuitesLength = (ushort)(NetworkByteOrderConverter.ToUInt16(stream) / 2); + if (cipherSuitesLength > 0) + { + result.CipherSuites = new ushort[cipherSuitesLength]; + for (uint index = 0; index < cipherSuitesLength; index++) + { + result.CipherSuites[index] = NetworkByteOrderConverter.ToUInt16(stream); + } + } + + length = stream.ReadByte(); + if (length > 0) + { + result.CompressionMethods = new byte[length]; + stream.Read(result.CompressionMethods, 0, length); + } + + result.Extensions = Extensions.Deserialise(stream, true); + return result; + } + + public void Serialise(Stream stream, Version version) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + stream.WriteByte((byte)(255 - this.ClientVersion.Major)); + stream.WriteByte((byte)(255 - this.ClientVersion.Minor)); + this.Random.Serialise(stream); + if (this.SessionID == null) + { + stream.WriteByte(0); + } + else + { + stream.WriteByte((byte)this.SessionID.Length); + stream.Write(this.SessionID, 0, this.SessionID.Length); + } + + if (this.Cookie == null) + { + stream.WriteByte(0); + } + else + { + stream.WriteByte((byte)this.Cookie.Length); + stream.Write(this.Cookie, 0, this.Cookie.Length); + } + + if (this.CipherSuites.Length > 0) + { + NetworkByteOrderConverter.WriteUInt16(stream,(ushort)(this.CipherSuites.Length * 2)); + for (var index = 0; index < this.CipherSuites.Length; index++) + { + NetworkByteOrderConverter.WriteUInt16(stream, this.CipherSuites[index]); + } + } + + stream.WriteByte((byte)this.CompressionMethods.Length); + stream.Write(this.CompressionMethods, 0, this.CompressionMethods.Length); + + if (this.Extensions == null) + { + NetworkByteOrderConverter.WriteUInt16(stream, 0); + } + else + { + this.Extensions.Serialise(stream); + } + } + } +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/Extensions/ClientCertificateTypeExtension.cs b/DTLS.Net/HandshakeMessages/Extensions/ClientCertificateTypeExtension.cs similarity index 62% rename from src/DTLS.Net/HandshakeMessages/Extensions/ClientCertificateTypeExtension.cs rename to DTLS.Net/HandshakeMessages/Extensions/ClientCertificateTypeExtension.cs index c64187d..6f71a57 100644 --- a/src/DTLS.Net/HandshakeMessages/Extensions/ClientCertificateTypeExtension.cs +++ b/DTLS.Net/HandshakeMessages/Extensions/ClientCertificateTypeExtension.cs @@ -21,69 +21,62 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace DTLS { - // struct { - // select(ClientOrServerExtension) { - // case client: - // CertificateType client_certificate_types<1..2^8-1>; - // case server: - // CertificateType client_certificate_type; - // } - //} ClientCertTypeExtension; - internal class ClientCertificateTypeExtension : IExtension + // struct { + // select(ClientOrServerExtension) { + // case client: + // CertificateType client_certificate_types<1..2^8-1>; + // case server: + // CertificateType client_certificate_type; + // } + //} ClientCertTypeExtension; + internal class ClientCertificateTypeExtension : IExtension { - private byte[] _CertificateTypes; + public TExtensionType ExtensionType => TExtensionType.ClientCertificateType; - public TExtensionType ExtensionType { get { return TExtensionType.ClientCertificateType; } } + public byte[] CertificateTypes { get; set; } - public byte[] CertificateTypes - { - get { return _CertificateTypes; } - set { _CertificateTypes = value; } - } - - public ClientCertificateTypeExtension() - { - - } + public ClientCertificateTypeExtension() { } public ClientCertificateTypeExtension(TCertificateType certificateType) { - _CertificateTypes = new byte[1]; - _CertificateTypes[0] = (byte)certificateType; + this.CertificateTypes = new byte[1]; + this.CertificateTypes[0] = (byte)certificateType; } - public int CalculateSize() { - int result = 1; - if (_CertificateTypes != null) - result += _CertificateTypes.Length; - return result; + var result = 1; + if (this.CertificateTypes != null) + { + result += this.CertificateTypes.Length; + } + + return result; } public static ClientCertificateTypeExtension Deserialise(Stream stream, bool client) { - ClientCertificateTypeExtension result = new ClientCertificateTypeExtension(); - ushort length = NetworkByteOrderConverter.ToUInt16(stream); + if(stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new ClientCertificateTypeExtension(); + var length = NetworkByteOrderConverter.ToUInt16(stream); if (length > 0) { - result._CertificateTypes = new byte[length]; - stream.Read(result._CertificateTypes, 0, length); + result.CertificateTypes = new byte[length]; + stream.Read(result.CertificateTypes, 0, length); } + return result; } - public void Serialise(Stream stream) - { - - } - } + public void Serialise(Stream stream) => throw new NotImplementedException(); + } } diff --git a/src/DTLS.Net/HandshakeMessages/Extensions/EllipticCurvePointFormatsExtension.cs b/DTLS.Net/HandshakeMessages/Extensions/EllipticCurvePointFormatsExtension.cs similarity index 64% rename from src/DTLS.Net/HandshakeMessages/Extensions/EllipticCurvePointFormatsExtension.cs rename to DTLS.Net/HandshakeMessages/Extensions/EllipticCurvePointFormatsExtension.cs index 5cf2dda..b792df8 100644 --- a/src/DTLS.Net/HandshakeMessages/Extensions/EllipticCurvePointFormatsExtension.cs +++ b/DTLS.Net/HandshakeMessages/Extensions/EllipticCurvePointFormatsExtension.cs @@ -22,46 +22,46 @@ products derived from this software without specific prior written permission. using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace DTLS { - //rfc4492 section 5.1.2 - // enum { uncompressed (0), ansiX962_compressed_prime (1), - // ansiX962_compressed_char2 (2), reserved (248..255) - //} ECPointFormat; + //rfc4492 section 5.1.2 + // enum { uncompressed (0), ansiX962_compressed_prime (1), + // ansiX962_compressed_char2 (2), reserved (248..255) + //} ECPointFormat; - //struct { - // ECPointFormat ec_point_format_list<1..2^8-1> - //} ECPointFormatList; - internal class EllipticCurvePointFormatsExtension: IExtension + //struct { + // ECPointFormat ec_point_format_list<1..2^8-1> + //} ECPointFormatList; + internal class EllipticCurvePointFormatsExtension: IExtension { - List _SupportedPointFormats; + public TExtensionType ExtensionType => TExtensionType.EllipticCurvePointFormats; + public List SupportedPointFormats { get; } - public TExtensionType ExtensionType { get { return TExtensionType.EllipticCurvePointFormats;} } + public EllipticCurvePointFormatsExtension() => this.SupportedPointFormats = new List(); - public List SupportedPointFormats { get { return _SupportedPointFormats; } } - - public EllipticCurvePointFormatsExtension() - { - _SupportedPointFormats = new List(); - } - - public int CalculateSize() + public int CalculateSize() { - int result = 1; - if (_SupportedPointFormats != null) - result += _SupportedPointFormats.Count; - return result; + var result = 1; + if (this.SupportedPointFormats != null) + { + result += this.SupportedPointFormats.Count; + } + + return result; } public static EllipticCurvePointFormatsExtension Deserialise(Stream stream) { - EllipticCurvePointFormatsExtension result = new EllipticCurvePointFormatsExtension(); - int length = stream.ReadByte(); + if(stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new EllipticCurvePointFormatsExtension(); + var length = stream.ReadByte(); if (length > 0) { for (uint index = 0; index < length; index++) @@ -74,12 +74,16 @@ public static EllipticCurvePointFormatsExtension Deserialise(Stream stream) public void Serialise(Stream stream) { - stream.WriteByte((byte)_SupportedPointFormats.Count); - foreach (TEllipticCurvePointFormat item in _SupportedPointFormats) + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + stream.WriteByte((byte)this.SupportedPointFormats.Count); + foreach (var item in this.SupportedPointFormats) { stream.WriteByte((byte)item); } } - } } diff --git a/src/DTLS.Net/HandshakeMessages/Extensions/EllipticCurvesExtension.cs b/DTLS.Net/HandshakeMessages/Extensions/EllipticCurvesExtension.cs similarity index 57% rename from src/DTLS.Net/HandshakeMessages/Extensions/EllipticCurvesExtension.cs rename to DTLS.Net/HandshakeMessages/Extensions/EllipticCurvesExtension.cs index 75ed225..12d7832 100644 --- a/src/DTLS.Net/HandshakeMessages/Extensions/EllipticCurvesExtension.cs +++ b/DTLS.Net/HandshakeMessages/Extensions/EllipticCurvesExtension.cs @@ -22,61 +22,62 @@ products derived from this software without specific prior written permission. using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace DTLS { - //rfc4492 section 5.1.2 - //enum { - // sect163k1 (1), sect163r1 (2), sect163r2 (3), - // sect193r1 (4), sect193r2 (5), sect233k1 (6), - // sect233r1 (7), sect239k1 (8), sect283k1 (9), - // sect283r1 (10), sect409k1 (11), sect409r1 (12), - // sect571k1 (13), sect571r1 (14), secp160k1 (15), - // secp160r1 (16), secp160r2 (17), secp192k1 (18), - // secp192r1 (19), secp224k1 (20), secp224r1 (21), - // secp256k1 (22), secp256r1 (23), secp384r1 (24), - // secp521r1 (25), - // reserved (0xFE00..0xFEFF), - // arbitrary_explicit_prime_curves(0xFF01), - // arbitrary_explicit_char2_curves(0xFF02), - // (0xFFFF) - //} NamedCurve; - - //struct { - // NamedCurve elliptic_curve_list<1..2^16-1> - //} EllipticCurveList; - - internal class EllipticCurvesExtension : IExtension - { - List _SupportedCurves; + //rfc4492 section 5.1.2 + //enum { + // sect163k1 (1), sect163r1 (2), sect163r2 (3), + // sect193r1 (4), sect193r2 (5), sect233k1 (6), + // sect233r1 (7), sect239k1 (8), sect283k1 (9), + // sect283r1 (10), sect409k1 (11), sect409r1 (12), + // sect571k1 (13), sect571r1 (14), secp160k1 (15), + // secp160r1 (16), secp160r2 (17), secp192k1 (18), + // secp192r1 (19), secp224k1 (20), secp224r1 (21), + // secp256k1 (22), secp256r1 (23), secp384r1 (24), + // secp521r1 (25), + // reserved (0xFE00..0xFEFF), + // arbitrary_explicit_prime_curves(0xFF01), + // arbitrary_explicit_char2_curves(0xFF02), + // (0xFFFF) + //} NamedCurve; - public TExtensionType ExtensionType { get { return TExtensionType.EllipticCurves; } } + //struct { + // NamedCurve elliptic_curve_list<1..2^16-1> + //} EllipticCurveList; - public List SupportedCurves { get { return _SupportedCurves; } } + internal class EllipticCurvesExtension : IExtension + { + public TExtensionType ExtensionType => TExtensionType.EllipticCurves; - public EllipticCurvesExtension() - { - _SupportedCurves = new List(); - } + public List SupportedCurves { get; } + + public EllipticCurvesExtension() => this.SupportedCurves = new List(); - public int CalculateSize() + public int CalculateSize() { - int result = 2; - if (_SupportedCurves != null) - result += (_SupportedCurves.Count * 2); - return result; + var result = 2; + if (this.SupportedCurves != null) + { + result += (this.SupportedCurves.Count * 2); + } + + return result; } public static EllipticCurvesExtension Deserialise(Stream stream) { - EllipticCurvesExtension result = new EllipticCurvesExtension(); - ushort length = NetworkByteOrderConverter.ToUInt16(stream); - ushort supportedCurvesLength = (ushort)(length / 2); + if(stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new EllipticCurvesExtension(); + var length = NetworkByteOrderConverter.ToUInt16(stream); + var supportedCurvesLength = (ushort)(length / 2); if (supportedCurvesLength > 0) { for (uint index = 0; index < supportedCurvesLength; index++) @@ -84,21 +85,29 @@ public static EllipticCurvesExtension Deserialise(Stream stream) result.SupportedCurves.Add((TEllipticCurve)NetworkByteOrderConverter.ToUInt16(stream)); } } + return result; } public void Serialise(Stream stream) { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + ushort length = 0; - if (_SupportedCurves == null) + if (this.SupportedCurves == null) + { NetworkByteOrderConverter.WriteUInt16(stream, length); + } else { - length = (ushort)(_SupportedCurves.Count * 2); + length = (ushort)(this.SupportedCurves.Count * 2); NetworkByteOrderConverter.WriteUInt16(stream, length); - for (int index = 0; index < _SupportedCurves.Count; index++) + for (var index = 0; index < this.SupportedCurves.Count; index++) { - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)_SupportedCurves[index]); + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.SupportedCurves[index]); } } } diff --git a/src/DTLS.Net/HandshakeMessages/Extensions/Extension.cs b/DTLS.Net/HandshakeMessages/Extensions/Extension.cs similarity index 53% rename from src/DTLS.Net/HandshakeMessages/Extensions/Extension.cs rename to DTLS.Net/HandshakeMessages/Extensions/Extension.cs index 6d37008..6d2810b 100644 --- a/src/DTLS.Net/HandshakeMessages/Extensions/Extension.cs +++ b/DTLS.Net/HandshakeMessages/Extensions/Extension.cs @@ -21,112 +21,102 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace DTLS { - // struct { - // ExtensionType extension_type; - // opaque extension_data<0..2^16-1>; - //} Extension; + // struct { + // ExtensionType extension_type; + // opaque extension_data<0..2^16-1>; + //} Extension; - internal class Extension + internal class Extension { - TExtensionType _ExtensionType; - IExtension _SpecifcExtension; - byte[] _Data; + public TExtensionType ExtensionType { get; set; } - public TExtensionType ExtensionType - { - get { return _ExtensionType; } - set { _ExtensionType = value; } - } - - public byte[] Data - { - get { return _Data; } - set { _Data = value; } - } + public byte[] Data { get; set; } - public IExtension SpecifcExtension - { - get { return _SpecifcExtension; } - set { _SpecifcExtension = value; } - } + public IExtension SpecificExtension { get; set; } - public int CalculateSize() + public int CalculateSize() { - int result = 4; - if (_SpecifcExtension != null) + var result = 4; + if (this.SpecificExtension != null) { - result += _SpecifcExtension.CalculateSize(); + result += this.SpecificExtension.CalculateSize(); } return result; } - public Extension() - { + public Extension() { } - } - - public Extension(IExtension specifcExtension) + public Extension(IExtension specificExtension) { - _ExtensionType = specifcExtension.ExtensionType; - _SpecifcExtension = specifcExtension; + this.ExtensionType = specificExtension.ExtensionType; + this.SpecificExtension = specificExtension; } - public static Extension Deserialise(Stream stream, bool client) { + if(stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + Extension result = null; if (stream.Position < stream.Length) { - result = new Extension(); - result._ExtensionType = (TExtensionType)NetworkByteOrderConverter.ToUInt16(stream); - ushort length = NetworkByteOrderConverter.ToUInt16(stream); + result = new Extension + { + ExtensionType = (TExtensionType)NetworkByteOrderConverter.ToUInt16(stream) + }; + + var length = NetworkByteOrderConverter.ToUInt16(stream); if (length > 0) { - if (result._ExtensionType == TExtensionType.EllipticCurves) + if (result.ExtensionType == TExtensionType.EllipticCurves) { - result._SpecifcExtension = EllipticCurvesExtension.Deserialise(stream); + result.SpecificExtension = EllipticCurvesExtension.Deserialise(stream); } - else if (result._ExtensionType == TExtensionType.ClientCertificateType) + else if (result.ExtensionType == TExtensionType.ClientCertificateType) { - result._SpecifcExtension = ClientCertificateTypeExtension.Deserialise(stream, client); + result.SpecificExtension = ClientCertificateTypeExtension.Deserialise(stream, client); } - else if (result._ExtensionType == TExtensionType.ServerCertificateType) + else if (result.ExtensionType == TExtensionType.ServerCertificateType) { - result._SpecifcExtension = ServerCertificateTypeExtension.Deserialise(stream, client); + result.SpecificExtension = ServerCertificateTypeExtension.Deserialise(stream, client); } - else if (result._ExtensionType == TExtensionType.SignatureAlgorithms) + else if (result.ExtensionType == TExtensionType.SignatureAlgorithms) { - result._SpecifcExtension = SignatureAlgorithmsExtension.Deserialise(stream); - } + result.SpecificExtension = SignatureAlgorithmsExtension.Deserialise(stream); + } else { - result._Data = new byte[length]; - stream.Read(result._Data, 0, length); + result.Data = new byte[length]; + stream.Read(result.Data, 0, length); } } } return result; } - public void Serialise(System.IO.Stream stream) + public void Serialise(Stream stream) { - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)_ExtensionType); - int length = 0; - if (_SpecifcExtension != null) + if(stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.ExtensionType); + var length = 0; + if (this.SpecificExtension != null) { - length += _SpecifcExtension.CalculateSize(); + length += this.SpecificExtension.CalculateSize(); } NetworkByteOrderConverter.WriteUInt16(stream, (ushort)length); - if (_SpecifcExtension != null) + if (this.SpecificExtension != null) { - _SpecifcExtension.Serialise(stream); + this.SpecificExtension.Serialise(stream); } } } diff --git a/src/DTLS.Net/HandshakeMessages/Extensions/Extensions.cs b/DTLS.Net/HandshakeMessages/Extensions/Extensions.cs similarity index 76% rename from src/DTLS.Net/HandshakeMessages/Extensions/Extensions.cs rename to DTLS.Net/HandshakeMessages/Extensions/Extensions.cs index 8b42d40..4a63b8e 100644 --- a/src/DTLS.Net/HandshakeMessages/Extensions/Extensions.cs +++ b/DTLS.Net/HandshakeMessages/Extensions/Extensions.cs @@ -22,31 +22,29 @@ products derived from this software without specific prior written permission. using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace DTLS { - // Extension extensions<0..2^16-1>; + // Extension extensions<0..2^16-1>; - // struct { - // ExtensionType extension_type; - // opaque extension_data<0..2^16-1>; - //} Extension; + // struct { + // ExtensionType extension_type; + // opaque extension_data<0..2^16-1>; + //} Extension; - //enum { - // signature_algorithms(13), (65535) - //} ExtensionType; + //enum { + // signature_algorithms(13), (65535) + //} ExtensionType; - internal class Extensions : List + internal class Extensions : List { public int CalculateSize() { - int result = 2; - foreach (Extension item in this) + var result = 2; + foreach (var item in this) { result += item.CalculateSize(); } @@ -55,14 +53,19 @@ public int CalculateSize() public static Extensions Deserialise(Stream stream, bool client) { + if(stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + Extensions result = null; if (stream.Position < stream.Length) { result = new Extensions(); - ushort length = NetworkByteOrderConverter.ToUInt16(stream); + var length = NetworkByteOrderConverter.ToUInt16(stream); if (length > 0) { - Extension extension = Extension.Deserialise(stream, client); + var extension = Extension.Deserialise(stream, client); while (extension != null) { result.Add(extension); @@ -73,19 +76,23 @@ public static Extensions Deserialise(Stream stream, bool client) return result; } - public void Serialise(System.IO.Stream stream) + public void Serialise(Stream stream) { + if(stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + uint length = 0; - foreach (Extension item in this) + foreach (var item in this) { length += (uint)item.CalculateSize(); } NetworkByteOrderConverter.WriteUInt16(stream, (ushort)length); - foreach (Extension item in this) + foreach (var item in this) { item.Serialise(stream); } } - } } diff --git a/src/DTLS.Net/HandshakeMessages/Extensions/IExtension.cs b/DTLS.Net/HandshakeMessages/Extensions/IExtension.cs similarity index 94% rename from src/DTLS.Net/HandshakeMessages/Extensions/IExtension.cs rename to DTLS.Net/HandshakeMessages/Extensions/IExtension.cs index f297ca8..e54921a 100644 --- a/src/DTLS.Net/HandshakeMessages/Extensions/IExtension.cs +++ b/DTLS.Net/HandshakeMessages/Extensions/IExtension.cs @@ -20,14 +20,10 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - internal interface IExtension + internal interface IExtension { TExtensionType ExtensionType { get; } diff --git a/src/DTLS.Net/HandshakeMessages/Extensions/ServerCertificateTypeExtension.cs b/DTLS.Net/HandshakeMessages/Extensions/ServerCertificateTypeExtension.cs similarity index 61% rename from src/DTLS.Net/HandshakeMessages/Extensions/ServerCertificateTypeExtension.cs rename to DTLS.Net/HandshakeMessages/Extensions/ServerCertificateTypeExtension.cs index 81cc996..534c3ab 100644 --- a/src/DTLS.Net/HandshakeMessages/Extensions/ServerCertificateTypeExtension.cs +++ b/DTLS.Net/HandshakeMessages/Extensions/ServerCertificateTypeExtension.cs @@ -21,64 +21,54 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace DTLS { - //struct { - // select(ClientOrServerExtension) { - // case client: - // CertificateType server_certificate_types<1..2^8-1>; - // case server: - // CertificateType server_certificate_type; - // } - // } ServerCertTypeExtension; - internal class ServerCertificateTypeExtension : IExtension + //struct { + // select(ClientOrServerExtension) { + // case client: + // CertificateType server_certificate_types<1..2^8-1>; + // case server: + // CertificateType server_certificate_type; + // } + // } ServerCertTypeExtension; + internal class ServerCertificateTypeExtension : IExtension { - private byte _CertificateType; + public TExtensionType ExtensionType => TExtensionType.ServerCertificateType; - public TExtensionType ExtensionType { get { return TExtensionType.ServerCertificateType; } } + public byte CertificateType { get; set; } - public byte CertificateType - { - get { return _CertificateType; } - set { _CertificateType = value; } - } - - public ServerCertificateTypeExtension() - { + public ServerCertificateTypeExtension() { } - } + public ServerCertificateTypeExtension(TCertificateType certificateType) => this.CertificateType = (byte)certificateType; - public ServerCertificateTypeExtension(TCertificateType certificateType) - { - _CertificateType= (byte)certificateType; - } + public int CalculateSize() => 1; - public int CalculateSize() + public static ServerCertificateTypeExtension Deserialise(Stream stream, bool client) { - int result = 1; - return result; - } + if(stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } - public static ServerCertificateTypeExtension Deserialise(Stream stream, bool client) - { - ServerCertificateTypeExtension result = new ServerCertificateTypeExtension(); - int certificateType = stream.ReadByte(); + var result = new ServerCertificateTypeExtension(); + var certificateType = stream.ReadByte(); if (certificateType >= 0) { - result._CertificateType = (byte)certificateType; + result.CertificateType = (byte)certificateType; } return result; } public void Serialise(Stream stream) { - stream.WriteByte(_CertificateType); + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + stream.WriteByte(this.CertificateType); } } - } diff --git a/src/DTLS.Net/HandshakeMessages/Extensions/SignatureAlgorithmsExtension.cs b/DTLS.Net/HandshakeMessages/Extensions/SignatureAlgorithmsExtension.cs similarity index 55% rename from src/DTLS.Net/HandshakeMessages/Extensions/SignatureAlgorithmsExtension.cs rename to DTLS.Net/HandshakeMessages/Extensions/SignatureAlgorithmsExtension.cs index b9504b4..9a3d744 100644 --- a/src/DTLS.Net/HandshakeMessages/Extensions/SignatureAlgorithmsExtension.cs +++ b/DTLS.Net/HandshakeMessages/Extensions/SignatureAlgorithmsExtension.cs @@ -22,83 +22,89 @@ products derived from this software without specific prior written permission. using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace DTLS { - // enum { - // none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), - // sha512(6), (255) - //} HashAlgorithm; + // enum { + // none(0), md5(1), sha1(2), sha224(3), sha256(4), sha384(5), + // sha512(6), (255) + //} HashAlgorithm; - //enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } - // SignatureAlgorithm; + //enum { anonymous(0), rsa(1), dsa(2), ecdsa(3), (255) } + // SignatureAlgorithm; - //struct { - // HashAlgorithm hash; - // SignatureAlgorithm signature; - //} SignatureAndHashAlgorithm; + //struct { + // HashAlgorithm hash; + // SignatureAlgorithm signature; + //} SignatureAndHashAlgorithm; - //SignatureAndHashAlgorithm - // supported_signature_algorithms<2..2^16-2>; + //SignatureAndHashAlgorithm + // supported_signature_algorithms<2..2^16-2>; - - internal class SignatureAlgorithmsExtension : IExtension + internal class SignatureAlgorithmsExtension : IExtension { - public TExtensionType ExtensionType { get { return TExtensionType.SignatureAlgorithms; } } + public TExtensionType ExtensionType => TExtensionType.SignatureAlgorithms; + public List SupportedAlgorithms { get; private set; } - public List SupportedAlgorithms { get; private set; } + public SignatureAlgorithmsExtension() => this.SupportedAlgorithms = new List(); - public SignatureAlgorithmsExtension() + public int CalculateSize() { - SupportedAlgorithms = new List(); - } + var result = 2; + if (this.SupportedAlgorithms != null) + { + result += (this.SupportedAlgorithms.Count * 2); + } - public int CalculateSize() - { - int result = 2; - if (SupportedAlgorithms != null) - result += (SupportedAlgorithms.Count * 2); - return result; + return result; } - public static SignatureAlgorithmsExtension Deserialise(Stream stream) { - SignatureAlgorithmsExtension result = new SignatureAlgorithmsExtension(); - ushort length = NetworkByteOrderConverter.ToUInt16(stream); - ushort supportedAlgorithmsLength = (ushort)(length / 2); + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new SignatureAlgorithmsExtension(); + var length = NetworkByteOrderConverter.ToUInt16(stream); + var supportedAlgorithmsLength = (ushort)(length / 2); if (supportedAlgorithmsLength > 0) { for (uint index = 0; index < supportedAlgorithmsLength; index++) { - THashAlgorithm hash = (THashAlgorithm)stream.ReadByte(); - TSignatureAlgorithm signature = (TSignatureAlgorithm)stream.ReadByte(); + var hash = (THashAlgorithm)stream.ReadByte(); + var signature = (TSignatureAlgorithm)stream.ReadByte(); result.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash = hash, Signature = signature }); } } + return result; } public void Serialise(Stream stream) { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + ushort length = 0; - if (SupportedAlgorithms == null) - NetworkByteOrderConverter.WriteUInt16(stream, length); - else + if (this.SupportedAlgorithms == null) { - length = (ushort)(SupportedAlgorithms.Count * 2); NetworkByteOrderConverter.WriteUInt16(stream, length); - for (int index = 0; index < SupportedAlgorithms.Count; index++) - { - stream.WriteByte((byte)SupportedAlgorithms[index].Hash); - stream.WriteByte((byte)SupportedAlgorithms[index].Signature); - } + return; } - } + length = (ushort)(this.SupportedAlgorithms.Count * 2); + NetworkByteOrderConverter.WriteUInt16(stream, length); + for (var index = 0; index < this.SupportedAlgorithms.Count; index++) + { + stream.WriteByte((byte)this.SupportedAlgorithms[index].Hash); + stream.WriteByte((byte)this.SupportedAlgorithms[index].Signature); + } + } } } diff --git a/src/DTLS.Net/HandshakeMessages/Extensions/TEllipticCurvePointFormat.cs b/DTLS.Net/HandshakeMessages/Extensions/TEllipticCurvePointFormat.cs similarity index 92% rename from src/DTLS.Net/HandshakeMessages/Extensions/TEllipticCurvePointFormat.cs rename to DTLS.Net/HandshakeMessages/Extensions/TEllipticCurvePointFormat.cs index dc60f5d..0e0da8a 100644 --- a/src/DTLS.Net/HandshakeMessages/Extensions/TEllipticCurvePointFormat.cs +++ b/DTLS.Net/HandshakeMessages/Extensions/TEllipticCurvePointFormat.cs @@ -20,15 +20,11 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - //rfc4492 section 5.1.2 - internal enum TEllipticCurvePointFormat + //rfc4492 section 5.1.2 + internal enum TEllipticCurvePointFormat { Uncompressed = 0, AnsiX962CompressedPrime = 1, diff --git a/src/DTLS.Net/HandshakeMessages/Extensions/TExtensionType.cs b/DTLS.Net/HandshakeMessages/Extensions/TExtensionType.cs similarity index 96% rename from src/DTLS.Net/HandshakeMessages/Extensions/TExtensionType.cs rename to DTLS.Net/HandshakeMessages/Extensions/TExtensionType.cs index f27f1e7..0388f96 100644 --- a/src/DTLS.Net/HandshakeMessages/Extensions/TExtensionType.cs +++ b/DTLS.Net/HandshakeMessages/Extensions/TExtensionType.cs @@ -20,10 +20,6 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { @@ -57,5 +53,4 @@ internal enum TExtensionType RenegotiationInfo = 65281 //(65535) } -} - +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/Finished.cs b/DTLS.Net/HandshakeMessages/Finished.cs similarity index 62% rename from src/DTLS.Net/HandshakeMessages/Finished.cs rename to DTLS.Net/HandshakeMessages/Finished.cs index 178db87..9e0b386 100644 --- a/src/DTLS.Net/HandshakeMessages/Finished.cs +++ b/DTLS.Net/HandshakeMessages/Finished.cs @@ -21,56 +21,58 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace DTLS { - - //struct { - // opaque verify_data[verify_data_length]; - //} Finished; - //verify_data - // PRF(master_secret, finished_label, Hash(handshake_messages)) - // [0..verify_data_length-1]; + //struct { + // opaque verify_data[verify_data_length]; + //} Finished; - //finished_label - // For Finished messages sent by the client, the string - // "client finished". For Finished messages sent by the server, - // the string "server finished". + //verify_data + // PRF(master_secret, finished_label, Hash(handshake_messages)) + // [0..verify_data_length-1]; - //verify_data_length default = 12 + //finished_label + // For Finished messages sent by the client, the string + // "client finished". For Finished messages sent by the server, + // the string "server finished". - internal class Finished : IHandshakeMessage + //verify_data_length default = 12 + + internal class Finished : IHandshakeMessage { - private byte[] _VerifyData; + public THandshakeType MessageType => THandshakeType.Finished; - public THandshakeType MessageType - { - get { return THandshakeType.Finished; } - } + public byte[] VerifyData { get; set; } - public byte[] VerifyData { get { return _VerifyData; } set { _VerifyData = value;} } + public int CalculateSize(Version version) => 12; - public int CalculateSize(Version version) + public static Finished Deserialise(Stream stream) { - return 12; - } - - public static Finished Deserialise(Stream stream) - { - Finished result = new Finished(); - result._VerifyData = new byte[12]; - stream.Read(result._VerifyData, 0, 12); + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new Finished + { + VerifyData = new byte[12] + }; + + stream.Read(result.VerifyData, 0, 12); return result; } public void Serialise(Stream stream, Version version) { - stream.Write(_VerifyData, 0, _VerifyData.Length); + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + stream.Write(this.VerifyData, 0, this.VerifyData.Length); } } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/HelloRequest.cs b/DTLS.Net/HandshakeMessages/HelloRequest.cs similarity index 93% rename from src/DTLS.Net/HandshakeMessages/HelloRequest.cs rename to DTLS.Net/HandshakeMessages/HelloRequest.cs index 42bcf3e..3d0aeeb 100644 --- a/src/DTLS.Net/HandshakeMessages/HelloRequest.cs +++ b/DTLS.Net/HandshakeMessages/HelloRequest.cs @@ -20,15 +20,8 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - internal class HelloRequest - { - - } + internal class HelloRequest { } } diff --git a/src/DTLS.Net/HandshakeMessages/HelloVerifyRequest.cs b/DTLS.Net/HandshakeMessages/HelloVerifyRequest.cs similarity index 57% rename from src/DTLS.Net/HandshakeMessages/HelloVerifyRequest.cs rename to DTLS.Net/HandshakeMessages/HelloVerifyRequest.cs index d272b3d..26e208e 100644 --- a/src/DTLS.Net/HandshakeMessages/HelloVerifyRequest.cs +++ b/DTLS.Net/HandshakeMessages/HelloVerifyRequest.cs @@ -21,69 +21,67 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace DTLS { - - //struct { - // ProtocolVersion server_version; - // opaque cookie<0..2^8-1>; } HelloVerifyRequest; - internal class HelloVerifyRequest : IHandshakeMessage + + //struct { + // ProtocolVersion server_version; + // opaque cookie<0..2^8-1>; } HelloVerifyRequest; + internal class HelloVerifyRequest : IHandshakeMessage { - Version _ServerVersion; - byte[] _Cookie; + public THandshakeType MessageType => THandshakeType.HelloVerifyRequest; - public THandshakeType MessageType { get { return THandshakeType.HelloVerifyRequest;} } + public Version ServerVersion { get; set; } + public byte[] Cookie { get; set; } - public Version ServerVersion - { - get { return _ServerVersion; } - set { _ServerVersion = value; } - } + public HelloVerifyRequest() => this.ServerVersion = ServerHello.DefaultVersion; - public byte[] Cookie + public int CalculateSize(Version version) { - get { return _Cookie; } - set { _Cookie = value; } - } + var result = 3; //Version + Length of cookie + if (this.Cookie != null) + { + result += this.Cookie.Length; + } - public HelloVerifyRequest() - { - _ServerVersion = ServerHello.DefaultVersion; - } - - public int CalculateSize(Version version) - { - int result = 3; //Version + Length of cookie - if (_Cookie != null) - result += _Cookie.Length; - return result; + return result; } public static HelloVerifyRequest Deserialise(Stream stream) { - HelloVerifyRequest result = new HelloVerifyRequest(); - result._ServerVersion = new Version(255 - stream.ReadByte(), 255 - stream.ReadByte()); - int length = stream.ReadByte(); + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new HelloVerifyRequest + { + ServerVersion = new Version(255 - stream.ReadByte(), 255 - stream.ReadByte()) + }; + + var length = stream.ReadByte(); if (length > 0) { - result._Cookie = new byte[length]; - stream.Read(result._Cookie, 0, length); + result.Cookie = new byte[length]; + stream.Read(result.Cookie, 0, length); } return result; } - public void Serialise(System.IO.Stream stream, Version version) + public void Serialise(Stream stream, Version version) { - stream.WriteByte((byte)(255 - _ServerVersion.Major)); - stream.WriteByte((byte)(255 - _ServerVersion.Minor)); - stream.WriteByte((byte)_Cookie.Length); - stream.Write(_Cookie, 0, _Cookie.Length); + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + stream.WriteByte((byte)(255 - this.ServerVersion.Major)); + stream.WriteByte((byte)(255 - this.ServerVersion.Minor)); + stream.WriteByte((byte)this.Cookie.Length); + stream.Write(this.Cookie, 0, this.Cookie.Length); } } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/IHandshakeMessage.cs b/DTLS.Net/HandshakeMessages/IHandshakeMessage.cs similarity index 94% rename from src/DTLS.Net/HandshakeMessages/IHandshakeMessage.cs rename to DTLS.Net/HandshakeMessages/IHandshakeMessage.cs index b903a3b..9877e7a 100644 --- a/src/DTLS.Net/HandshakeMessages/IHandshakeMessage.cs +++ b/DTLS.Net/HandshakeMessages/IHandshakeMessage.cs @@ -21,14 +21,11 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; namespace DTLS { - internal interface IHandshakeMessage + internal interface IHandshakeMessage { THandshakeType MessageType { get; } @@ -36,4 +33,4 @@ internal interface IHandshakeMessage void Serialise(Stream stream, Version version); } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/KeyExchange/ClientKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/ClientKeyExchange.cs similarity index 94% rename from src/DTLS.Net/HandshakeMessages/KeyExchange/ClientKeyExchange.cs rename to DTLS.Net/HandshakeMessages/KeyExchange/ClientKeyExchange.cs index eb3ef9e..3bf21cf 100644 --- a/src/DTLS.Net/HandshakeMessages/KeyExchange/ClientKeyExchange.cs +++ b/DTLS.Net/HandshakeMessages/KeyExchange/ClientKeyExchange.cs @@ -20,14 +20,10 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - class ClientKeyExchange + class ClientKeyExchange { } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEClientKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEClientKeyExchange.cs similarity index 59% rename from src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEClientKeyExchange.cs rename to DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEClientKeyExchange.cs index 387eb9f..5deef39 100644 --- a/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEClientKeyExchange.cs +++ b/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEClientKeyExchange.cs @@ -20,74 +20,77 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using Org.BouncyCastle.Crypto.Parameters; +using System; +using System.IO; namespace DTLS { - internal class ECDHEClientKeyExchange : IHandshakeMessage + internal class ECDHEClientKeyExchange : IHandshakeMessage { + public THandshakeType MessageType => THandshakeType.ClientKeyExchange; - private byte[] _PublicKeyBytes; - - public THandshakeType MessageType - { - get { return THandshakeType.ClientKeyExchange; } - } + public byte[] PublicKeyBytes { get; private set; } - public byte[] PublicKeyBytes - { - get { return _PublicKeyBytes; } - } - - public int CalculateSize(Version version) + public int CalculateSize(Version version) { - int result = 1; - if (_PublicKeyBytes != null) + var result = 1; + if (this.PublicKeyBytes != null) { - result += _PublicKeyBytes.Length; + result += this.PublicKeyBytes.Length; } return result; } - public ECDHEClientKeyExchange() - { - - } + public ECDHEClientKeyExchange() { } public ECDHEClientKeyExchange(ECPublicKeyParameters publicKey) { - _PublicKeyBytes = publicKey.Q.GetEncoded(); + if(publicKey == null) + { + throw new ArgumentNullException(nameof(publicKey)); + } + + this.PublicKeyBytes = publicKey.Q.GetEncoded(); } - public void Serialise(System.IO.Stream stream, Version version) + public void Serialise(Stream stream, Version version) { - if (_PublicKeyBytes == null) + if(stream == null) { - stream.WriteByte(0); + throw new ArgumentNullException(nameof(stream)); } - else + + if (this.PublicKeyBytes == null) { - stream.WriteByte((byte)_PublicKeyBytes.Length); - stream.Write(_PublicKeyBytes, 0, _PublicKeyBytes.Length); + stream.WriteByte(0); + return; } + + stream.WriteByte((byte)this.PublicKeyBytes.Length); + stream.Write(this.PublicKeyBytes, 0, this.PublicKeyBytes.Length); } - public static ECDHEClientKeyExchange Deserialise(System.IO.Stream stream) + public static ECDHEClientKeyExchange Deserialise(Stream stream) { - ECDHEClientKeyExchange result = null; - int length = stream.ReadByte(); + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + ECDHEClientKeyExchange result = null; + var length = stream.ReadByte(); if (length > 0) { - result = new ECDHEClientKeyExchange(); - result._PublicKeyBytes = new byte[length]; - stream.Read(result._PublicKeyBytes, 0, length); + result = new ECDHEClientKeyExchange + { + PublicKeyBytes = new byte[length] + }; + + stream.Read(result.PublicKeyBytes, 0, length); } - return result; + return result; } } } diff --git a/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEKeyExchange.cs similarity index 76% rename from src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEKeyExchange.cs rename to DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEKeyExchange.cs index 67a3a7c..68aede8 100644 --- a/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEKeyExchange.cs +++ b/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEKeyExchange.cs @@ -20,19 +20,15 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Security; using Org.BouncyCastle.Crypto.Tls; +using Org.BouncyCastle.Security; +using System; namespace DTLS { - internal class ECDHEKeyExchange : IKeyExchange + internal class ECDHEKeyExchange : IKeyExchange { public RandomData ClientRandom { get; set; } @@ -40,9 +36,6 @@ internal class ECDHEKeyExchange : IKeyExchange public TKeyExchangeAlgorithm KeyExchangeAlgorithm { get; set; } - - - public TCipherSuite CipherSuite { get; set; } public TEllipticCurve Curve { get; set; } @@ -53,22 +46,26 @@ internal class ECDHEKeyExchange : IKeyExchange public ECPublicKeyParameters PublicKey { get; set; } - public void GenerateEphemeralKey() { - EllipticCurveParameters = EllipticCurveFactory.GetEllipticCurveParameters(Curve); - ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); - SecureRandom random = new SecureRandom(); - keyPairGenerator.Init(new ECKeyGenerationParameters(EllipticCurveParameters, random)); - AsymmetricCipherKeyPair keys = keyPairGenerator.GenerateKeyPair(); - PrivateKey = (ECPrivateKeyParameters)keys.Private; - PublicKey = (ECPublicKeyParameters)keys.Public; + this.EllipticCurveParameters = EllipticCurveFactory.GetEllipticCurveParameters(this.Curve); + var keyPairGenerator = new ECKeyPairGenerator(); + var random = new SecureRandom(); + keyPairGenerator.Init(new ECKeyGenerationParameters(this.EllipticCurveParameters, random)); + var keys = keyPairGenerator.GenerateKeyPair(); + this.PrivateKey = (ECPrivateKeyParameters)keys.Private; + this.PublicKey = (ECPublicKeyParameters)keys.Public; } public byte[] GetPreMasterSecret(byte[] encodedPoint) { - ECPublicKeyParameters peerPublicKey = TlsEccUtilities.DeserializeECPublicKey(null, EllipticCurveParameters, encodedPoint); - return TlsEccUtilities.CalculateECDHBasicAgreement(peerPublicKey, PrivateKey); + if(encodedPoint == null) + { + throw new ArgumentNullException(nameof(encodedPoint)); + } + + var peerPublicKey = TlsEccUtilities.DeserializeECPublicKey(null, this.EllipticCurveParameters, encodedPoint); + return TlsEccUtilities.CalculateECDHBasicAgreement(peerPublicKey, this.PrivateKey); } } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKClientKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKClientKeyExchange.cs similarity index 62% rename from src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKClientKeyExchange.cs rename to DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKClientKeyExchange.cs index 6728897..1ac6c21 100644 --- a/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKClientKeyExchange.cs +++ b/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKClientKeyExchange.cs @@ -20,11 +20,9 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using Org.BouncyCastle.Crypto.Parameters; +using System; +using System.IO; namespace DTLS { @@ -38,82 +36,81 @@ namespace DTLS //} ClientKeyExchange; internal class ECDHEPSKClientKeyExchange : IHandshakeMessage { - private byte[] _PSKIdentity; - private byte[] _PublicKeyBytes; + public THandshakeType MessageType => THandshakeType.ClientKeyExchange; - public THandshakeType MessageType - { - get { return THandshakeType.ClientKeyExchange; } - } + public byte[] PSKIdentity { get; set; } - public byte[] PSKIdentity - { - get { return _PSKIdentity; } - set { _PSKIdentity = value; } - } + public byte[] PublicKeyBytes { get; private set; } + public ECDHEPSKClientKeyExchange() { } - public byte[] PublicKeyBytes - { - get { return _PublicKeyBytes; } - } + public ECDHEPSKClientKeyExchange(ECPublicKeyParameters publicKey) => this.PublicKeyBytes = publicKey.Q.GetEncoded(); - - public ECDHEPSKClientKeyExchange() + public int CalculateSize(Version version) { + var result = 3; + if (this.PSKIdentity != null) + { + result += this.PSKIdentity.Length; + } - } - - public ECDHEPSKClientKeyExchange(ECPublicKeyParameters publicKey) - { - _PublicKeyBytes = publicKey.Q.GetEncoded(); - } + if (this.PublicKeyBytes != null) + { + result += this.PublicKeyBytes.Length; + } - public int CalculateSize(Version version) - { - int result = 3; - if (_PSKIdentity != null) - result += _PSKIdentity.Length; - if (_PublicKeyBytes != null) - result += _PublicKeyBytes.Length; return result; } - public void Serialise(System.IO.Stream stream, Version version) + public void Serialise(Stream stream, Version version) { - if (_PSKIdentity == null) + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (this.PSKIdentity == null) + { NetworkByteOrderConverter.WriteUInt16(stream, 0); + } else { - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)_PSKIdentity.Length); - stream.Write(_PSKIdentity, 0, _PSKIdentity.Length); + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.PSKIdentity.Length); + stream.Write(this.PSKIdentity, 0, this.PSKIdentity.Length); } - if (_PublicKeyBytes == null) + if (this.PublicKeyBytes == null) { stream.WriteByte(0); } else { - stream.WriteByte((byte)_PublicKeyBytes.Length); - stream.Write(_PublicKeyBytes, 0, _PublicKeyBytes.Length); + stream.WriteByte((byte)this.PublicKeyBytes.Length); + stream.Write(this.PublicKeyBytes, 0, this.PublicKeyBytes.Length); } } - public static ECDHEPSKClientKeyExchange Deserialise(System.IO.Stream stream) + public static ECDHEPSKClientKeyExchange Deserialise(Stream stream) { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + ECDHEPSKClientKeyExchange result = null; - ushort pskIdentityLength = NetworkByteOrderConverter.ToUInt16(stream); + var pskIdentityLength = NetworkByteOrderConverter.ToUInt16(stream); if (pskIdentityLength > 0) { - result = new ECDHEPSKClientKeyExchange(); - result._PSKIdentity = new byte[pskIdentityLength]; - stream.Read(result._PSKIdentity, 0, pskIdentityLength); - int length = stream.ReadByte(); + result = new ECDHEPSKClientKeyExchange + { + PSKIdentity = new byte[pskIdentityLength] + }; + stream.Read(result.PSKIdentity, 0, pskIdentityLength); + var length = stream.ReadByte(); if (length > 0) { - result._PublicKeyBytes = new byte[length]; - stream.Read(result._PublicKeyBytes, 0, length); + result.PublicKeyBytes = new byte[length]; + stream.Read(result.PublicKeyBytes, 0, length); } } return result; diff --git a/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKServerKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKServerKeyExchange.cs similarity index 52% rename from src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKServerKeyExchange.cs rename to DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKServerKeyExchange.cs index a55b56d..09206cb 100644 --- a/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKServerKeyExchange.cs +++ b/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEPSKServerKeyExchange.cs @@ -21,119 +21,117 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.IO; namespace DTLS { - //struct { - // select (KeyExchangeAlgorithm) { - // /* other cases for rsa, diffie_hellman, etc. */ - // case ec_diffie_hellman_psk: /* NEW */ - // opaque psk_identity_hint<0..2^16-1>; - // ServerECDHParams params; - // }; - //} ServerKeyExchange; + //struct { + // select (KeyExchangeAlgorithm) { + // /* other cases for rsa, diffie_hellman, etc. */ + // case ec_diffie_hellman_psk: /* NEW */ + // opaque psk_identity_hint<0..2^16-1>; + // ServerECDHParams params; + // }; + //} ServerKeyExchange; internal class ECDHEPSKServerKeyExchange : IHandshakeMessage { - private byte[] _PSKIdentityHint; - private byte[] _ServerParams; + private readonly byte[] _ServerParams; private TEllipticCurveType _EllipticCurveType; - private TEllipticCurve _EllipticCurve; - private byte[] _PublicKeyBytes; - public THandshakeType MessageType - { - get { return THandshakeType.ServerKeyExchange; } - } + public THandshakeType MessageType => THandshakeType.ServerKeyExchange; - public byte[] PSKIdentityHint - { - get { return _PSKIdentityHint; } - set { _PSKIdentityHint = value; } - } + public byte[] PSKIdentityHint { get; set; } - public TEllipticCurve EllipticCurve - { - get { return _EllipticCurve; } - } + public TEllipticCurve EllipticCurve { get; private set; } - public byte[] PublicKeyBytes - { - get { return _PublicKeyBytes; } - } + public byte[] PublicKeyBytes { get; private set; } - public ECDHEPSKServerKeyExchange() - { - _EllipticCurveType = TEllipticCurveType.NamedCurve; - } + public ECDHEPSKServerKeyExchange() => this._EllipticCurveType = TEllipticCurveType.NamedCurve; public ECDHEPSKServerKeyExchange(ECDHEKeyExchange keyExchange) { - _EllipticCurveType = TEllipticCurveType.NamedCurve; - _EllipticCurve = keyExchange.Curve; - System.IO.MemoryStream stream = new System.IO.MemoryStream(); - stream.WriteByte((byte)_EllipticCurveType); - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)_EllipticCurve); - byte[] pointEncoded = keyExchange.PublicKey.Q.GetEncoded(false); + if(keyExchange == null) + { + throw new ArgumentNullException(nameof(keyExchange)); + } + + this._EllipticCurveType = TEllipticCurveType.NamedCurve; + this.EllipticCurve = keyExchange.Curve; + var stream = new MemoryStream(); + stream.WriteByte((byte)this._EllipticCurveType); + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.EllipticCurve); + var pointEncoded = keyExchange.PublicKey.Q.GetEncoded(false); stream.WriteByte((byte)pointEncoded.Length); stream.Write(pointEncoded, 0, pointEncoded.Length); - _ServerParams = stream.ToArray(); + this._ServerParams = stream.ToArray(); } public int CalculateSize(Version version) { - int result = 2; - if (_PSKIdentityHint != null) + var result = 2; + if (this.PSKIdentityHint != null) { - result += _PSKIdentityHint.Length; + result += this.PSKIdentityHint.Length; } - if (_ServerParams != null) + + if (this._ServerParams != null) { - result += _ServerParams.Length; + result += this._ServerParams.Length; } + return result; } - public static ECDHEPSKServerKeyExchange Deserialise(System.IO.Stream stream, Version version) + public static ECDHEPSKServerKeyExchange Deserialise(Stream stream) { - ECDHEPSKServerKeyExchange result = new ECDHEPSKServerKeyExchange(); + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new ECDHEPSKServerKeyExchange(); int pdkIdentityHintLenth = NetworkByteOrderConverter.ToUInt16(stream); if (pdkIdentityHintLenth > 0) { - result._PSKIdentityHint = new byte[pdkIdentityHintLenth]; - stream.Read(result._PSKIdentityHint, 0, pdkIdentityHintLenth); + result.PSKIdentityHint = new byte[pdkIdentityHintLenth]; + stream.Read(result.PSKIdentityHint, 0, pdkIdentityHintLenth); } result._EllipticCurveType = (TEllipticCurveType)stream.ReadByte(); - result._EllipticCurve = (TEllipticCurve)NetworkByteOrderConverter.ToUInt16(stream); - int length = stream.ReadByte(); + result.EllipticCurve = (TEllipticCurve)NetworkByteOrderConverter.ToUInt16(stream); + var length = stream.ReadByte(); if (length > 0) { - result._PublicKeyBytes = new byte[length]; - stream.Read(result._PublicKeyBytes, 0, length); + result.PublicKeyBytes = new byte[length]; + stream.Read(result.PublicKeyBytes, 0, length); } return result; } - public void Serialise(System.IO.Stream stream, Version version) + public void Serialise(Stream stream, Version version) { - if (_PSKIdentityHint != null) + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (this.PSKIdentityHint != null) { - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)_PSKIdentityHint.Length); - stream.Write(_PSKIdentityHint, 0, _PSKIdentityHint.Length); + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.PSKIdentityHint.Length); + stream.Write(this.PSKIdentityHint, 0, this.PSKIdentityHint.Length); } else + { NetworkByteOrderConverter.WriteUInt16(stream, 0); - if (_ServerParams != null) + } + + if (this._ServerParams != null) { - stream.Write(_ServerParams, 0, _ServerParams.Length); + stream.Write(this._ServerParams, 0, this._ServerParams.Length); } } - } } diff --git a/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEServerKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEServerKeyExchange.cs new file mode 100644 index 0000000..a792da0 --- /dev/null +++ b/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEServerKeyExchange.cs @@ -0,0 +1,358 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Digests; +using Org.BouncyCastle.Crypto.Signers; +using System; +using System.IO; + +namespace DTLS +{ + // struct { + // opaque a <1..2^8-1>; + // opaque b <1..2^8-1>; + //} ECCurve; + + //enum { explicit_prime (1), explicit_char2 (2), + // named_curve (3), reserved(248..255) } ECCurveType; + // struct { + // opaque point <1..2^8-1>; + //} ECPoint; + //enum { ec_basis_trinomial, ec_basis_pentanomial } ECBasisType; + // struct { + // ECCurveType curve_type; + // select (curve_type) { + // case explicit_prime: + // opaque prime_p <1..2^8-1>; + // ECCurve curve; + // ECPoint base; + // opaque order <1..2^8-1>; + // opaque cofactor <1..2^8-1>; + // case explicit_char2: + // uint16 m; + // ECBasisType basis; + // select (basis) { + // case ec_trinomial: + // opaque k <1..2^8-1>; + // case ec_pentanomial: + // opaque k1 <1..2^8-1>; + // opaque k2 <1..2^8-1>; + // opaque k3 <1..2^8-1>; + // }; + // ECCurve curve; + // ECPoint base; + // opaque order <1..2^8-1>; + // opaque cofactor <1..2^8-1>; + + + + //Blake-Wilson, et al. Informational [Page 18] + + //RFC 4492 ECC Cipher Suites for TLS May 2006 + + + // case named_curve: + // NamedCurve namedcurve; + // }; + // } ECParameters; + + //struct { + // ECParameters curve_params; + // ECPoint public; + //} ServerECDHParams; + + + // enum { ec_diffie_hellman } KeyExchangeAlgorithm; + + //ec_diffie_hellman: Indicates the ServerKeyExchange message contains + // an ECDH public key. + + // select (KeyExchangeAlgorithm) { + // case ec_diffie_hellman: + // ServerECDHParams params; + // Signature signed_params; + // } ServerKeyExchange; + + + + // enum { ecdsa } SignatureAlgorithm; + + // select (SignatureAlgorithm) { + // case ecdsa: + // digitally-signed struct { + // opaque sha_hash[sha_size]; + // }; + // } Signature; + + + //ServerKeyExchange.signed_params.sha_hash + // SHA(ClientHello.random + ServerHello.random + + // ServerKeyExchange.params); + + + // struct { + // SignatureAndHashAlgorithm algorithm; + // opaque signature<0..2^16-1>; + //} DigitallySigned; + + internal class ECDHEServerKeyExchange : IHandshakeMessage + { + private readonly byte[] _ServerParams; + + public THandshakeType MessageType => THandshakeType.ServerKeyExchange; + + public TEllipticCurveType EllipticCurveType { get; private set; } + + public TEllipticCurve EllipticCurve { get; private set; } + + public byte[] PublicKeyBytes { get; private set; } + + public THashAlgorithm HashAlgorithm { get; private set; } + + public TSignatureAlgorithm SignatureAlgorithm { get; private set; } + + public byte[] Signature { get; private set; } + + public ECDHEServerKeyExchange() => this.EllipticCurveType = TEllipticCurveType.NamedCurve; + + public ECDHEServerKeyExchange(ECDHEKeyExchange keyExchange, THashAlgorithm hashAlgorithm, + TSignatureAlgorithm signatureAlgorithm, AsymmetricKeyParameter serverPrivateKey) + { + if(keyExchange == null) + { + throw new ArgumentNullException(nameof(keyExchange)); + } + + if(serverPrivateKey == null) + { + throw new ArgumentNullException(nameof(serverPrivateKey)); + } + + this.EllipticCurveType = TEllipticCurveType.NamedCurve; + this.EllipticCurve = keyExchange.Curve; + this.HashAlgorithm = hashAlgorithm; + this.SignatureAlgorithm = signatureAlgorithm; + + var stream = new System.IO.MemoryStream(); + stream.WriteByte((byte)this.EllipticCurveType); + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.EllipticCurve); + var pointEncoded = keyExchange.PublicKey.Q.GetEncoded(false); + stream.WriteByte((byte)pointEncoded.Length); + stream.Write(pointEncoded, 0, pointEncoded.Length); + this._ServerParams = stream.ToArray(); + + + //IDigest hashMD5 = GetDigest(THashAlgorithm.MD5); + //IDigest hashSHA = GetDigest(THashAlgorithm.SHA1); + //int size = hashMD5.GetDigestSize(); + //byte[] hash = new byte[size + hashSHA.GetDigestSize()]; + //hashMD5.BlockUpdate(clientRandom.RandomBytes, 0, clientRandom.RandomBytes.Length); + //hashMD5.BlockUpdate(serverRandom.RandomBytes, 0, serverRandom.RandomBytes.Length); + //hashMD5.BlockUpdate(_ServerParams, 0, _ServerParams.Length); + //hashMD5.DoFinal(hash, 0); + //hashSHA.BlockUpdate(clientRandom.RandomBytes, 0, clientRandom.RandomBytes.Length); + //hashSHA.BlockUpdate(serverRandom.RandomBytes, 0, serverRandom.RandomBytes.Length); + //hashSHA.BlockUpdate(_ServerParams, 0, _ServerParams.Length); + //hashSHA.DoFinal(hash, size); + + //ISigner signer = GetSigner(signatureAlgorithm, THashAlgorithm.None, serverPrivateKey); + //signer.BlockUpdate(hash, 0, hash.Length); + //_Signature = signer.GenerateSignature(); + + var signer = this.GetSigner(signatureAlgorithm, hashAlgorithm, serverPrivateKey); + var clientRandomBytes = keyExchange.ClientRandom.Serialise(); + var serverRandomBytes = keyExchange.ServerRandom.Serialise(); + signer.BlockUpdate(clientRandomBytes, 0, clientRandomBytes.Length); + signer.BlockUpdate(serverRandomBytes, 0, serverRandomBytes.Length); + signer.BlockUpdate(this._ServerParams, 0, this._ServerParams.Length); + this.Signature = signer.GenerateSignature(); + } + + public int CalculateSize(Version version) + { + if(version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + var result = 0; + if (this._ServerParams != null) + { + result += this._ServerParams.Length; + } + + if (this.Signature != null) + { + if (version >= DTLSRecord.Version1_2) + { + result += 2; + } + + result += 2; + result += this.Signature.Length; + } + + return result; + } + + public static ECDHEServerKeyExchange Deserialise(Stream stream, Version version) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + var result = new ECDHEServerKeyExchange + { + EllipticCurveType = (TEllipticCurveType)stream.ReadByte(), + EllipticCurve = (TEllipticCurve)NetworkByteOrderConverter.ToUInt16(stream) + }; + + var length = stream.ReadByte(); + if (length > 0) + { + result.PublicKeyBytes = new byte[length]; + stream.Read(result.PublicKeyBytes, 0, length); + } + + if (version >= DTLSRecord.Version1_2) + { + result.HashAlgorithm = (THashAlgorithm)stream.ReadByte(); + result.SignatureAlgorithm = (TSignatureAlgorithm)stream.ReadByte(); + } + + int signatureLength = NetworkByteOrderConverter.ToUInt16(stream); + if (signatureLength > 0) + { + result.Signature = new byte[signatureLength]; + stream.Read(result.Signature, 0, signatureLength); + } + + return result; + } + + public void Serialise(Stream stream, Version version) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + if (this._ServerParams != null) + { + stream.Write(this._ServerParams, 0, this._ServerParams.Length); + } + + if (version >= DTLSRecord.Version1_2) + { + stream.WriteByte((byte)this.HashAlgorithm); + stream.WriteByte((byte)this.SignatureAlgorithm); + } + + if (this.Signature != null) + { + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.Signature.Length); + stream.Write(this.Signature, 0, this.Signature.Length); + } + } + + private IDigest GetDigest(THashAlgorithm hashAlgorithm) + { + IDigest result = null; + switch (hashAlgorithm) + { + case THashAlgorithm.None: + result = new NullDigest(); + break; + case THashAlgorithm.MD5: + result = new MD5Digest(); + break; + case THashAlgorithm.SHA1: + result = new Sha1Digest(); + break; + case THashAlgorithm.SHA224: + result = new Sha224Digest(); + break; + case THashAlgorithm.SHA256: + result = new Sha256Digest(); + break; + case THashAlgorithm.SHA384: + result = new Sha384Digest(); + break; + case THashAlgorithm.SHA512: + result = new Sha512Digest(); + break; + default: + break; + } + return result; + } + + private ISigner GetSigner(TSignatureAlgorithm signatureAlgorithm, THashAlgorithm hashAlgorithm, AsymmetricKeyParameter serverPrivateKey) + { + if(serverPrivateKey == null) + { + throw new ArgumentNullException(nameof(serverPrivateKey)); + } + + ISigner result = null; + switch (signatureAlgorithm) + { + case TSignatureAlgorithm.Anonymous: + { + break; + } + case TSignatureAlgorithm.RSA: + { + break; + } + case TSignatureAlgorithm.DSA: + { + break; + } + case TSignatureAlgorithm.ECDSA: + { + result = new DsaDigestSigner(new ECDsaSigner(), this.GetDigest(hashAlgorithm)); + break; + } + default: + { + break; + } + } + result.Init(true, serverPrivateKey); + //result.Init(true, new ParametersWithRandom(serverPrivateKey, this.mContext.SecureRandom)); + return result; + } + } +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKClientKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKClientKeyExchange.cs similarity index 59% rename from src/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKClientKeyExchange.cs rename to DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKClientKeyExchange.cs index c57f8f7..b0a18c9 100644 --- a/src/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKClientKeyExchange.cs +++ b/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKClientKeyExchange.cs @@ -21,65 +21,70 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.IO; namespace DTLS { - //struct { - // select (KeyExchangeAlgorithm) { - // /* other cases for rsa, diffie_hellman, etc. */ - // case psk: /* NEW */ - // opaque psk_identity<0..2^16-1>; - // } exchange_keys; - //} ClientKeyExchange; - internal class PSKClientKeyExchange : IHandshakeMessage + //struct { + // select (KeyExchangeAlgorithm) { + // /* other cases for rsa, diffie_hellman, etc. */ + // case psk: /* NEW */ + // opaque psk_identity<0..2^16-1>; + // } exchange_keys; + //} ClientKeyExchange; + internal class PSKClientKeyExchange : IHandshakeMessage { - private byte[] _PSKIdentity; - - public THandshakeType MessageType - { - get { return THandshakeType.ClientKeyExchange; } - } + public THandshakeType MessageType => THandshakeType.ClientKeyExchange; - public byte[] PSKIdentity - { - get { return _PSKIdentity; } - set { _PSKIdentity = value; } - } + public byte[] PSKIdentity { get; set; } - - public int CalculateSize(Version version) + public int CalculateSize(Version version) { - int result = 2; - if (_PSKIdentity != null) - result += _PSKIdentity.Length; + var result = 2; + if (this.PSKIdentity != null) + { + result += this.PSKIdentity.Length; + } + return result; } - public void Serialise(System.IO.Stream stream, Version version) + public void Serialise(Stream stream, Version version) { - if (_PSKIdentity == null) + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (this.PSKIdentity == null) + { NetworkByteOrderConverter.WriteUInt16(stream, 0); + } else { - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)_PSKIdentity.Length); - stream.Write(_PSKIdentity, 0, _PSKIdentity.Length); + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.PSKIdentity.Length); + stream.Write(this.PSKIdentity, 0, this.PSKIdentity.Length); } } - public static PSKClientKeyExchange Deserialise(System.IO.Stream stream) + public static PSKClientKeyExchange Deserialise(Stream stream) { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + PSKClientKeyExchange result = null; - ushort pskIdentityLength = NetworkByteOrderConverter.ToUInt16(stream); + var pskIdentityLength = NetworkByteOrderConverter.ToUInt16(stream); if (pskIdentityLength > 0) { - result = new PSKClientKeyExchange(); - result._PSKIdentity = new byte[pskIdentityLength]; - stream.Read(result._PSKIdentity, 0, pskIdentityLength); + result = new PSKClientKeyExchange + { + PSKIdentity = new byte[pskIdentityLength] + }; + stream.Read(result.PSKIdentity, 0, pskIdentityLength); } - return result; + return result; } } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKKeyExchange.cs similarity index 95% rename from src/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKKeyExchange.cs rename to DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKKeyExchange.cs index 9ad00f1..4821238 100644 --- a/src/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKKeyExchange.cs +++ b/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKKeyExchange.cs @@ -20,10 +20,6 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { @@ -35,4 +31,4 @@ internal class PSKKeyExchange : IKeyExchange public TKeyExchangeAlgorithm KeyExchangeAlgorithm { get; set; } } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKServerKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKServerKeyExchange.cs similarity index 65% rename from src/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKServerKeyExchange.cs rename to DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKServerKeyExchange.cs index afc06ac..ed3c30f 100644 --- a/src/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKServerKeyExchange.cs +++ b/DTLS.Net/HandshakeMessages/KeyExchange/PSK/PSKServerKeyExchange.cs @@ -21,69 +21,68 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.IO; namespace DTLS { - // struct { - // select (KeyExchangeAlgorithm) { - // /* other cases for rsa, diffie_hellman, etc. */ - // case psk: /* NEW */ - // opaque psk_identity_hint<0..2^16-1>; - // }; - //} ServerKeyExchange; + // struct { + // select (KeyExchangeAlgorithm) { + // /* other cases for rsa, diffie_hellman, etc. */ + // case psk: /* NEW */ + // opaque psk_identity_hint<0..2^16-1>; + // }; + //} ServerKeyExchange; internal class PSKServerKeyExchange : IHandshakeMessage { - private byte[] _PSKIdentityHint; - - public THandshakeType MessageType - { - get { return THandshakeType.ServerKeyExchange; } - } - - public byte[] PSKIdentityHint - { - get { return _PSKIdentityHint; } - set { _PSKIdentityHint = value; } - } + public THandshakeType MessageType => THandshakeType.ServerKeyExchange; + public byte[] PSKIdentityHint { get; set; } public int CalculateSize(Version version) { - int result = 2; - if (_PSKIdentityHint != null) + var result = 2; + if (this.PSKIdentityHint != null) { - result += _PSKIdentityHint.Length; + result += this.PSKIdentityHint.Length; } return result; } - public static PSKServerKeyExchange Deserialise(System.IO.Stream stream, Version version) + public static PSKServerKeyExchange Deserialise(Stream stream) { - PSKServerKeyExchange result = new PSKServerKeyExchange(); + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new PSKServerKeyExchange(); int pdkIdentityHintLenth = NetworkByteOrderConverter.ToUInt16(stream); if (pdkIdentityHintLenth > 0) { - result._PSKIdentityHint = new byte[pdkIdentityHintLenth]; - stream.Read(result._PSKIdentityHint, 0, pdkIdentityHintLenth); + result.PSKIdentityHint = new byte[pdkIdentityHintLenth]; + stream.Read(result.PSKIdentityHint, 0, pdkIdentityHintLenth); } return result; } - public void Serialise(System.IO.Stream stream, Version version) + public void Serialise(Stream stream, Version version) { - if (_PSKIdentityHint != null) + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (this.PSKIdentityHint != null) { - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)_PSKIdentityHint.Length); - stream.Write(_PSKIdentityHint, 0, _PSKIdentityHint.Length); + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.PSKIdentityHint.Length); + stream.Write(this.PSKIdentityHint, 0, this.PSKIdentityHint.Length); } else + { NetworkByteOrderConverter.WriteUInt16(stream, 0); + } } - } -} +} \ No newline at end of file diff --git a/DTLS.Net/HandshakeMessages/KeyExchange/RSA/RSAClientKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/RSA/RSAClientKeyExchange.cs new file mode 100644 index 0000000..0eba4c8 --- /dev/null +++ b/DTLS.Net/HandshakeMessages/KeyExchange/RSA/RSAClientKeyExchange.cs @@ -0,0 +1,63 @@ +using System; +using System.IO; + +namespace DTLS +{ + //EncryptedPreMasterSecret + internal class RSAClientKeyExchange : IHandshakeMessage + { + public THandshakeType MessageType => THandshakeType.ClientKeyExchange; + + public byte[] PremasterSecret { get; set; } + + + public int CalculateSize(Version version) + { + var result = 2; + if (this.PremasterSecret != null) + { + result += this.PremasterSecret.Length; + } + + return result; + } + + public void Serialise(Stream stream, Version version) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + if (this.PremasterSecret == null) + { + NetworkByteOrderConverter.WriteUInt16(stream, 0); + } + else + { + NetworkByteOrderConverter.WriteUInt16(stream, (ushort)this.PremasterSecret.Length); + stream.Write(this.PremasterSecret, 0, this.PremasterSecret.Length); + } + } + + public static RSAClientKeyExchange Deserialise(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + RSAClientKeyExchange result = null; + var rsaPremasterLength = NetworkByteOrderConverter.ToUInt16(stream); + if (rsaPremasterLength > 0) + { + result = new RSAClientKeyExchange + { + PremasterSecret = new byte[rsaPremasterLength] + }; + stream.Read(result.PremasterSecret, 0, rsaPremasterLength); + } + return result; + } + } +} \ No newline at end of file diff --git a/DTLS.Net/HandshakeMessages/KeyExchange/ServerKeyExchange.cs b/DTLS.Net/HandshakeMessages/KeyExchange/ServerKeyExchange.cs new file mode 100644 index 0000000..44a8f10 --- /dev/null +++ b/DTLS.Net/HandshakeMessages/KeyExchange/ServerKeyExchange.cs @@ -0,0 +1,111 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using System; +using System.IO; + +namespace DTLS +{ + + // enum { rsa, diffie_hellman } KeyExchangeAlgorithm; + + //struct { + // opaque rsa_modulus<1..2^16-1>; + // opaque rsa_exponent<1..2^16-1>; + //} ServerRSAParams; + + //rsa_modulus + // The modulus of the server's temporary RSA key. + + //rsa_exponent + // The public exponent of the server's temporary RSA key. + + // struct { + // opaque dh_p<1..2^16-1>; + // opaque dh_g<1..2^16-1>; + // opaque dh_Ys<1..2^16-1>; + //} ServerDHParams; /* Ephemeral DH parameters */ + + //dh_p + // The prime modulus used for the Diffie-Hellman operation. + + //dh_g + // The generator used for the Diffie-Hellman operation. + + //dh_Ys + // The server's Diffie-Hellman public value (g^X mod p). + + + // struct { + // select (KeyExchangeAlgorithm) { + // case diffie_hellman: + // ServerDHParams params; + // Signature signed_params; + // case rsa: + // ServerRSAParams params; + // Signature signed_params; + // }; + //} ServerKeyExchange; + + + + // struct { + // select (SignatureAlgorithm) { + // case anonymous: struct { }; + // case rsa: + // digitally-signed struct { + // opaque md5_hash[16]; + // opaque sha_hash[20]; + // }; + // case dsa: + // digitally-signed struct { + // opaque sha_hash[20]; + // }; + // }; + // }; + //} Signature; + + + + // enum { ecdsa } SignatureAlgorithm; + + // select (SignatureAlgorithm) { + // case ecdsa: + // digitally-signed struct { + // opaque sha_hash[sha_size]; + // }; + // } Signature; + + + //ServerKeyExchange.signed_params.sha_hash + // SHA(ClientHello.random + ServerHello.random + + // ServerKeyExchange.params); + + internal class ServerKeyExchange : IHandshakeMessage + { + public THandshakeType MessageType => THandshakeType.ServerKeyExchange; + + public virtual int CalculateSize(Version version) => 0; + + public virtual void Serialise(Stream stream, Version version) => throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/DTLS.Net/HandshakeMessages/NewSessionTicket.cs b/DTLS.Net/HandshakeMessages/NewSessionTicket.cs new file mode 100644 index 0000000..12524f1 --- /dev/null +++ b/DTLS.Net/HandshakeMessages/NewSessionTicket.cs @@ -0,0 +1,70 @@ +using System; +using System.IO; + +namespace DTLS +{ + //struct { + // opaque key_name[16]; + // opaque iv[16]; + // opaque encrypted_state<0..2^16-1>; + // opaque mac[32]; + // } ticket; + + internal class NewSessionTicket : IHandshakeMessage + { + public THandshakeType MessageType => THandshakeType.NewSessionTicket; + + public uint LifetimeHint { get; set; } + public ushort Length { get; set; } + public byte[] Ticket { get; set; } + + public int CalculateSize(Version version) + { + var result = 6; + + if(this.Ticket != null) + { + result += this.Ticket.Length; + } + + return result; + } + + public static NewSessionTicket Deserialise(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new NewSessionTicket + { + LifetimeHint = (uint)stream.ReadByte(), + Length = NetworkByteOrderConverter.ToUInt16(stream) + }; + + stream.Read(result.Ticket, 0, result.Length); + return result; + } + + public void Serialise(Stream stream, Version version) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + NetworkByteOrderConverter.WriteUInt32(stream, this.LifetimeHint); + + if (this.Ticket == null) + { + NetworkByteOrderConverter.WriteUInt16(stream, 0); + } + else + { + NetworkByteOrderConverter.WriteUInt16(stream, this.Length); + stream.Write(this.Ticket, 0, this.Ticket.Length); + } + } + } +} diff --git a/src/DTLS.Net/HandshakeMessages/RandomData.cs b/DTLS.Net/HandshakeMessages/RandomData.cs similarity index 61% rename from src/DTLS.Net/HandshakeMessages/RandomData.cs rename to DTLS.Net/HandshakeMessages/RandomData.cs index eb48899..3400992 100644 --- a/src/DTLS.Net/HandshakeMessages/RandomData.cs +++ b/DTLS.Net/HandshakeMessages/RandomData.cs @@ -21,66 +21,65 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.IO; using System.Security.Cryptography; namespace DTLS { - // struct { - // uint32 gmt_unix_time; - // opaque random_bytes[28]; - //} Random; + // struct { + // uint32 gmt_unix_time; + // opaque random_bytes[28]; + //} Random; - internal class RandomData + internal class RandomData { - private uint _UnixTime; - private byte[] _RandomBytes = new byte[28]; + public uint UnixTime { get; set; } - public uint UnixTime - { - get { return _UnixTime; } - set { _UnixTime = value; } - } + public byte[] RandomBytes { get; set; } = new byte[28]; - public byte[] RandomBytes + public static RandomData Deserialise(Stream stream) { - get { return _RandomBytes; } - set { _RandomBytes = value; } - } + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + var result = new RandomData + { + UnixTime = NetworkByteOrderConverter.ToUInt32(stream) + }; - public static RandomData Deserialise(Stream stream) - { - RandomData result = new RandomData(); - result._UnixTime = NetworkByteOrderConverter.ToUInt32(stream); - stream.Read(result._RandomBytes, 0, 28); + stream.Read(result.RandomBytes, 0, 28); return result; } public void Generate() { - TimeSpan unixTime = DateTime.UtcNow.Subtract(TLSUtils.UnixEpoch); - _UnixTime = (uint)unixTime.TotalSeconds; - RNGCryptoServiceProvider random = new RNGCryptoServiceProvider(); - random.GetBytes(_RandomBytes); + var unixTime = DateTime.UtcNow.Subtract(TLSUtils.UnixEpoch); + this.UnixTime = (uint)unixTime.TotalSeconds; + using (var random = RandomNumberGenerator.Create()) + { + random.GetBytes(this.RandomBytes); + } } public byte[] Serialise() { - byte[] result = new byte[32]; - NetworkByteOrderConverter.WriteUInt32(result,0, _UnixTime); - Array.Copy(_RandomBytes, 0, result, 4, 28); + var result = new byte[32]; + NetworkByteOrderConverter.WriteUInt32(result,0, this.UnixTime); + Array.Copy(this.RandomBytes, 0, result, 4, 28); return result; } - public void Serialise(System.IO.Stream stream) + public void Serialise(Stream stream) { - NetworkByteOrderConverter.WriteUInt32(stream, _UnixTime); - stream.Write(_RandomBytes, 0, 28); - } + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + NetworkByteOrderConverter.WriteUInt32(stream, this.UnixTime); + stream.Write(this.RandomBytes, 0, 28); + } } -} +} \ No newline at end of file diff --git a/DTLS.Net/HandshakeMessages/ServerHello.cs b/DTLS.Net/HandshakeMessages/ServerHello.cs new file mode 100644 index 0000000..0fdab5e --- /dev/null +++ b/DTLS.Net/HandshakeMessages/ServerHello.cs @@ -0,0 +1,155 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using System; +using System.IO; + +namespace DTLS +{ + + // struct { + // ProtocolVersion server_version; + // Random random; + // SessionID session_id; + // CipherSuite cipher_suite; + // CompressionMethod compression_method; + // select (extensions_present) { + // case false: + // struct {}; + // case true: + // Extension extensions<0..2^16-1>; + // }; + //} ServerHello; + + internal class ServerHello : IHandshakeMessage + { + public static Version DefaultVersion = new Version(1, 0); + + public THandshakeType MessageType => THandshakeType.ServerHello; + + public Version ServerVersion { get; set; } + + public RandomData Random { get; set; } + + public byte[] SessionID { get; set; } + + public ushort CipherSuite { get; set; } + + public byte CompressionMethod { get; set; } + + public Extensions Extensions { get; set; } + + public ServerHello() => this.ServerVersion = DefaultVersion; + + public void AddExtension(IExtension extension) + { + if (extension == null) + { + throw new ArgumentNullException(nameof(extension)); + } + + if (this.Extensions == null) + { + this.Extensions = new Extensions(); + } + + var item = new Extension + { + ExtensionType = extension.ExtensionType, + SpecificExtension = extension + }; + + this.Extensions.Add(item); + } + + public int CalculateSize(Version version) + { + var result = 38; //Version + Length of cookie + if (this.SessionID != null) + { + result += this.SessionID.Length; + } + + if (this.Extensions != null) + { + result += this.Extensions.CalculateSize(); + } + + return result; + } + + public static ServerHello Deserialise(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new ServerHello + { + ServerVersion = new Version(255 - stream.ReadByte(), 255 - stream.ReadByte()), + Random = RandomData.Deserialise(stream) + }; + + var length = stream.ReadByte(); + if (length > 0) + { + result.SessionID = new byte[length]; + stream.Read(result.SessionID, 0, length); + } + + result.CipherSuite = NetworkByteOrderConverter.ToUInt16(stream); + result.CompressionMethod = (byte)stream.ReadByte(); + result.Extensions = Extensions.Deserialise(stream, false); + return result; + } + + public void Serialise(Stream stream, Version version) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + stream.WriteByte((byte)(255 - this.ServerVersion.Major)); + stream.WriteByte((byte)(255 - this.ServerVersion.Minor)); + this.Random.Serialise(stream); + + if (this.SessionID == null) + { + stream.WriteByte(0); + } + else + { + stream.WriteByte((byte)this.SessionID.Length); + stream.Write(this.SessionID, 0, this.SessionID.Length); + } + + NetworkByteOrderConverter.WriteUInt16(stream, this.CipherSuite); + stream.WriteByte(this.CompressionMethod); + if (this.Extensions != null) + { + this.Extensions.Serialise(stream); + } + } + } +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/ServerHelloDone.cs b/DTLS.Net/HandshakeMessages/ServerHelloDone.cs similarity index 82% rename from src/DTLS.Net/HandshakeMessages/ServerHelloDone.cs rename to DTLS.Net/HandshakeMessages/ServerHelloDone.cs index e457146..3134804 100644 --- a/src/DTLS.Net/HandshakeMessages/ServerHelloDone.cs +++ b/DTLS.Net/HandshakeMessages/ServerHelloDone.cs @@ -21,27 +21,16 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - // struct { } ServerHelloDone; - internal class ServerHelloDone : IHandshakeMessage + // struct { } ServerHelloDone; + internal class ServerHelloDone : IHandshakeMessage { - public THandshakeType MessageType - { - get { return THandshakeType.ServerHelloDone; } - } + public THandshakeType MessageType => THandshakeType.ServerHelloDone; - public int CalculateSize(Version version) - { - return 0; - } + public int CalculateSize(Version version) => 0; - public void Serialise(System.IO.Stream stream, Version version) - { - } - } -} + public void Serialise(System.IO.Stream stream, Version version) { } + } +} \ No newline at end of file diff --git a/src/DTLS.Net/HandshakeMessages/THandshakeType.cs b/DTLS.Net/HandshakeMessages/THandshakeType.cs similarity index 93% rename from src/DTLS.Net/HandshakeMessages/THandshakeType.cs rename to DTLS.Net/HandshakeMessages/THandshakeType.cs index ccda9fb..816eab8 100644 --- a/src/DTLS.Net/HandshakeMessages/THandshakeType.cs +++ b/DTLS.Net/HandshakeMessages/THandshakeType.cs @@ -20,19 +20,16 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - internal enum THandshakeType + internal enum THandshakeType { HelloRequest = 0, ClientHello = 1, - ServerHello = 2, + ServerHello = 2, HelloVerifyRequest = 3, + NewSessionTicket = 4, Certificate = 11, ServerKeyExchange = 12, CertificateRequest = 13, diff --git a/src/DTLS.Net/IKeyExchangeState.cs b/DTLS.Net/IKeyExchangeState.cs similarity index 94% rename from src/DTLS.Net/IKeyExchangeState.cs rename to DTLS.Net/IKeyExchangeState.cs index 0021e8d..72c8b07 100644 --- a/src/DTLS.Net/IKeyExchangeState.cs +++ b/DTLS.Net/IKeyExchangeState.cs @@ -20,14 +20,10 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { - internal interface IKeyExchange + internal interface IKeyExchange { RandomData ClientRandom { get; set; } diff --git a/DTLS.Net/PSK/PSKIdentities.cs b/DTLS.Net/PSK/PSKIdentities.cs new file mode 100644 index 0000000..ca58eda --- /dev/null +++ b/DTLS.Net/PSK/PSKIdentities.cs @@ -0,0 +1,228 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; +using System.Xml; +using System.IO; +using System.Linq; + +namespace DTLS +{ + public class PSKIdentities: IEqualityComparer + { + private readonly Dictionary _Identities; + + public int Count => this._Identities.Count; + + public PSKIdentities() => this._Identities = new Dictionary(10, this); + + public void AddIdentity(byte[] identity, byte[] key) + { + if(identity == null) + { + throw new ArgumentNullException(nameof(identity)); + } + + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + var pskIdentity = new PSKIdentity() { Identity = identity, Key = key }; + this._Identities.Add(pskIdentity.Identity, pskIdentity); + } + + public void AddIdentity(string identity, byte[] key) + { + if (string.IsNullOrWhiteSpace(identity)) + { + throw new ArgumentNullException(nameof(identity)); + } + + if (key == null) + { + throw new ArgumentNullException(nameof(key)); + } + + var pskIdentity = new PSKIdentity() { Identity = Encoding.UTF8.GetBytes(identity), Key = key }; + this._Identities.Add(pskIdentity.Identity, pskIdentity); + } + + public byte[] GetKey(byte[] identity) + { + if (identity == null) + { + throw new ArgumentNullException(nameof(identity)); + } + + if (this._Identities.TryGetValue(identity, out var pskIdentity)) + { + return pskIdentity.Key; + } + + return null; + } + + internal PSKIdentity GetRandom() + { + PSKIdentity result = null; + if (this._Identities.Count > 0) + { + var random = new Random(); + var index = random.Next(this._Identities.Count); + var count = 0; + foreach (var identity in this._Identities.Keys) + { + if (count == index) + { + this._Identities.TryGetValue(identity, out result); + break; + } + count++; + } + } + return result; + } + + private static byte[] HexToBytes(string hex) + { + if (string.IsNullOrWhiteSpace(hex)) + { + throw new ArgumentNullException(nameof(hex)); + } + + var result = new byte[hex.Length / 2]; + var count = 0; + for (var index = 0; index < hex.Length; index += 2) + { + result[count] = Convert.ToByte(hex.Substring(index, 2), 16); + count++; + } + return result; + } + + public void LoadFromFile(string fileName) + { + if (string.IsNullOrWhiteSpace(fileName)) + { + throw new ArgumentNullException(nameof(fileName)); + } + + if (!File.Exists(fileName)) + { + return; + } + + using (var reader = XmlReader.Create(fileName)) + { + while (reader.Read()) + { + if ((reader.NodeType != XmlNodeType.Element) || (reader.Name != "Identity") || !reader.HasAttributes) + { + continue; + } + + string name = null; + byte[] key = null; + + reader.MoveToFirstAttribute(); + do + { + if (reader.Name == "name") + { + name = reader.Value; + } + else if (reader.Name == "key") + { + key = HexToBytes(reader.Value); + } + } while (reader.MoveToNextAttribute()); + + reader.MoveToElement(); + if ((name != null) && (key != null)) + { + this.AddIdentity(name, key); + } + } + } + } + + bool IEqualityComparer.Equals(byte[] x, byte[] y) + { + if(x == null) + { + throw new ArgumentNullException(nameof(x)); + } + + if(y == null) + { + throw new ArgumentNullException(nameof(y)); + } + + return x.SequenceEqual(y); + } + + int IEqualityComparer.GetHashCode(byte[] obj) + { + if (obj == null) + { + throw new ArgumentNullException(nameof(obj)); + } + + var result = 0; + for (var i = 0; i < obj.Length; i++) + { + switch (i % 4) + { + case 0: + { + result = result | obj[i]; + break; + } + case 1: + { + result = result | (obj[i] << 8); + break; + } + case 2: + { + result = result | (obj[i] << 16); + break; + } + case 3: + { + result = result | (obj[i] << 24); + break; + } + default: + { + break; + } + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/src/DTLS.Net/PSK/PSKIdentity.cs b/DTLS.Net/PSK/PSKIdentity.cs similarity index 80% rename from src/DTLS.Net/PSK/PSKIdentity.cs rename to DTLS.Net/PSK/PSKIdentity.cs index 58984f0..63200d4 100644 --- a/src/DTLS.Net/PSK/PSKIdentity.cs +++ b/DTLS.Net/PSK/PSKIdentity.cs @@ -20,34 +20,14 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - namespace DTLS { internal class PSKIdentity { - private byte[] _Identity; - private byte[] _Key; - - public byte[] Identity - { - get { return _Identity; } - set { _Identity = value; } - } - - public byte[] Key - { - get { return _Key; } - set { _Key = value; } - } + public byte[] Identity { get; set; } - public PSKIdentity() - { + public byte[] Key { get; set; } - } - + public PSKIdentity() { } } -} +} \ No newline at end of file diff --git a/DTLS.Net/Records/AlertRecord.cs b/DTLS.Net/Records/AlertRecord.cs new file mode 100644 index 0000000..f6ea775 --- /dev/null +++ b/DTLS.Net/Records/AlertRecord.cs @@ -0,0 +1,114 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using System; +using System.IO; + +namespace DTLS +{ + + //enum { warning(1), fatal(2), (255) } AlertLevel; + + // enum { + // close_notify(0), + // unexpected_message(10), + // bad_record_mac(20), + // decryption_failed_RESERVED(21), + // record_overflow(22), + // decompression_failure(30), + // handshake_failure(40), + // no_certificate_RESERVED(41), + // bad_certificate(42), + // unsupported_certificate(43), + // certificate_revoked(44), + // certificate_expired(45), + // certificate_unknown(46), + // illegal_parameter(47), + // unknown_ca(48), + // access_denied(49), + // decode_error(50), + // decrypt_error(51), + // export_restriction_RESERVED(60), + // protocol_version(70), + // insufficient_security(71), + // internal_error(80), + // user_canceled(90), + // no_renegotiation(100), + // unsupported_extension(110), + // (255) + // } AlertDescription; + + // struct { + // AlertLevel level; + // AlertDescription description; + // } Alert; + + internal class AlertRecord + { + public TAlertLevel AlertLevel { get; set; } + + public TAlertDescription AlertDescription { get; set; } + + public static AlertRecord Deserialise(byte[] data) + { + if (data == null) + { + throw new ArgumentNullException(nameof(data)); + } + + var result = new AlertRecord + { + AlertLevel = (TAlertLevel)data[0], + AlertDescription = (TAlertDescription)data[1] + }; + + return result; + } + + public static AlertRecord Deserialise(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new AlertRecord + { + AlertLevel = (TAlertLevel)stream.ReadByte(), + AlertDescription = (TAlertDescription)stream.ReadByte() + }; + + return result; + } + + public void Serialise(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + stream.WriteByte((byte)this.AlertLevel); + stream.WriteByte((byte)this.AlertDescription); + } + } +} \ No newline at end of file diff --git a/src/DTLS.Net/Records/ChangeCipherSpecRecord.cs b/DTLS.Net/Records/ChangeCipherSpecRecord.cs similarity index 88% rename from src/DTLS.Net/Records/ChangeCipherSpecRecord.cs rename to DTLS.Net/Records/ChangeCipherSpecRecord.cs index 220dcea..ade4230 100644 --- a/src/DTLS.Net/Records/ChangeCipherSpecRecord.cs +++ b/DTLS.Net/Records/ChangeCipherSpecRecord.cs @@ -20,18 +20,10 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - namespace DTLS.Records { - // struct { - // enum { change_cipher_spec(1), (255) } type; - //} ChangeCipherSpec; - internal class ChangeCipherSpecRecord - { - - } -} + // struct { + // enum { change_cipher_spec(1), (255) } type; + //} ChangeCipherSpec; + internal class ChangeCipherSpecRecord { } +} \ No newline at end of file diff --git a/DTLS.Net/Records/DTLSRecord.cs b/DTLS.Net/Records/DTLSRecord.cs new file mode 100644 index 0000000..659c48c --- /dev/null +++ b/DTLS.Net/Records/DTLSRecord.cs @@ -0,0 +1,133 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using System; +using System.IO; +using System.Net; + +namespace DTLS +{ + //RFC 6347 DTLS1.2 + // RFC 4347 DTLS + //RFC 5246 TLS1.2 + internal class DTLSRecord + { + public static Version DefaultVersion = new Version(1, 0); + public static Version Version1_0 = new Version(1, 0); + public static Version Version1_2 = new Version(1, 2); + public const int RECORD_OVERHEAD = 13; + ushort _Length; + byte[] _Fragment; + + // struct { + // ContentType type; + // ProtocolVersion version; + // uint16 epoch; // New field + // uint48 sequence_number; // New field + // uint16 length; + // opaque fragment[DTLSPlaintext.length]; + //} DTLSPlaintext; + + public TRecordType RecordType { get; set; } + + public Version Version { get; set; } + + public ushort Epoch { get; set; } + + public long SequenceNumber { get; set; } + + public byte[] Fragment + { + get => this._Fragment; + set + { + this._Fragment = value; + if (this._Fragment != null) + { + this._Length = (ushort)this._Fragment.Length; + } + } + } + + public EndPoint RemoteEndPoint { get; set; } + + public DTLSRecord() => this.Version = DefaultVersion; + + public static DTLSRecord Deserialise(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = new DTLSRecord + { + RecordType = (TRecordType)stream.ReadByte(), + // could check here for a valid type, and bail out if invalid + Version = new Version(255 - stream.ReadByte(), 255 - stream.ReadByte()), + Epoch = NetworkByteOrderConverter.ToUInt16(stream), + SequenceNumber = NetworkByteOrderConverter.ToInt48(stream), + _Length = NetworkByteOrderConverter.ToUInt16(stream) + }; + + if (result._Length <= 0) + { + return result; + } + + result._Fragment = new byte[result._Length]; + var length = stream.Read(result._Fragment, 0, result._Length); + while (length < result._Length) + { + var bytesRead = stream.Read(result._Fragment, length, result._Length - length); + if (bytesRead > 0) + { + length += bytesRead; + } + else + { + break; + } + } + return result; + } + + public void Serialise(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + stream.WriteByte((byte)this.RecordType); + stream.WriteByte((byte)(255 - this.Version.Major)); + stream.WriteByte((byte)(255 - this.Version.Minor)); + NetworkByteOrderConverter.WriteUInt16(stream, this.Epoch); + NetworkByteOrderConverter.WriteInt48(stream, this.SequenceNumber); + NetworkByteOrderConverter.WriteUInt16(stream, this._Length); + if (this._Length > 0) + { + stream.Write(this._Fragment, 0, this._Length); + } + } + } +} \ No newline at end of file diff --git a/src/DTLS.Net/Records/DTLSRecords.cs b/DTLS.Net/Records/DTLSRecords.cs similarity index 69% rename from src/DTLS.Net/Records/DTLSRecords.cs rename to DTLS.Net/Records/DTLSRecords.cs index acf482c..b6a8a22 100644 --- a/src/DTLS.Net/Records/DTLSRecords.cs +++ b/DTLS.Net/Records/DTLSRecords.cs @@ -22,41 +22,42 @@ products derived from this software without specific prior written permission. using System; using System.Collections.Generic; -using System.Linq; -using System.Text; namespace DTLS { internal class DTLSRecords { - private List _Records; + private readonly object _Lock = new object(); + private readonly List _Records; - public DTLSRecords() - { - _Records = new List(); - } + public DTLSRecords() => this._Records = new List(); public void Add(DTLSRecord record) { - lock (_Records) + if (record == null) + { + throw new ArgumentNullException(nameof(record)); + } + + lock (this._Lock) { - int index = 0; - bool added = false; - while (index < _Records.Count) + var index = 0; + var added = false; + while (index < this._Records.Count) { - if (record.Epoch < _Records[index].Epoch) + if (record.Epoch < this._Records[index].Epoch) { - _Records.Insert(index, record); + this._Records.Insert(index, record); added = true; break; } - if ((record.SequenceNumber < _Records[index].SequenceNumber) && (record.Epoch == _Records[index].Epoch)) + if ((record.SequenceNumber < this._Records[index].SequenceNumber) && (record.Epoch == this._Records[index].Epoch)) { - _Records.Insert(index, record); + this._Records.Insert(index, record); added = true; break; } - else if ((record.SequenceNumber == _Records[index].SequenceNumber) && (record.Epoch == _Records[index].Epoch)) + else if ((record.SequenceNumber == this._Records[index].SequenceNumber) && (record.Epoch == this._Records[index].Epoch)) { added = true; break; @@ -64,7 +65,9 @@ public void Add(DTLSRecord record) index++; } if (!added) - _Records.Add(record); + { + this._Records.Add(record); + } } } @@ -76,20 +79,22 @@ public void Clear() public DTLSRecord PeekRecord() { DTLSRecord result = null; - lock (_Records) + lock (this._Lock) { - if (_Records.Count > 0) - result = _Records[0]; + if (this._Records.Count > 0) + { + result = this._Records[0]; + } } return result; } public void RemoveRecord() { - lock (_Records) + lock (this._Lock) { - _Records.RemoveAt(0); + this._Records.RemoveAt(0); } } } -} +} \ No newline at end of file diff --git a/DTLS.Net/Records/HandshakeRecord.cs b/DTLS.Net/Records/HandshakeRecord.cs new file mode 100644 index 0000000..ff14b81 --- /dev/null +++ b/DTLS.Net/Records/HandshakeRecord.cs @@ -0,0 +1,90 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using System.IO; + +namespace DTLS +{ + //struct { + // HandshakeType msg_type; + // uint24 length; + // uint16 message_seq; // New field + // uint24 fragment_offset; // New field + // uint24 fragment_length; // New field + // select (HandshakeType) { + // case hello_request: HelloRequest; + // case client_hello: ClientHello; + // case server_hello: ServerHello; + // case hello_verify_request: HelloVerifyRequest; // New field + // case certificate:Certificate; + // case server_key_exchange: ServerKeyExchange; + // case certificate_request: CertificateRequest; + // case server_hello_done:ServerHelloDone; + // case certificate_verify: CertificateVerify; + // case client_key_exchange: ClientKeyExchange; + // case finished: Finished; + // } body; } Handshake; + + internal class HandshakeRecord + { + public const int RECORD_OVERHEAD = 12; + + public THandshakeType MessageType { get; set; } + + public uint Length { get; set; } + + public ushort MessageSeq { get; set; } + + public uint FragmentOffset { get; set; } + + public uint FragmentLength { get; set; } + + + public static HandshakeRecord Deserialise(Stream stream) + { + var result = new HandshakeRecord + { + MessageType = (THandshakeType)stream.ReadByte(), + Length = NetworkByteOrderConverter.ToUInt24(stream), + MessageSeq = NetworkByteOrderConverter.ToUInt16(stream), + FragmentOffset = NetworkByteOrderConverter.ToUInt24(stream), + FragmentLength = NetworkByteOrderConverter.ToUInt24(stream) + }; + return result; + } + + public void Serialise(Stream stream) + { + stream.WriteByte((byte)this.MessageType); + NetworkByteOrderConverter.WriteUInt24(stream, this.Length); + NetworkByteOrderConverter.WriteUInt16(stream, this.MessageSeq); + NetworkByteOrderConverter.WriteUInt24(stream, this.FragmentOffset); + NetworkByteOrderConverter.WriteUInt24(stream, this.FragmentLength); + } + } + + + +// struct { +// ProtocolVersion server_version; +// opaque cookie<0..2^8-1>; } HelloVerifyRequest; +} diff --git a/src/DTLS.Net/Records/TRecordType.cs b/DTLS.Net/Records/TRecordType.cs similarity index 94% rename from src/DTLS.Net/Records/TRecordType.cs rename to DTLS.Net/Records/TRecordType.cs index d2397b7..5c7491d 100644 --- a/src/DTLS.Net/Records/TRecordType.cs +++ b/DTLS.Net/Records/TRecordType.cs @@ -20,18 +20,13 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - namespace DTLS { - internal enum TRecordType + internal enum TRecordType { ChangeCipherSpec = 20, Alert = 21, Handshake = 22, ApplicationData = 23 } -} +} \ No newline at end of file diff --git a/DTLS.Net/Server.cs b/DTLS.Net/Server.cs new file mode 100644 index 0000000..920e977 --- /dev/null +++ b/DTLS.Net/Server.cs @@ -0,0 +1,633 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using Org.BouncyCastle.Crypto.Tls; +using Org.BouncyCastle.Utilities.IO.Pem; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +#if !NET452 && !NET47 +using System.Runtime.InteropServices; +#endif +using System.Threading; + +namespace DTLS +{ + public class Server + { + public delegate void DataReceivedEventHandler(EndPoint endPoint, byte[] data); + public event DataReceivedEventHandler DataReceived; + + public delegate byte[] ValidatePSKEventHandler(byte[] identity); + public event ValidatePSKEventHandler ValidatePSK; + + private int _ReceiveBufferSize; + private int _SendBufferSize; + private Socket _Socket; + private ServerHandshake _Handshake; + private Certificate _Certificate; + private Org.BouncyCastle.Crypto.AsymmetricKeyParameter _PrivateKey; + private readonly Sessions _Sessions; + + public EndPoint LocalEndPoint { get; } + + //The maximum safe UDP payload is 508 bytes. Except on an IPv6-only route, where the maximum payload is 1,212 bytes. + //https://stackoverflow.com/questions/1098897/what-is-the-largest-safe-udp-packet-size-on-the-internet#:~:text=The%20maximum%20safe%20UDP%20payload%20is%20508%20bytes.&text=Except%20on%20an%20IPv6%2Donly,bytes%20may%20be%20preferred%20instead. + public int MaxPacketSize { get; set; } = 1212; + + public PSKIdentities PSKIdentities { get; set; } + + public bool RequireClientCertificate { get; set; } + + public List SupportedCipherSuites { get; } + + public int ReceiveBufferSize + { + get => this._ReceiveBufferSize; + set + { + this._ReceiveBufferSize = value; + if (this._Socket != null) + { + this._Socket.ReceiveBufferSize = value; + } + } + } + + public int SendBufferSize + { + get => this._SendBufferSize; + set + { + this._SendBufferSize = value; + if (this._Socket != null) + { + this._Socket.SendBufferSize = value; + } + } + } + + public Server(EndPoint localEndPoint) + { + this.LocalEndPoint = localEndPoint ?? throw new ArgumentNullException(nameof(localEndPoint)); + if (this.LocalEndPoint.AddressFamily != AddressFamily.InterNetworkV6) + { + MaxPacketSize = 508; + } + + this._Sessions = new Sessions(); + this.PSKIdentities = new PSKIdentities(); + this.SupportedCipherSuites = new List(); + } + + public Server(EndPoint localEndPoint, List supportedCipherSuites) + { + this.LocalEndPoint = localEndPoint ?? throw new ArgumentNullException(nameof(localEndPoint)); + this.SupportedCipherSuites = supportedCipherSuites ?? throw new ArgumentNullException(nameof(supportedCipherSuites)); + this._Sessions = new Sessions(); + this.PSKIdentities = new PSKIdentities(); + } + + private void _CheckSession(Session session, DTLSRecord record) + { + if(session == null) + { + throw new ArgumentNullException(nameof(session)); + } + + if(record == null) + { + throw new ArgumentNullException(nameof(record)); + } + + if ((session.ClientEpoch == record.Epoch) && (session.ClientSequenceNumber == record.SequenceNumber)) + { + ThreadPool.QueueUserWorkItem(this._ProcessRecord, record); + } + else if (session.ClientEpoch > record.Epoch) + { + ThreadPool.QueueUserWorkItem(this._ProcessRecord, record); + } + else if ((session.ClientEpoch == record.Epoch) && (session.ClientSequenceNumber > record.SequenceNumber)) + { + ThreadPool.QueueUserWorkItem(this._ProcessRecord, record); + } + else + { + var canProcessNow = false; + lock (session) + { + if ((session.ClientSequenceNumber == record.SequenceNumber) && (session.ClientEpoch == record.Epoch)) + { + canProcessNow = true; + } + else + { + session.Records.Add(record); + } + } + if (canProcessNow) + { + this._CheckSession(session, record); + } + } + } + + public void LoadCertificateFromPem(string filename) + { + if (string.IsNullOrWhiteSpace(filename)) + { + throw new ArgumentNullException(nameof(filename)); + } + + using (var stream = File.OpenRead(filename)) + { + this.LoadCertificateFromPem(stream); + } + } + + public void LoadCertificateFromPem(Stream stream) + { + if(stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var chain = new List(); + var reader = new PemReader(new StreamReader(stream)); + var pem = reader.ReadPemObject(); + + while (pem != null) + { + if (pem.Type.EndsWith("CERTIFICATE")) + { + chain.Add(pem.Content); + } + else if (pem.Type.EndsWith("PRIVATE KEY")) + { + this._PrivateKey = Certificates.GetPrivateKeyFromPEM(pem); + } + pem = reader.ReadPemObject(); + } + this._Certificate = new Certificate + { + CertChain = chain, + CertificateType = TCertificateType.X509 + }; + } + + public string GetClientPSKIdentity(EndPoint clientEndPoint) + { + if(clientEndPoint == null) + { + throw new ArgumentNullException(nameof(clientEndPoint)); + } + + var address = clientEndPoint.Serialize(); + var session = this._Sessions.GetSession(address); + if (session != null) + { + return session.PSKIdentity; + } + + return null; + } + + public CertificateInfo GetClientCertificateInfo(EndPoint clientEndPoint) + { + if(clientEndPoint == null) + { + throw new ArgumentNullException(nameof(clientEndPoint)); + } + + var address = clientEndPoint.Serialize(); + var session = this._Sessions.GetSession(address); + if (session != null) + { + return session.CertificateInfo; + } + + return null; + } + + private void _ProcessRecord(object state) + { + if (!(state is DTLSRecord record)) + { + throw new ArgumentException("State Object Must be a DTLSRecord"); + } + + Session session = null; + try + { + var address = record.RemoteEndPoint.Serialize(); + session = this._Sessions.GetSession(address); + if (session == null) + { + this._ProcessRecord(address, session, record); + session = this._Sessions.GetSession(address); + if (session != null) + { + lock (session) + { + if (record.RecordType != TRecordType.ChangeCipherSpec) + { + session.ClientSequenceNumber++; + } + } + } + + return; + } + + var processRecord = false; + if ((session.ClientEpoch == record.Epoch) && (session.ClientSequenceNumber == record.SequenceNumber)) + { + processRecord = true; + } + else if (session.ClientEpoch > record.Epoch) + { + processRecord = true; + } + else if ((session.ClientEpoch == record.Epoch) && (session.ClientSequenceNumber > record.SequenceNumber)) + { + processRecord = true; + } + + if (!processRecord) + { + return; + } + + do + { + this._ProcessRecord(address, session, record); + lock (session) + { + if (record.RecordType != TRecordType.ChangeCipherSpec) + { + session.ClientSequenceNumber++; + } + } + + record = session.Records.PeekRecord(); + if (record == null) + { + break; + } + + if ((session.ClientSequenceNumber == record.SequenceNumber) && (session.ClientEpoch == record.Epoch)) + { + session.Records.RemoveRecord(); + continue; + } + + break; + + } while (record != null); + } + catch (TlsFatalAlert ex) + { + this._SendAlert(session, TAlertLevel.Fatal, (TAlertDescription)ex.AlertDescription); + } + catch + { + this._SendAlert(session, TAlertLevel.Fatal, TAlertDescription.InternalError); + } + } + + private void _ProcessRecord(SocketAddress address, Session session, DTLSRecord record) + { + try + { + if(address == null) + { + throw new ArgumentNullException(nameof(address)); + } + + if(record == null) + { + throw new ArgumentNullException(nameof(record)); + } + + switch (record.RecordType) + { + case TRecordType.ChangeCipherSpec: + { + if (session != null) + { + session.ClientEpoch++; + session.ClientSequenceNumber = 0; + session.SetEncyptChange(record); + } + break; + } + case TRecordType.Alert: + { + if (session == null) + { + break; + } + + AlertRecord alertRecord; + try + { + if (session.Cipher == null) + { + alertRecord = AlertRecord.Deserialise(record.Fragment); + } + else + { + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + var data = session.Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Alert, record.Fragment, 0, record.Fragment.Length); + alertRecord = AlertRecord.Deserialise(data); + } + } + catch + { + alertRecord = new AlertRecord + { + AlertLevel = TAlertLevel.Fatal + }; + } + + if (alertRecord.AlertLevel == TAlertLevel.Fatal) + { + this._Sessions.Remove(session, address); + } + else if (alertRecord.AlertDescription == TAlertDescription.CloseNotify) + { + this._SendAlert(session, TAlertLevel.Warning, TAlertDescription.CloseNotify); + this._Sessions.Remove(session, address); + } + else if (alertRecord.AlertLevel == TAlertLevel.Warning) + { + this._Sessions.Remove(session, address); + } + break; + } + case TRecordType.Handshake: + { + this._Handshake.ProcessHandshake(record); + break; + } + case TRecordType.ApplicationData: + { + if (session == null) + { + break; + } + + if (session.Cipher != null) + { + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + var data = session.Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.ApplicationData, record.Fragment, 0, record.Fragment.Length); + DataReceived?.Invoke(record.RemoteEndPoint, data); + } + break; + } + default: + break; + } + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + this._SendAlert(session, TAlertLevel.Fatal, TAlertDescription.InternalError); + } + } + + private void _ReceiveCallback(object sender, SocketAsyncEventArgs e) + { + if(e == null) + { + throw new ArgumentNullException(nameof(e)); + } + + var count = e.BytesTransferred; + if (count == 0) + { + //do nothing? + return; + } + + var data = new byte[count]; + Buffer.BlockCopy(e.Buffer, 0, data, 0, count); + using (var stream = new MemoryStream(data)) + { + while (stream.Position < stream.Length) + { + var record = DTLSRecord.Deserialise(stream); + record.RemoteEndPoint = e.RemoteEndPoint; + var address = record.RemoteEndPoint.Serialize(); + var session = this._Sessions.GetSession(address); + if (session == null) + { + ThreadPool.QueueUserWorkItem(this._ProcessRecord, record); + } + else + { + this._CheckSession(session, record); + } + } + + if (sender is Socket socket) + { + var remoteEndPoint = socket.AddressFamily == AddressFamily.InterNetwork ? new IPEndPoint(IPAddress.Any, 0) : (EndPoint)new IPEndPoint(IPAddress.IPv6Any, 0); + e.RemoteEndPoint = remoteEndPoint; + e.SetBuffer(0, 4096); + socket.ReceiveFromAsync(e); + } + } + } + + private Socket _SetupSocket(AddressFamily addressFamily) + { + var result = new Socket(addressFamily, SocketType.Dgram, ProtocolType.Udp); + if (addressFamily == AddressFamily.InterNetworkV6) + { + result.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, true); + } + +#if NET452 || NET47 + if (Environment.OSVersion.Platform != PlatformID.Unix) +#else + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) +#endif + { + // Do not throw SocketError.ConnectionReset by ignoring ICMP Port Unreachable + const int SIO_UDP_CONNRESET = -1744830452; + result.IOControl(SIO_UDP_CONNRESET, new byte[] { 0 }, null); + } + + return result; + } + + public void Send(EndPoint remoteEndPoint, byte[] data) + { + if(remoteEndPoint == null) + { + throw new ArgumentNullException(nameof(remoteEndPoint)); + } + + if(data == null) + { + throw new ArgumentNullException(nameof(data)); + } + + var address = remoteEndPoint.Serialize(); + var session = this._Sessions.GetSession(address); + if (session == null) + { + return; + } + + try + { + var record = new DTLSRecord + { + RecordType = TRecordType.ApplicationData, + Epoch = session.Epoch, + SequenceNumber = session.NextSequenceNumber() + }; + + if (session.Version != null) + { + record.Version = session.Version; + } + + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.ApplicationData, data, 0, data.Length); + var responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; + var response = new byte[responseSize]; + using (var stream = new MemoryStream(response)) + { + record.Serialise(stream); + } + var parameters = new SocketAsyncEventArgs() + { + RemoteEndPoint = session.RemoteEndPoint + }; + parameters.SetBuffer(response, 0, responseSize); + this._Socket.SendToAsync(parameters); + } + catch (Exception ex) + { + Console.WriteLine(ex.ToString()); + } + } + + private void _SendAlert(Session session, TAlertLevel alertLevel, TAlertDescription alertDescription) + { + if (session == null) + { + throw new ArgumentNullException(nameof(session)); + } + + var record = new DTLSRecord + { + RecordType = TRecordType.Alert, + Epoch = session.Epoch, + SequenceNumber = session.NextSequenceNumber() + }; + + if (session.Version != null) + { + record.Version = session.Version; + } + + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + + var data = new byte[2]; + data[0] = (byte)alertLevel; + data[1] = (byte)alertDescription; + record.Fragment = session.Cipher == null + ? data + : session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.ApplicationData, data, 0, data.Length); + + var responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; + var response = new byte[responseSize]; + using (var stream = new MemoryStream(response)) + { + record.Serialise(stream); + } + var parameters = new SocketAsyncEventArgs() + { + RemoteEndPoint = session.RemoteEndPoint + }; + parameters.SetBuffer(response, 0, responseSize); + this._Socket.SendToAsync(parameters); + } + + public void Start() + { + if (this.SupportedCipherSuites.Count == 0) + { + this.SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); //Test 1.2 + this.SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 + this.SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 + this.SupportedCipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8); //Test 1.2 + this.SupportedCipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 + } + + this._Socket = this._SetupSocket(this.LocalEndPoint.AddressFamily); + this._Handshake = new ServerHandshake(this._Socket, this.MaxPacketSize, this.PSKIdentities, this.SupportedCipherSuites, this.RequireClientCertificate, ValidatePSK) + { + Certificate = this._Certificate, + PrivateKey = this._PrivateKey, + Sessions = this._Sessions + }; + + this._Socket.Bind(this.LocalEndPoint); + this._StartReceive(this._Socket); + } + + private void _StartReceive(Socket socket) + { + if(socket == null) + { + throw new ArgumentNullException(nameof(socket)); + } + + var parameters = new SocketAsyncEventArgs + { + RemoteEndPoint = socket.AddressFamily == AddressFamily.InterNetwork ? new IPEndPoint(IPAddress.Any, 0) : new IPEndPoint(IPAddress.IPv6Any, 0) + }; + parameters.Completed += new EventHandler(this._ReceiveCallback); + parameters.SetBuffer(new byte[4096], 0, 4096); + socket.ReceiveFromAsync(parameters); + } + + public void Stop() + { + if (this._Socket == null) + { + return; + } + + this._Socket.Dispose(); + this._Socket = null; + } + } +} \ No newline at end of file diff --git a/DTLS.Net/ServerHandshake.cs b/DTLS.Net/ServerHandshake.cs new file mode 100644 index 0000000..c3c94f7 --- /dev/null +++ b/DTLS.Net/ServerHandshake.cs @@ -0,0 +1,710 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using Org.BouncyCastle.Crypto; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using static DTLS.Server; + +namespace DTLS +{ + internal class ServerHandshake + { + private readonly bool _RequireClientCertificate; + private readonly ValidatePSKEventHandler _ValidatePSK; + private readonly int _MaxPacketSize; + private readonly byte[] _HelloSecret = new byte[] { 0x12, 0x84, 0x65, 0x94, 0xD5, 0x5E, 0x4B, 0x3A, 0xF3, 0x68, 0x56, 0x6F, 0xD7, 0x1B, 0x09, 0x8A }; + + private Socket _Socket; + private PSKIdentities _PSKIdentities; + private readonly Dictionary _SupportedCipherSuites; + + public Certificate Certificate { get; set; } + public AsymmetricKeyParameter PrivateKey { get; set; } + public Version ServerVersion { get; set; } + public Sessions Sessions { get; set; } + + public ServerHandshake(Socket socket, int maxPacketSize, PSKIdentities pskIdentities, List supportedCipherSuites, + bool requireClientCertificate, ValidatePSKEventHandler validatePSK) + { + if(supportedCipherSuites == null) + { + throw new ArgumentNullException(nameof(supportedCipherSuites)); + } + + this._Socket = socket ?? throw new ArgumentNullException(nameof(socket)); + this._PSKIdentities = pskIdentities ?? throw new ArgumentNullException(nameof(pskIdentities)); + this._ValidatePSK = validatePSK; + this._MaxPacketSize = maxPacketSize; + this._RequireClientCertificate = requireClientCertificate; + this.ServerVersion = new Version(1, 2); + + this._SupportedCipherSuites = new Dictionary(); + foreach (var item in supportedCipherSuites) + { + this._SupportedCipherSuites.Add(item, null); + } + } + + public void ProcessHandshake(DTLSRecord record) + { + if(record == null) + { + throw new ArgumentNullException(nameof(record)); + } + + var address = record.RemoteEndPoint.Serialize(); + var session = this.Sessions.GetSession(address); + var data = record.Fragment; + if ((session != null) && session.IsEncypted(record)) + { + var count = 0; + while ((session.Cipher == null) && (count < 50)) + { + System.Threading.Thread.Sleep(10); + count++; + } + + if (session.Cipher == null) + { + throw new Exception("Need Cipher for Encrypted Session"); + } + + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + data = session.Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); + } + + using (var stream = new MemoryStream(data)) + { + var handshakeRecord = HandshakeRecord.Deserialise(stream); + switch (handshakeRecord.MessageType) + { + case THandshakeType.HelloRequest: + { + //HelloReq + break; + } + case THandshakeType.ClientHello: + { + var clientHello = ClientHello.Deserialise(stream); + var cookie = clientHello.CalculateCookie(record.RemoteEndPoint, this._HelloSecret); + + if (clientHello.Cookie == null) + { + var vers = clientHello.ClientVersion; + if (this.ServerVersion < vers) + { + vers = this.ServerVersion; + } + + if (session == null) + { + session = new Session + { + SessionID = Guid.NewGuid(), + RemoteEndPoint = record.RemoteEndPoint, + Version = vers + }; + this.Sessions.AddSession(address, session); + } + else + { + session.Reset(); + session.Version = vers; + } + + session.ClientEpoch = record.Epoch; + session.ClientSequenceNumber = record.SequenceNumber; + + var helloVerifyRequest = new HelloVerifyRequest + { + Cookie = cookie, + ServerVersion = ServerVersion + }; + + this.SendResponse(session, helloVerifyRequest, 0); + break; + } + + if (session != null && session.Cipher != null && !session.IsEncypted(record)) + { + session.Reset(); + } + + if (!clientHello.Cookie.SequenceEqual(cookie)) + { + break; + } + + var version = clientHello.ClientVersion; + if (this.ServerVersion < version) + { + version = this.ServerVersion; + } + + if (clientHello.SessionID == null) + { + if (session == null) + { + session = new Session(); + session.NextSequenceNumber(); + session.SessionID = Guid.NewGuid(); + session.RemoteEndPoint = record.RemoteEndPoint; + this.Sessions.AddSession(address, session); + } + } + else + { + if (clientHello.SessionID.Length >= 16) + { + session = this.Sessions.GetSession(new Guid(clientHello.SessionID.Take(16).ToArray())); + } + + if (session == null) + { + //need to Find Session + session = new Session + { + SessionID = Guid.NewGuid() + }; + session.NextSequenceNumber(); + session.RemoteEndPoint = record.RemoteEndPoint; + this.Sessions.AddSession(address, session); + } + } + + session.Version = version; + var cipherSuite = TCipherSuite.TLS_NULL_WITH_NULL_NULL; + foreach (TCipherSuite item in clientHello.CipherSuites) + { + if (this._SupportedCipherSuites.ContainsKey(item) && CipherSuites.SupportedVersion(item, session.Version) && CipherSuites.SuiteUsable(item, this.PrivateKey, this._PSKIdentities, this._ValidatePSK != null)) + { + cipherSuite = item; + break; + } + } + + var clientSessionID = new byte[32]; + var temp = session.SessionID.ToByteArray(); + Buffer.BlockCopy(temp, 0, clientSessionID, 0, 16); + Buffer.BlockCopy(temp, 0, clientSessionID, 16, 16); + + var serverHello = new ServerHello + { + SessionID = clientSessionID,// session.SessionID.ToByteArray(); + Random = new RandomData(), + CipherSuite = (ushort)cipherSuite, + ServerVersion = session.Version + }; + serverHello.Random.Generate(); + + session.Handshake.UpdateHandshakeHash(data); + session.Handshake.CipherSuite = cipherSuite; + session.Handshake.ClientRandom = clientHello.Random; + session.Handshake.ServerRandom = serverHello.Random; + + var hash = THashAlgorithm.SHA256; + var curve = TEllipticCurve.secp521r1; + if (clientHello.Extensions != null) + { + foreach (var extension in clientHello.Extensions) + { + if (extension.SpecificExtension is ClientCertificateTypeExtension) + { + var clientCertificateType = extension.SpecificExtension as ClientCertificateTypeExtension; + //TCertificateType certificateType = TCertificateType.Unknown; + //foreach (TCertificateType item in clientCertificateType.CertificateTypes) + //{ + + //} + //serverHello.AddExtension(new ClientCertificateTypeExtension(certificateType)); + } + else if (extension.SpecificExtension is EllipticCurvesExtension) + { + var ellipticCurves = extension.SpecificExtension as EllipticCurvesExtension; + foreach (var item in ellipticCurves.SupportedCurves) + { + if (EllipticCurveFactory.SupportedCurve(item)) + { + curve = item; + break; + } + } + } + else if (extension.SpecificExtension is ServerCertificateTypeExtension) + { + //serverHello.AddExtension(); + } + else if (extension.SpecificExtension is SignatureAlgorithmsExtension) + { + var signatureAlgorithms = extension.SpecificExtension as SignatureAlgorithmsExtension; + foreach (var item in signatureAlgorithms.SupportedAlgorithms) + { + if (item.Signature == TSignatureAlgorithm.ECDSA) + { + hash = item.Hash; + break; + } + } + } + } + } + + var keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(cipherSuite); + if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) + { + var pointFormatsExtension = new EllipticCurvePointFormatsExtension(); + pointFormatsExtension.SupportedPointFormats.Add(TEllipticCurvePointFormat.Uncompressed); + serverHello.AddExtension(pointFormatsExtension); + } + + session.Handshake.MessageSequence = 1; + this.SendResponse(session, serverHello, session.Handshake.MessageSequence); + session.Handshake.MessageSequence++; + + if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) + { + if (this.Certificate != null) + { + this.SendResponse(session, this.Certificate, session.Handshake.MessageSequence); + session.Handshake.MessageSequence++; + } + + var keyExchange = new ECDHEKeyExchange + { + Curve = curve, + KeyExchangeAlgorithm = keyExchangeAlgorithm, + ClientRandom = clientHello.Random, + ServerRandom = serverHello.Random + }; + + keyExchange.GenerateEphemeralKey(); + session.Handshake.KeyExchange = keyExchange; + if (session.Version == DTLSRecord.DefaultVersion) + { + hash = THashAlgorithm.SHA1; + } + + var serverKeyExchange = new ECDHEServerKeyExchange(keyExchange, hash, TSignatureAlgorithm.ECDSA, this.PrivateKey); + this.SendResponse(session, serverKeyExchange, session.Handshake.MessageSequence); + + session.Handshake.MessageSequence++; + if (this._RequireClientCertificate) + { + var certificateRequest = new CertificateRequest(); + certificateRequest.CertificateTypes.Add(TClientCertificateType.ECDSASign); + certificateRequest.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash = THashAlgorithm.SHA256, Signature = TSignatureAlgorithm.ECDSA }); + this.SendResponse(session, certificateRequest, session.Handshake.MessageSequence); + session.Handshake.MessageSequence++; + } + } + else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK) + { + var keyExchange = new ECDHEKeyExchange + { + Curve = curve, + KeyExchangeAlgorithm = keyExchangeAlgorithm, + ClientRandom = clientHello.Random, + ServerRandom = serverHello.Random + }; + + keyExchange.GenerateEphemeralKey(); + session.Handshake.KeyExchange = keyExchange; + var serverKeyExchange = new ECDHEPSKServerKeyExchange(keyExchange); + this.SendResponse(session, serverKeyExchange, session.Handshake.MessageSequence); + session.Handshake.MessageSequence++; + + } + else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK) + { + var keyExchange = new PSKKeyExchange + { + KeyExchangeAlgorithm = keyExchangeAlgorithm, + ClientRandom = clientHello.Random, + ServerRandom = serverHello.Random + }; + session.Handshake.KeyExchange = keyExchange; + //Need to be able to hint identity?? for PSK if not hinting don't really need key exchange message + //PSKServerKeyExchange serverKeyExchange = new PSKServerKeyExchange(); + //SendResponse(session, serverKeyExchange, session.Handshake.MessageSequence); + //session.Handshake.MessageSequence++; + } + this.SendResponse(session, new ServerHelloDone(), session.Handshake.MessageSequence); + session.Handshake.MessageSequence++; + break; + } + case THandshakeType.ServerHello: + { + break; + } + case THandshakeType.HelloVerifyRequest: + { + break; + } + case THandshakeType.Certificate: + { + var clientCertificate = Certificate.Deserialise(stream, TCertificateType.X509); + if (clientCertificate.CertChain.Count > 0) + { + session.CertificateInfo = Certificates.GetCertificateInfo(clientCertificate.CertChain[0], TCertificateFormat.CER); + } + session.Handshake.UpdateHandshakeHash(data); + break; + } + case THandshakeType.ServerKeyExchange: + { + break; + } + case THandshakeType.CertificateRequest: + { + break; + } + case THandshakeType.ServerHelloDone: + { + break; + } + case THandshakeType.CertificateVerify: + { + var certificateVerify = CertificateVerify.Deserialise(stream, session.Version); + session.Handshake.UpdateHandshakeHash(data); + } + break; + case THandshakeType.ClientKeyExchange: + { + if ((session == null) || (session.Handshake.KeyExchange == null)) + { + break; + } + + session.Handshake.UpdateHandshakeHash(data); + byte[] preMasterSecret = null; + if (session.Handshake.KeyExchange.KeyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) + { + var clientKeyExchange = ECDHEClientKeyExchange.Deserialise(stream); + if (clientKeyExchange != null) + { + var ecKeyExchange = session.Handshake.KeyExchange as ECDHEKeyExchange; + preMasterSecret = ecKeyExchange.GetPreMasterSecret(clientKeyExchange.PublicKeyBytes); + } + } + else if (session.Handshake.KeyExchange.KeyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK) + { + var clientKeyExchange = ECDHEPSKClientKeyExchange.Deserialise(stream); + if (clientKeyExchange != null) + { + session.PSKIdentity = Encoding.UTF8.GetString(clientKeyExchange.PSKIdentity); + var psk = this._PSKIdentities.GetKey(clientKeyExchange.PSKIdentity); + + if (psk == null) + { + psk = this._ValidatePSK(clientKeyExchange.PSKIdentity); + if (psk != null) + { + this._PSKIdentities.AddIdentity(clientKeyExchange.PSKIdentity, psk); + } + } + + if (psk != null) + { + var ecKeyExchange = session.Handshake.KeyExchange as ECDHEKeyExchange; + var otherSecret = ecKeyExchange.GetPreMasterSecret(clientKeyExchange.PublicKeyBytes); + preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, psk); + + } + } + } + else if (session.Handshake.KeyExchange.KeyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK) + { + var clientKeyExchange = PSKClientKeyExchange.Deserialise(stream); + if (clientKeyExchange != null) + { + session.PSKIdentity = Encoding.UTF8.GetString(clientKeyExchange.PSKIdentity); + var psk = this._PSKIdentities.GetKey(clientKeyExchange.PSKIdentity); + + if (psk == null) + { + psk = this._ValidatePSK(clientKeyExchange.PSKIdentity); + if (psk != null) + { + this._PSKIdentities.AddIdentity(clientKeyExchange.PSKIdentity, psk); + } + } + + if (psk != null) + { + var ecKeyExchange = session.Handshake.KeyExchange as ECDHEKeyExchange; + var otherSecret = new byte[psk.Length]; + preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, psk); + } + } + } + + if (preMasterSecret != null) + { + //session.MasterSecret = TLSUtils.CalculateMasterSecret(preMasterSecret, session.KeyExchange); + //TLSUtils.AssignCipher(session); + + session.Cipher = TLSUtils.AssignCipher(preMasterSecret, false, session.Version, session.Handshake); + } + break; + } + case THandshakeType.Finished: + { + var finished = Finished.Deserialise(stream); + if (session == null) + { + break; + } + + var handshakeHash = session.Handshake.GetHash(session.Version); + var calculatedVerifyData = TLSUtils.GetVerifyData(session.Version, session.Handshake, false, true, handshakeHash); + if (!finished.VerifyData.SequenceEqual(calculatedVerifyData)) + { + throw new Exception(); + } + + this.SendChangeCipherSpec(session); + session.Handshake.UpdateHandshakeHash(data); + handshakeHash = session.Handshake.GetHash(session.Version); + var serverFinished = new Finished + { + VerifyData = TLSUtils.GetVerifyData(session.Version, session.Handshake, false, false, handshakeHash) + }; + this.SendResponse(session, serverFinished, session.Handshake.MessageSequence); + session.Handshake.MessageSequence++; + break; + } + default: + break; + } + } + } + + private void SendResponse(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence) + { + if(session == null) + { + throw new ArgumentNullException(nameof(session)); + } + + if(handshakeMessage == null) + { + throw new ArgumentNullException(nameof(handshakeMessage)); + } + + var size = handshakeMessage.CalculateSize(session.Version); + var maxPayloadSize = this._MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD; + if (size > maxPayloadSize) + { + //fragments + return; + } + + var record = new DTLSRecord + { + RecordType = TRecordType.Handshake, + Epoch = session.Epoch, + SequenceNumber = session.NextSequenceNumber(), + Fragment = new byte[HandshakeRecord.RECORD_OVERHEAD + size] + }; + + if (session.Version != null) + { + record.Version = session.Version; + } + + var handshakeRecord = new HandshakeRecord + { + MessageType = handshakeMessage.MessageType, + MessageSeq = messageSequence, + Length = (uint)size, + FragmentLength = (uint)size + }; + + using (var stream = new MemoryStream(record.Fragment)) + { + handshakeRecord.Serialise(stream); + handshakeMessage.Serialise(stream, session.Version); + } + + if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest) + { + session.Handshake.UpdateHandshakeHash(record.Fragment); + } + + var responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + size; + if (session.Cipher != null) + { + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); + responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; + } + + var response = new byte[responseSize]; + using (var stream = new MemoryStream(response)) + { + record.Serialise(stream); + } + var parameters = new SocketAsyncEventArgs() + { + RemoteEndPoint = session.RemoteEndPoint + }; + parameters.SetBuffer(response, 0, responseSize); + this._Socket.SendToAsync(parameters); + } + + private void SendResponseEnd(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence) + { + if(session == null) + { + throw new ArgumentNullException(nameof(session)); + } + + if(handshakeMessage == null) + { + throw new ArgumentNullException(nameof(handshakeMessage)); + } + + var size = handshakeMessage.CalculateSize(session.Version); + var maxPayloadSize = this._MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD; + if (size > maxPayloadSize) + { + //fragments + return; + } + + var record = this.CreateRecord(session, handshakeMessage, messageSequence); + session.Handshake.MessageSequence++; + var recordEnd = this.CreateRecord(session, new ServerHelloDone(), session.Handshake.MessageSequence); + session.Handshake.MessageSequence++; + var responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length + DTLSRecord.RECORD_OVERHEAD + recordEnd.Fragment.Length; + + var response = new byte[responseSize]; + using (var stream = new MemoryStream(response)) + { + record.Serialise(stream); + recordEnd.Serialise(stream); + } + var parameters = new SocketAsyncEventArgs() + { + RemoteEndPoint = session.RemoteEndPoint + }; + parameters.SetBuffer(response, 0, responseSize); + this._Socket.SendToAsync(parameters); + } + + private DTLSRecord CreateRecord(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence) + { + if (session == null) + { + throw new ArgumentNullException(nameof(session)); + } + + if (handshakeMessage == null) + { + throw new ArgumentNullException(nameof(handshakeMessage)); + } + + var size = handshakeMessage.CalculateSize(session.Version); + var record = new DTLSRecord + { + RecordType = TRecordType.Handshake, + Epoch = session.Epoch, + SequenceNumber = session.NextSequenceNumber(), + Fragment = new byte[HandshakeRecord.RECORD_OVERHEAD + size] + }; + + if (session.Version != null) + { + record.Version = session.Version; + } + + var handshakeRecord = new HandshakeRecord + { + MessageType = handshakeMessage.MessageType, + MessageSeq = messageSequence, + Length = (uint)size, + FragmentLength = (uint)size + }; + + using (var stream = new MemoryStream(record.Fragment)) + { + handshakeRecord.Serialise(stream); + handshakeMessage.Serialise(stream, session.Version); + } + + if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest) + { + session.Handshake.UpdateHandshakeHash(record.Fragment); + } + + if (session.Cipher != null) + { + var sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; + record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); + } + + return record; + } + + + private void SendChangeCipherSpec(Session session) + { + if (session == null) + { + throw new ArgumentNullException(nameof(session)); + } + + var size = 1; + var responseSize = DTLSRecord.RECORD_OVERHEAD + size; + var response = new byte[responseSize]; + var record = new DTLSRecord + { + RecordType = TRecordType.ChangeCipherSpec, + Epoch = session.Epoch, + SequenceNumber = session.NextSequenceNumber(), + Fragment = new byte[size] + }; + record.Fragment[0] = 1; + if (session.Version != null) + { + record.Version = session.Version; + } + + using (var stream = new MemoryStream(response)) + { + record.Serialise(stream); + } + var parameters = new SocketAsyncEventArgs() + { + RemoteEndPoint = session.RemoteEndPoint + }; + parameters.SetBuffer(response, 0, responseSize); + this._Socket.SendToAsync(parameters); + session.ChangeEpoch(); + } + } +} \ No newline at end of file diff --git a/src/DTLS.Net/Session.cs b/DTLS.Net/Session.cs similarity index 79% rename from src/DTLS.Net/Session.cs rename to DTLS.Net/Session.cs index fe44945..b41c758 100644 --- a/src/DTLS.Net/Session.cs +++ b/DTLS.Net/Session.cs @@ -20,13 +20,9 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ +using Org.BouncyCastle.Crypto.Tls; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Net; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Tls; namespace DTLS { @@ -62,52 +58,48 @@ internal class Session public Session() { this.Handshake = new HandshakeInfo(); - Records = new DTLSRecords(); + this.Records = new DTLSRecords(); } public void ChangeEpoch() { - Epoch++; - _SequenceNumber = 0; + this.Epoch++; + this._SequenceNumber = 0; } public long NextSequenceNumber() { - long result = _SequenceNumber++; + var result = this._SequenceNumber++; return result; } internal bool IsEncypted(DTLSRecord record) { - bool result = false; - if (EncyptedClientEpoch.HasValue) - result = record.Epoch == EncyptedClientEpoch.Value; + var result = false; + if (this.EncyptedClientEpoch.HasValue) + { + result = record.Epoch == this.EncyptedClientEpoch.Value; + } + return result; } internal void Reset() { - Epoch = 0; - _SequenceNumber = 0; - Cipher = null; - ClientEpoch = 0; - ClientSequenceNumber = 0; - EncyptedClientEpoch = null; - PSKIdentity = null; - CertificateInfo = null; - Records.Clear(); + this.Epoch = 0; + this._SequenceNumber = 0; + this.Cipher = null; + this.ClientEpoch = 0; + this.ClientSequenceNumber = 0; + this.EncyptedClientEpoch = null; + this.PSKIdentity = null; + this.CertificateInfo = null; + this.Records.Clear(); this.Handshake = new HandshakeInfo(); } - internal void SetEncyptChange(DTLSRecord record) - { - EncyptedClientEpoch = (ushort)(record.Epoch + 1); - } - - - + internal void SetEncyptChange(DTLSRecord record) => this.EncyptedClientEpoch = (ushort)(record.Epoch + 1); } - } diff --git a/src/DTLS.Net/Sessions.cs b/DTLS.Net/Sessions.cs similarity index 70% rename from src/DTLS.Net/Sessions.cs rename to DTLS.Net/Sessions.cs index b8d856f..4ce1819 100644 --- a/src/DTLS.Net/Sessions.cs +++ b/DTLS.Net/Sessions.cs @@ -21,56 +21,44 @@ products derived from this software without specific prior written permission. ***********************************************************************************************************************/ using System; -using System.Net; -using System.Collections.Generic; using System.Collections.Concurrent; -using System.Linq; -using System.Text; +using System.Collections.Generic; +using System.Net; namespace DTLS { - internal class Sessions + internal class Sessions { - private ConcurrentDictionary _Sessions; - private ConcurrentDictionary _SessionsByID; - private List _SessionList; - - public Sessions() - { - _Sessions = new ConcurrentDictionary(); - _SessionsByID = new ConcurrentDictionary(); - _SessionList = new List(); - } + private readonly ConcurrentDictionary _Sessions = new ConcurrentDictionary(); + private readonly ConcurrentDictionary _SessionsByID = new ConcurrentDictionary(); + private readonly List _SessionList = new List(); public void AddSession(SocketAddress address, Session session) { - if (_Sessions.TryAdd(address, session)) + if (this._Sessions.TryAdd(address, session)) { - _SessionsByID.TryAdd(session.SessionID, session); - _SessionList.Add(session); + this._SessionsByID.TryAdd(session.SessionID, session); + this._SessionList.Add(session); } } public Session GetSession(SocketAddress address) { - Session result; - _Sessions.TryGetValue(address, out result); - return result; + this._Sessions.TryGetValue(address, out var result); + return result; } public Session GetSession(Guid sessionID) { - Session result; - _SessionsByID.TryGetValue(sessionID, out result); - return result; + this._SessionsByID.TryGetValue(sessionID, out var result); + return result; } public void Remove(Session session, SocketAddress address) { - Session existing; - _Sessions.TryRemove(address, out session); - _SessionsByID.TryRemove(session.SessionID, out existing); - _SessionList.Remove(session); + this._Sessions.TryRemove(address, out session); + this._SessionsByID.TryRemove(session.SessionID, out var existing); + this._SessionList.Remove(session); } } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/TAlertDescription.cs b/DTLS.Net/TAlertDescription.cs similarity index 97% rename from src/DTLS.Net/TAlertDescription.cs rename to DTLS.Net/TAlertDescription.cs index 979cb96..35e7801 100644 --- a/src/DTLS.Net/TAlertDescription.cs +++ b/DTLS.Net/TAlertDescription.cs @@ -20,11 +20,6 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - namespace DTLS { // enum { @@ -83,4 +78,4 @@ internal enum TAlertDescription NoRenegotiation = 100, UnsupportedExtension = 110, } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/TAlertLevel.cs b/DTLS.Net/TAlertLevel.cs similarity index 95% rename from src/DTLS.Net/TAlertLevel.cs rename to DTLS.Net/TAlertLevel.cs index ff3b46a..41802b8 100644 --- a/src/DTLS.Net/TAlertLevel.cs +++ b/DTLS.Net/TAlertLevel.cs @@ -20,11 +20,6 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - namespace DTLS { //enum { warning(1), fatal(2), (255) } AlertLevel; @@ -34,4 +29,4 @@ internal enum TAlertLevel Warning = 1, Fatal = 2, } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/TCertificateType.cs b/DTLS.Net/TCertificateType.cs similarity index 89% rename from src/DTLS.Net/TCertificateType.cs rename to DTLS.Net/TCertificateType.cs index d1816e4..c081331 100644 --- a/src/DTLS.Net/TCertificateType.cs +++ b/DTLS.Net/TCertificateType.cs @@ -20,17 +20,12 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - namespace DTLS { - // enum { client, server } ClientOrServerExtension; - //enum { X.509(0), OpenPGP(1), (255) } CertificateType; - //rfc7250 - //rfc6091 + // enum { client, server } ClientOrServerExtension; + //enum { X.509(0), OpenPGP(1), (255) } CertificateType; + //rfc7250 + //rfc6091 internal enum TCertificateType { X509 = 0, @@ -38,4 +33,4 @@ internal enum TCertificateType RawPublicKey = 2, Unknown = 255 } -} +} \ No newline at end of file diff --git a/src/DTLS.Net/TClientCertificateType.cs b/DTLS.Net/TClientCertificateType.cs similarity index 97% rename from src/DTLS.Net/TClientCertificateType.cs rename to DTLS.Net/TClientCertificateType.cs index 6056672..72783f3 100644 --- a/src/DTLS.Net/TClientCertificateType.cs +++ b/DTLS.Net/TClientCertificateType.cs @@ -20,11 +20,6 @@ products derived from this software without specific prior written permission. USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ***********************************************************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - namespace DTLS { // enum { @@ -48,4 +43,4 @@ internal enum TClientCertificateType RSAFixedECDH = 65, // Certificate MUST contain an ECDH-capable public key on the same elliptic curve as the server's long-term ECDH key.This certificate MUST be signed with ECDSA. ECDSAFixedECDH = 66, // Certificate MUST contain an ECDH-capable public key on the same elliptic curve as the server's long-term ECDH key.This certificate MUST be signed with RSA. } -} +} \ No newline at end of file diff --git a/DTLS.Net/Util/CryptoApiRandomGenerator.cs b/DTLS.Net/Util/CryptoApiRandomGenerator.cs new file mode 100644 index 0000000..9ab7681 --- /dev/null +++ b/DTLS.Net/Util/CryptoApiRandomGenerator.cs @@ -0,0 +1,50 @@ +using Org.BouncyCastle.Crypto.Prng; +using System; +using System.Security.Cryptography; + +namespace DTLS +{ + public class CryptoApiRandomGenerator + : IRandomGenerator + { + private readonly RandomNumberGenerator _RndProv; + + public CryptoApiRandomGenerator() => this._RndProv = RandomNumberGenerator.Create(); + + public virtual void AddSeedMaterial(byte[] seed) + { + // I don't care about the seed + } + + public virtual void AddSeedMaterial(long seed) + { + // I don't care about the seed + } + + public virtual void NextBytes(byte[] bytes) => this._RndProv.GetBytes(bytes); + + public virtual void NextBytes(byte[] bytes, int start, int len) + { + if (start < 0) + { + throw new ArgumentException("Start offset cannot be negative", "start"); + } + + if (bytes.Length < (start + len)) + { + throw new ArgumentException("Byte array too small for requested offset and length"); + } + + if (bytes.Length == len && start == 0) + { + this.NextBytes(bytes); + } + else + { + var tmpBuf = new byte[len]; + this._RndProv.GetBytes(tmpBuf); + Array.Copy(tmpBuf, 0, bytes, start, len); + } + } + } +} \ No newline at end of file diff --git a/DTLS.Net/Util/NCryptInterop.cs b/DTLS.Net/Util/NCryptInterop.cs new file mode 100644 index 0000000..364d7f6 --- /dev/null +++ b/DTLS.Net/Util/NCryptInterop.cs @@ -0,0 +1,68 @@ +using Microsoft.Win32.SafeHandles; +using System; +using System.Runtime.InteropServices; +using System.Security.Cryptography; + +namespace DTLS.Net.Util +{ + public static class NCryptInterop + { + private struct BCRYPT_PKCS1_PADDING_INFO + { + internal IntPtr _PszAlgId; + } + + [Flags] + private enum NCryptSignFlags + { + BCRYPT_PAD_PKCS1 = 2, + } + + [DllImport("ncrypt.dll")] + private static extern int NCryptSignHash( + SafeNCryptKeyHandle hKey, + ref BCRYPT_PKCS1_PADDING_INFO padding, + ref byte pbHashValue, + int cbHashValue, + ref byte pbSignature, + int cbSignature, + out int cbResult, + NCryptSignFlags dwFlags); + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "The RSA items are windows only, however we want to allow for the other types of encryption to be use in other platforms")] + internal static byte[] SignHashRaw(CngKey key, byte[] hash, int keySize) + { + var keySizeBytes = keySize / 8; + var signature = new byte[keySizeBytes]; + + // The Handle property returns a new object each time. + using (var keyHandle = key.Handle) + { + // Leave pszAlgId NULL to "raw sign" + var paddingInfo = new BCRYPT_PKCS1_PADDING_INFO(); + + var result = NCryptSignHash( + keyHandle, + ref paddingInfo, + ref hash[0], + hash.Length, + ref signature[0], + signature.Length, + out var cbResult, + NCryptSignFlags.BCRYPT_PAD_PKCS1); + + if (result != 0) + { + throw new CryptographicException(result); + } + + if (cbResult != signature.Length) + { + throw new InvalidOperationException(); + } + + return signature; + } + } + } +} \ No newline at end of file diff --git a/DTLS.Net/Util/NetworkByteOrderConverter.cs b/DTLS.Net/Util/NetworkByteOrderConverter.cs new file mode 100644 index 0000000..e1a60e3 --- /dev/null +++ b/DTLS.Net/Util/NetworkByteOrderConverter.cs @@ -0,0 +1,497 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using System; +using System.IO; + +namespace DTLS +{ + internal static class NetworkByteOrderConverter + { + public static short ToInt16(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + short result = 0; + var buffer = new byte[2]; + var read = stream.Read(buffer, 0, 2); + if (read == 2) + { + result = ToInt16(buffer, 0); + } + else + { + throw new EndOfStreamException(); + } + + return result; + } + + public static short ToInt16(byte[] value, uint startIndex) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if(startIndex + 1 > value.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + return (short)(value[startIndex] << 8 | value[startIndex + 1]); + } + + public static int ToInt24(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = 0; + var buffer = new byte[3]; + var read = stream.Read(buffer, 0, 3); + if (read == 3) + { + result = ToInt24(buffer, 0); + } + else + { + throw new EndOfStreamException(); + } + + return result; + } + + public static int ToInt24(byte[] value, uint startIndex) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (startIndex + 2 > value.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + return (value[startIndex] << 16 | value[startIndex + 1] << 8 | value[startIndex + 2]); + } + + public static int ToInt32(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var result = 0; + var buffer = new byte[4]; + var read = stream.Read(buffer, 0, 4); + if (read == 4) + { + result = ToInt32(buffer, 0); + } + else + { + throw new EndOfStreamException(); + } + + return result; + } + + public static int ToInt32(byte[] value, uint startIndex) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (startIndex + 3 > value.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + return value[startIndex] << 24 | value[startIndex + 1] << 16 | value[startIndex + 2] << 8 | value[startIndex + 3]; + } + + public static long ToInt48(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + long result = 0; + var buffer = new byte[6]; + var read = stream.Read(buffer, 0, 6); + if (read == 6) + { + result = ToInt48(buffer, 0); + } + else + { + throw new EndOfStreamException(); + } + + return result; + } + + public static long ToInt48(byte[] value, uint startIndex) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (startIndex + 2 > value.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + return ToUInt32(value, startIndex + 2) | (((long)ToUInt16(value, startIndex)) << 32); + } + + public static ushort ToUInt16(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + ushort result = 0; + var buffer = new byte[2]; + var read = stream.Read(buffer, 0, 2); + if (read == 2) + { + result = ToUInt16(buffer, 0); + } + else + { + throw new EndOfStreamException(); + } + + return result; + } + + public static ushort ToUInt16(byte[] value, uint startIndex) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (startIndex + 1 > value.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + return (ushort)((uint)(value[startIndex]) << 8 | value[startIndex + 1]); + } + + public static uint ToUInt24(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + uint result = 0; + var buffer = new byte[3]; + var read = stream.Read(buffer, 0, 3); + if (read == 3) + { + result = ToUInt24(buffer, 0); + } + else + { + throw new EndOfStreamException(); + } + + return result; + } + + public static uint ToUInt24(byte[] value, uint startIndex) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (startIndex + 2 > value.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + return ((uint)value[startIndex]) << 16 | ((uint)value[startIndex + 1]) << 8 | value[startIndex + 2]; + } + + public static uint ToUInt32(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + uint result = 0; + var buffer = new byte[4]; + var read = stream.Read(buffer, 0, 4); + if (read == 4) + { + result = ToUInt32(buffer, 0); + } + else + { + throw new EndOfStreamException(); + } + + return result; + } + + public static uint ToUInt32(byte[] value, uint startIndex) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (startIndex + 3 > value.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + return ((uint)value[startIndex]) << 24 | ((uint)value[startIndex + 1]) << 16 | ((uint)value[startIndex + 2]) << 8 | value[startIndex + 3]; + } + + public static ulong ToUInt48(Stream stream) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + ulong result = 0; + var buffer = new byte[6]; + var read = stream.Read(buffer, 0, 6); + if (read == 6) + { + result = ToUInt48(buffer, 0); + } + else + { + throw new EndOfStreamException(); + } + + return result; + } + + public static ulong ToUInt48(byte[] value, uint startIndex) + { + if (value == null) + { + throw new ArgumentNullException(nameof(value)); + } + + if (startIndex + 2 > value.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + return ToUInt32(value, startIndex + 2) | (((ulong)ToUInt16(value,startIndex)) << 32); + } + + + public static void WriteInt16(Stream stream, short value) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var buffer = new byte[4]; + buffer[0] = (byte)(value >> 8); + buffer[1] = (byte)(value & 0xFF); + stream.Write(buffer, 0, 2); + } + + public static void WriteInt24(Stream stream, int value) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var buffer = new byte[3]; + buffer[0] = (byte)(value >> 16); + buffer[1] = (byte)(value >> 8); + buffer[2] = (byte)(value & 0xFF); + stream.Write(buffer, 0, 3); + } + + public static void WriteInt32(Stream stream, int value) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var buffer = new byte[4]; + buffer[0] = (byte)(value >> 24); + buffer[1] = (byte)(value >> 16); + buffer[2] = (byte)(value >> 8); + buffer[3] = (byte)(value & 0xFF); + stream.Write(buffer, 0, 4); + } + + public static void WriteInt32(byte[] buffer, uint startIndex, int value) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + if (startIndex + 3 > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + buffer[startIndex] = (byte)(value >> 24); + buffer[startIndex + 1] = (byte)(value >> 16); + buffer[startIndex + 2] = (byte)(value >> 8); + buffer[startIndex + 3] = (byte)(value & 0xFF); + } + + public static void WriteInt48(Stream stream, long value) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var buffer = new byte[6]; + buffer[0] = (byte)(value >> 40); + buffer[1] = (byte)(value >> 32); + buffer[2] = (byte)(value >> 24); + buffer[3] = (byte)(value >> 16); + buffer[4] = (byte)(value >> 8); + buffer[5] = (byte)(value & 0xFF); + stream.Write(buffer, 0, 6); + } + + public static void WriteUInt16(Stream stream, ushort value) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var buffer = new byte[4]; + buffer[0]= (byte)(value >> 8); + buffer[1] = (byte)(value & 0xFF); + stream.Write(buffer, 0, 2); + } + + public static void WriteUInt24(Stream stream, uint value) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var buffer = new byte[3]; + buffer[0] = (byte)(value >> 16); + buffer[1] = (byte)(value >> 8); + buffer[2] = (byte)(value & 0xFF); + stream.Write(buffer, 0, 3); + } + + public static void WriteUInt32(Stream stream, uint value) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var buffer = new byte[4]; + buffer[0]= (byte)(value >> 24); + buffer[1]= (byte)(value >> 16); + buffer[2]= (byte)(value >> 8); + buffer[3]= (byte)(value & 0xFF); + stream.Write(buffer, 0, 4); + } + + public static void WriteUInt16(byte[] buffer, uint startIndex, ushort value) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + if (startIndex + 1 > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + buffer[startIndex] = (byte)(value >> 8); + buffer[startIndex+ 1] = (byte)(value & 0xFF); + } + + public static void WriteUInt32(byte[] buffer, int startIndex, uint value) + { + if (buffer == null) + { + throw new ArgumentNullException(nameof(buffer)); + } + + if (startIndex + 3 > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + buffer[startIndex] = (byte)(value >> 24); + buffer[startIndex + 1] = (byte)(value >> 16); + buffer[startIndex + 2] = (byte)(value >> 8); + buffer[startIndex + 3] = (byte)(value & 0xFF); + } + + public static void WriteUInt48(Stream stream, ulong value) + { + if (stream == null) + { + throw new ArgumentNullException(nameof(stream)); + } + + var buffer = new byte[6]; + buffer[0] = (byte)(value >> 40); + buffer[1] = (byte)(value >> 32); + buffer[2] = (byte)(value >> 24); + buffer[3] = (byte)(value >> 16); + buffer[4] = (byte)(value >> 8); + buffer[5] = (byte)(value & 0xFF); + stream.Write(buffer, 0, 6); + } + } +} \ No newline at end of file diff --git a/DTLS.Net/Util/TLSUtils.cs b/DTLS.Net/Util/TLSUtils.cs new file mode 100644 index 0000000..0d97313 --- /dev/null +++ b/DTLS.Net/Util/TLSUtils.cs @@ -0,0 +1,391 @@ +/*********************************************************************************************************************** + Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, are permitted provided that the + following conditions are met: + 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the + following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote + products derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +using DTLS.Net.Util; +using Org.BouncyCastle.Crypto; +using Org.BouncyCastle.Crypto.Tls; +using Org.BouncyCastle.Security; +using System; +using System.Linq; +using System.Security.Cryptography; +using System.Security.Cryptography.X509Certificates; +using System.Text; + +namespace DTLS +{ + internal static class TLSUtils + { + public static DateTime UnixEpoch = new(1970, 1, 1); + + private static readonly byte[] _MASTER_SECRET_LABEL = Encoding.ASCII.GetBytes("master secret"); + private const int _MASTERSECRETLENGTH = 48; + private static readonly TlsCipherFactory _CipherFactory = new DefaultTlsCipherFactory(); + + public static byte[] CalculateMasterSecret(byte[] preMasterSecret, IKeyExchange keyExchange) + { + if (preMasterSecret == null) + { + throw new ArgumentNullException(nameof(preMasterSecret)); + } + + if (keyExchange == null) + { + throw new ArgumentNullException(nameof(keyExchange)); + } + + var seed = _MASTER_SECRET_LABEL + .Concat(keyExchange.ClientRandom.Serialise()) + .Concat(keyExchange.ServerRandom.Serialise()) + .ToArray(); + + var result = PseudorandomFunction(preMasterSecret, seed, _MASTERSECRETLENGTH); + Array.Clear(preMasterSecret, 0, preMasterSecret.Length); + return result; + } + + public static byte[] PseudorandomFunction(byte[] secret, byte[] seed, int length) + { + if (secret == null) + { + throw new ArgumentNullException(nameof(secret)); + } + + if (seed == null) + { + throw new ArgumentNullException(nameof(seed)); + } + + if (length < 0) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + var result = new byte[length]; + using (var hmac = new HMACSHA256(secret)) + { + var iterations = (int)Math.Ceiling(length / (double)hmac.HashSize); + //var dataToHash = seed; + var offset = 0; + for (var index = 0; index < iterations; index++) + { + //dataToHash = hmac.ComputeHash(dataToHash); + //hmac.TransformBlock(dataToHash, 0, dataToHash.Length, dataToHash, 0); + //var hash = hmac.TransformFinalBlock(seed, 0, seed.Length); + var hash = hmac.ComputeHash(seed); + Buffer.BlockCopy(hash, 0, result, offset, Math.Min(hash.Length, length - offset)); + offset += hash.Length; + } + return result; + } + } + + private static int GetEncryptionAlgorithm(TCipherSuite cipherSuite) + { + if (cipherSuite == TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) + { + return EncryptionAlgorithm.AES_128_CCM_8; + } + + if (cipherSuite == TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) + { + return EncryptionAlgorithm.AES_128_CBC; + } + + if (cipherSuite == TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8) + { + return EncryptionAlgorithm.AES_128_CCM_8; + } + + if (cipherSuite == TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256) + { + return EncryptionAlgorithm.AES_128_CBC; + } + + if (cipherSuite == TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256) + { + return EncryptionAlgorithm.AES_128_CBC; + } + + if (cipherSuite == TCipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA) + { + return EncryptionAlgorithm.AES_256_CBC; + } + + return 0; + } + + private static int GetMACAlgorithm(TCipherSuite cipherSuite) + { + if (cipherSuite == TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) + { + return MacAlgorithm.cls_null; + } + + if (cipherSuite == TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) + { + return MacAlgorithm.hmac_sha256; + } + + if (cipherSuite == TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8) + { + return MacAlgorithm.cls_null; + } + + if (cipherSuite == TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256) + { + return MacAlgorithm.hmac_sha256; + } + + if (cipherSuite == TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256) + { + return MacAlgorithm.hmac_sha256; + } + + if (cipherSuite == TCipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA) + { + return MacAlgorithm.hmac_sha1; + } + + return 0; + } + + public static TlsCipher AssignCipher(byte[] preMasterSecret, bool client, Version version, HandshakeInfo handshakeInfo) + { + if (preMasterSecret == null) + { + throw new ArgumentNullException(nameof(preMasterSecret)); + } + + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + if (handshakeInfo == null) + { + throw new ArgumentNullException(nameof(handshakeInfo)); + } + + TlsContext context = new DTLSContext(client, version, handshakeInfo); + var securityParameters = context.SecurityParameters; + var isExtendedMasterSecret = handshakeInfo.Extensions.Exists(e => e.ExtensionType == TExtensionType.ExtendedMasterSecret); + var seed = + isExtendedMasterSecret + ? handshakeInfo.GetHash(version) + : [.. securityParameters.ClientRandom, .. securityParameters.ServerRandom]; + var asciiLabel = + isExtendedMasterSecret + ? ExporterLabel.extended_master_secret + : ExporterLabel.master_secret; + + handshakeInfo.MasterSecret = TlsUtilities.IsTlsV11(context) ? + TlsUtilities.PRF_legacy(preMasterSecret, asciiLabel, seed, 48) + : TlsUtilities.PRF(context, preMasterSecret, asciiLabel, seed, 48); + + //seed = + // isExtendedMasterSecret + // ? handshakeInfo.GetHash(version) + // : [.. securityParameters.ServerRandom, .. securityParameters.ClientRandom]; + //var key_block = TlsUtilities.IsTlsV11(context) ? + // TlsUtilities.PRF_legacy(handshakeInfo.MasterSecret, ExporterLabel.key_expansion, seed, 96) + // : TlsUtilities.PRF(context, handshakeInfo.MasterSecret, ExporterLabel.key_expansion, seed, 96); + + return _CipherFactory + .CreateCipher(context, GetEncryptionAlgorithm(handshakeInfo.CipherSuite), GetMACAlgorithm(handshakeInfo.CipherSuite)); + } + + public static byte[] CalculateKeyBlock(TlsContext context, int size) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (size < 0) + { + throw new ArgumentOutOfRangeException(nameof(size)); + } + + var securityParameters = context.SecurityParameters; + var master_secret = securityParameters.MasterSecret; + var seed = securityParameters.ServerRandom.Concat(securityParameters.ClientRandom).ToArray(); + + return TlsUtilities.IsTlsV11(context) + ? TlsUtilities.PRF_legacy(master_secret, ExporterLabel.key_expansion, seed, size) + : TlsUtilities.PRF(context, master_secret, ExporterLabel.key_expansion, seed, size); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "Other methods are available but RSA is just for windows")] + public static byte[] Sign(AsymmetricKeyParameter privateKey, CngKey cngKey, bool client, Version version, HandshakeInfo handshakeInfo, + SignatureHashAlgorithm signatureHashAlgorithm, byte[] hash) + { + if (privateKey == null && cngKey == null) + { + throw new ArgumentException("No key or Rsa CSP provided"); + } + + if (privateKey == null) + { + + if (signatureHashAlgorithm.Signature == TSignatureAlgorithm.RSA) + { + return NCryptInterop.SignHashRaw(cngKey, hash, cngKey.KeySize); + } + + throw new ArgumentException("Need private key for non-RSA Algorithms"); + } + + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + if (handshakeInfo == null) + { + throw new ArgumentNullException(nameof(handshakeInfo)); + } + + if (signatureHashAlgorithm == null) + { + throw new ArgumentNullException(nameof(signatureHashAlgorithm)); + } + + if (hash == null) + { + throw new ArgumentNullException(nameof(hash)); + } + + TlsSigner signer = null; + switch (signatureHashAlgorithm.Signature) + { + case TSignatureAlgorithm.Anonymous: + break; + case TSignatureAlgorithm.RSA: + signer = new TlsRsaSigner(); + break; + case TSignatureAlgorithm.DSA: + signer = new TlsDssSigner(); + break; + case TSignatureAlgorithm.ECDSA: + + signer = new TlsECDsaSigner(); + break; + default: + break; + } + + var context = new DTLSContext(client, version, handshakeInfo); + var randomGenerator = new CryptoApiRandomGenerator(); + context.SecureRandom = new SecureRandom(randomGenerator); + + signer.Init(context); + if (TlsUtilities.IsTlsV12(context)) + { + var signatureAndHashAlgorithm = new SignatureAndHashAlgorithm((byte)signatureHashAlgorithm.Hash, (byte)signatureHashAlgorithm.Signature); + return signer.GenerateRawSignature(signatureAndHashAlgorithm, privateKey, hash); + } + else + { + return signer.GenerateRawSignature(privateKey, hash); + } + } + + public static byte[] GetVerifyData(Version version, HandshakeInfo handshakeInfo, bool client, bool isClientFinished, + byte[] handshakeHash) + { + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + if (handshakeInfo == null) + { + throw new ArgumentNullException(nameof(handshakeInfo)); + } + + if (handshakeHash == null) + { + throw new ArgumentNullException(nameof(handshakeHash)); + } + + TlsContext context = new DTLSContext(client, version, handshakeInfo); + var asciiLabel = isClientFinished ? ExporterLabel.client_finished : ExporterLabel.server_finished; + return TlsUtilities.IsTlsV11(context) ? + TlsUtilities.PRF_legacy(handshakeInfo.MasterSecret, asciiLabel, handshakeHash, 12) + : TlsUtilities.PRF(context, handshakeInfo.MasterSecret, asciiLabel, handshakeHash, 12); + } + + internal static byte[] GetPSKPreMasterSecret(byte[] otherSecret, byte[] psk) + { + if (otherSecret == null) + { + throw new ArgumentNullException(nameof(otherSecret)); + } + + if (psk == null) + { + throw new ArgumentNullException(nameof(psk)); + } + + var result = new byte[4 + otherSecret.Length + psk.Length]; + NetworkByteOrderConverter.WriteUInt16(result, 0, (ushort)otherSecret.Length); + Buffer.BlockCopy(otherSecret, 0, result, 2, otherSecret.Length); + NetworkByteOrderConverter.WriteUInt16(result, (uint)(2 + otherSecret.Length), (ushort)psk.Length); + Buffer.BlockCopy(psk, 0, result, 4 + otherSecret.Length, psk.Length); + return result; + } + + internal static byte[] GetRsaPreMasterSecret(Version version) + { + if (version == null) + { + throw new ArgumentNullException(nameof(version)); + } + + using (var random = RandomNumberGenerator.Create()) + { + var randomData = new byte[46]; + random.GetBytes(randomData); + var versionBytes = new byte[] { (byte)(255 - version.Major), (byte)(255 - version.Minor) }; + return [.. versionBytes, .. randomData]; + } + } + + internal static byte[] GetEncryptedRsaPreMasterSecret(byte[] cert, byte[] premaster) + { + if (cert == null) + { + throw new ArgumentNullException(nameof(cert)); + } + + if (premaster == null) + { + throw new ArgumentNullException(nameof(premaster)); + } + + + var certificate = new X509Certificate2(cert); + var rsa = certificate.GetRSAPublicKey(); + return rsa.Encrypt(premaster, RSAEncryptionPadding.Pkcs1); + } + } +} diff --git a/Makefile b/Makefile deleted file mode 100644 index ba78154..0000000 --- a/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -DTLS_VERSION:=1.0.21 - -.PHONY: all -all: src/DTLS.Net/bin/Release/DTLS.Net.$(DTLS_VERSION).nupkg - -src/DTLS.Net/bin/Release/DTLS.Net.$(DTLS_VERSION).nupkg: - docker run -v $(PWD):/app --entrypoint /app/pack.sh creatordev/dotnet-mono-base Release src/DTLS.Net - -.PHONY: clean -clean: - rm -rf src/DTLS.Net/bin src/DTLS.Net/obj src/DTLS.Net/project.lock.json diff --git a/NetSnmpTestClient/NetSnmpTestClient.csproj b/NetSnmpTestClient/NetSnmpTestClient.csproj new file mode 100644 index 0000000..d71f3b9 --- /dev/null +++ b/NetSnmpTestClient/NetSnmpTestClient.csproj @@ -0,0 +1,12 @@ + + + + Exe + net8;net7;net6;net481;net48;net472;net462; + + + + + + + diff --git a/NetSnmpTestClient/Program.cs b/NetSnmpTestClient/Program.cs new file mode 100644 index 0000000..19a4073 --- /dev/null +++ b/NetSnmpTestClient/Program.cs @@ -0,0 +1,35 @@ +using DTLS; +using System; +using System.Net; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; + +namespace NetSnmpTestClient +{ + public class Program + { + public static async Task Main() + { + using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser)) + { + store.Open(OpenFlags.ReadOnly); + var myCertCollection = store.Certificates.Find(X509FindType.FindByThumbprint, "", true); + using (var chain = new X509Chain()) + { + chain.Build(myCertCollection[0]); + + //If reaching out to an IPv6 address you will need to create a client with an IPv6 endpoint + //var client = new Client(new IPEndPoint(IPAddress.IPv6Any, 0)); + using (var client = new Client(new IPEndPoint(IPAddress.Any, 0))) + { + client.LoadX509Certificate(chain); + client.SupportedCipherSuites.Add(TCipherSuite.TLS_RSA_WITH_AES_256_CBC_SHA); + await client.ConnectToServerAsync(new IPEndPoint(IPAddress.Parse(""), 10161), TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(2)); + await client.SendAsync(Encoding.UTF8.GetBytes("TEST"), TimeSpan.FromSeconds(5)); + } + } + } + } + } +} diff --git a/README.md b/README.md index 6b9bec8..cc7df85 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,3 @@ -![Imagination Technologies Limited logo](doc/img.png) - ----- - ## DTLS.Net [![License (3-Clause BSD)](https://img.shields.io/badge/license-BSD%203--Clause-blue.svg?style=flat-square)](http://opensource.org/licenses/BSD-3-Clause) @@ -14,13 +10,19 @@ DTLS.Net was developed for use in an [implementation](https://github.com/Creator * TLS_PSK_WITH_AES_128_CCM_8 * TLS_PSK_WITH_AES_128_CBC_SHA256 + +DTLS2.Net was developed for use with Net-SNMP and an RSA certificate from the Windows Certificate Store and adds a new CipherSuite on the client side + +* TLS_RSA_WITH_AES_256_CBC_SHA + ### Limitations Since the client is only required to serve for the above project it has several inherent limitations: 1. No automatic retransmission -2. No support for fragmentation of handshake packets +2. No reordering of messages or fragments 3. Does not verify Server Certificates (against CA) +4. No resumption when using the New Session Ticket Extention The server currently also has the following limitations: diff --git a/test/TestClient/Client.pem b/TestClient/Client.pem similarity index 100% rename from test/TestClient/Client.pem rename to TestClient/Client.pem diff --git a/test/TestClient/Program.cs b/TestClient/Program.cs similarity index 62% rename from test/TestClient/Program.cs rename to TestClient/Program.cs index 1bf1855..bc86e07 100644 --- a/test/TestClient/Program.cs +++ b/TestClient/Program.cs @@ -22,8 +22,6 @@ products derived from this software without specific prior written permission. using DTLS; using System; -using System.Collections.Generic; -using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; @@ -34,9 +32,9 @@ public class Program { static byte[] HexToBytes(string hex) { - byte[] result = new byte[hex.Length / 2]; - int count = 0; - for (int index = 0; index < hex.Length; index += 2) + var result = new byte[hex.Length / 2]; + var count = 0; + for (var index = 0; index < hex.Length; index += 2) { result[count] = Convert.ToByte(hex.Substring(index, 2), 16); count++; @@ -44,33 +42,34 @@ static byte[] HexToBytes(string hex) return result; } - public static void Main(string[] args) + public static async Task Main(string[] args) { - bool exit = false; + var exit = false; Console.WriteLine("Press any key to Connect to Server"); Console.ReadKey(true); - Client client = new Client(new IPEndPoint(IPAddress.Any, 56239)); - client.PSKIdentities.AddIdentity(Encoding.UTF8.GetBytes("oFIrQFrW8EWcZ5u7eGfrkw"), HexToBytes("7CCDE14A5CF3B71C0C08C8B7F9E5")); - //client.LoadCertificateFromPem(@"Client.pem"); - client.SupportedCipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8); - client.ConnectToServer(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5684)); - Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e) + using (var client = new Client(new IPEndPoint(IPAddress.Any, 56239))) { - e.Cancel = true; - exit = true; - }; - Console.WriteLine(); - Console.WriteLine("Press Ctrl+C to stop the client. Any other characters are send to server"); - Console.WriteLine(); - while (!exit) - { - if (Console.KeyAvailable) + client.PSKIdentities.AddIdentity(Encoding.UTF8.GetBytes("oFIrQFrW8EWcZ5u7eGfrkw"), HexToBytes("7CCDE14A5CF3B71C0C08C8B7F9E5")); + client.LoadCertificateFromPem(@"Client.pem"); + client.SupportedCipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8); + await client.ConnectToServerAsync(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 5684), TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1)); + Console.CancelKeyPress += delegate (object sender, ConsoleCancelEventArgs e) + { + e.Cancel = true; + exit = true; + }; + Console.WriteLine(); + Console.WriteLine("Press Ctrl+C to stop the client. Any other characters are send to server"); + Console.WriteLine(); + while (!exit) { - ConsoleKeyInfo pressedKey = Console.ReadKey(true); - client.Send(Encoding.UTF8.GetBytes(pressedKey.KeyChar.ToString())); + if (Console.KeyAvailable) + { + var pressedKey = Console.ReadKey(true); + await client.SendAsync(Encoding.UTF8.GetBytes(pressedKey.KeyChar.ToString())); + } } } - client.Stop(); } } } diff --git a/TestClient/TestClient.csproj b/TestClient/TestClient.csproj new file mode 100644 index 0000000..d71f3b9 --- /dev/null +++ b/TestClient/TestClient.csproj @@ -0,0 +1,12 @@ + + + + Exe + net8;net7;net6;net481;net48;net472;net462; + + + + + + + diff --git a/test/TestServer/Program.cs b/TestServer/Program.cs similarity index 85% rename from test/TestServer/Program.cs rename to TestServer/Program.cs index 72568b2..dbea421 100644 --- a/test/TestServer/Program.cs +++ b/TestServer/Program.cs @@ -22,22 +22,31 @@ products derived from this software without specific prior written permission. using DTLS; using System; -using System.Collections.Generic; -using System.Linq; using System.Net; using System.Text; -using System.Threading.Tasks; namespace TestServer { public class Program { + static byte[] HexToBytes(string hex) + { + var result = new byte[hex.Length / 2]; + var count = 0; + for (var index = 0; index < hex.Length; index += 2) + { + result[count] = Convert.ToByte(hex.Substring(index, 2), 16); + count++; + } + return result; + } + public static void Main(string[] args) { - Server server = new Server(new IPEndPoint(IPAddress.Any, 5684)); + var server = new Server(new IPEndPoint(IPAddress.Any, 5684)); try { - server.DataReceived += new Server.DataReceivedEventHandler(server_DataReceived); + server.DataReceived += new Server.DataReceivedEventHandler(Server_DataReceived); server.PSKIdentities.AddIdentity(Encoding.UTF8.GetBytes("oFIrQFrW8EWcZ5u7eGfrkw"), HexToBytes("7CCDE14A5CF3B71C0C08C8B7F9E5")); server.LoadCertificateFromPem("TestServer.pem"); server.RequireClientCertificate = true; @@ -57,21 +66,6 @@ public static void Main(string[] args) } } - static byte[] HexToBytes(string hex) - { - byte[] result = new byte[hex.Length / 2]; - int count = 0; - for (int index = 0; index < hex.Length; index += 2) - { - result[count] = Convert.ToByte(hex.Substring(index, 2), 16); - count++; - } - return result; - } - - static void server_DataReceived(EndPoint endPoint, byte[] data) - { - Console.Write(Encoding.UTF8.GetString(data)); - } + static void Server_DataReceived(EndPoint endPoint, byte[] data) => Console.Write(Encoding.UTF8.GetString(data)); } -} +} \ No newline at end of file diff --git a/TestServer/TestServer.csproj b/TestServer/TestServer.csproj new file mode 100644 index 0000000..d71f3b9 --- /dev/null +++ b/TestServer/TestServer.csproj @@ -0,0 +1,12 @@ + + + + Exe + net8;net7;net6;net481;net48;net472;net462; + + + + + + + diff --git a/test/TestServer/TestServer.pem b/TestServer/TestServer.pem similarity index 100% rename from test/TestServer/TestServer.pem rename to TestServer/TestServer.pem diff --git a/doc/coding_style.md b/doc/coding_style.md deleted file mode 100644 index cff24bc..0000000 --- a/doc/coding_style.md +++ /dev/null @@ -1,16 +0,0 @@ -![](img.png) - ----- - - -# DTLS.Net. - - -## Coding style guide. - -TODO: Basically standard C# style. - - - ----- ----- \ No newline at end of file diff --git a/doc/img.png b/doc/img.png deleted file mode 100644 index 83d97b2..0000000 Binary files a/doc/img.png and /dev/null differ diff --git a/doc/rebasing_info.md b/doc/rebasing_info.md deleted file mode 100644 index 75c8e76..0000000 --- a/doc/rebasing_info.md +++ /dev/null @@ -1,174 +0,0 @@ - - -![](images/img.png) - ----- - -# Extra information for DTLS.Net contributors. - - -## Rebasing. - -Usually rebasing commits that have already been pushed is strongly discouraged. - -The main problem with rebasing pushed commits is that if another contributor has based -their work on one of the commits which is subsequently rebased, this effectively -creates a parallel timeline in which the commits on which their work stands never existed. - -Given that we created our own fork, and branched within that fork, it's safe -to assume that nobody will be using it as a baseline. We can therefore rebase without causing -the universe to implode. - -That said, here's the process... - - -First, fetch any upstream changes... - -``` -$ git fetch upstream -``` - -and change to your development branch... - -``` -$ git checkout dev-branch1 -``` - -### Rebasing your commits on top of upstream/master. - -Now if you want to rebase your commits on top without making any additional changes you can use the command: - -``` -$ git rebase upstream/master -``` - -### Editing commit messages. - -If you want to edit a commit message you will need to use the interactive rebase. - -``` -$ git rebase -i origin/dev-branch1 -``` - -Your default text editor will launch and display something like... - -``` -pick d8ff6b0 Update readme -pick 80309d3 Fixed tpyo -pick d38fb35 Deleted line - -# Rebase 0bee19a..d38fb35 onto 0bee19a (3 command(s)) -# -# Commands: -# p, pick = use commit -# r, reword = use commit, but edit the commit message -# e, edit = use commit, but stop for amending -# s, squash = use commit, but meld into previous commit -# f, fixup = like "squash", but discard this commit's log message -# x, exec = run command (the rest of the line) using shell -# d, drop = remove commit -``` -To change a commit comment, select the line you wish to change by replacing -"pick" with "r" and then saving the document. - -``` -pick d8ff6b0 Update readme -r 80309d3 Fixed tpyo -pick d38fb35 Deleted line -``` - -Your text editor will open a new window allowing you to change the commit message... - -``` -Fixed typo - -# Please enter the commit message for your changes. Lines starting -# with '#' will be ignored, and an empty message aborts the commit. -``` - -Save and quit to apply your changes. - - -### Squashing commits. - -If you want to squash multiple commits together into a single commit you will need to use the interactive -rebase. - -``` -$ git rebase -i origin/dev-branch1 -``` - -Your default text editor will launch and display something like... - -``` -pick d8ff6b0 Update readme -pick 80309d3 Fixed tpyo -pick d38fb35 Deleted line - -# Rebase 0bee19a..d38fb35 onto 0bee19a (3 command(s)) -# -# Commands: -# p, pick = use commit -# r, reword = use commit, but edit the commit message -# e, edit = use commit, but stop for amending -# s, squash = use commit, but meld into previous commit -# f, fixup = like "squash", but discard this commit's log message -# x, exec = run command (the rest of the line) using shell -# d, drop = remove commit -``` -To change a commit comment, select the lines you wish to squash by replacing -"pick" with "s" and saving the document. - - -For example: - -``` -pick d8ff6b0 Update readme -s 80309d3 Fixed tpyo -s d38fb35 Deleted line -``` - -If all goes well your text editor will open and display something like... - -``` -# This is a combination of 3 commits. -# The first commit's message is: -Update readme - -# This is the 2nd commit message: - -Fixed typo - -# This is the 3rd commit message: - -Deleted line -``` - -Comment out any of the commit messages you no longer require, enter a new message -then save and quit. - - -###Aborting a rebase. - -If you feel uncertain at any stage, you can abort a rebase using the following command: - -``` -$ git rebase --abort -``` - - -### Pushing your changes. - -After rebasing you will not be able to push your changes back to your branch. You will need to use the --force option. -There's no going back if you make a mistake so be sure about what you are pushing, and that you are pushing the correct branch to the correct remote. - -``` -$ git push -f origin dev-branch1:dev-branch1 -``` - -The above command will replace origin/dev-branch1 with the contents of dev-branch1, including all history. - ----- - ----- - diff --git a/global.json b/global.json deleted file mode 100644 index b51e28b..0000000 --- a/global.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "projects": [ "src", "test" ], - "sdk": { - "version": "1.0.0-preview1-002702" - } -} diff --git a/pack.sh b/pack.sh deleted file mode 100644 index c0317bf..0000000 --- a/pack.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -CONFIGURATION=$1 -shift - -for PACKAGE in $*; do - cd /app/$PACKAGE - dotnet restore - dotnet pack --configuration=$CONFIGURATION -done \ No newline at end of file diff --git a/src/DTLS.Net/Certificates/Certificates.cs b/src/DTLS.Net/Certificates/Certificates.cs deleted file mode 100644 index 75b1119..0000000 --- a/src/DTLS.Net/Certificates/Certificates.cs +++ /dev/null @@ -1,375 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using Org.BouncyCastle.Asn1; -using Org.BouncyCastle.Asn1.X509; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Crypto.Generators; -using Org.BouncyCastle.Crypto.Operators; -using Org.BouncyCastle.Crypto.Parameters; -using Org.BouncyCastle.Crypto.Prng; -using Org.BouncyCastle.Math; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Utilities; -using Org.BouncyCastle.X509; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Org.BouncyCastle.Asn1.Pkcs; -using System.Collections; - -namespace DTLS -{ - public static class Certificates - { - - private static void AddStandardCertificateInfo(X509V3CertificateGenerator certificateGenerator, SecureRandom random, CertificateSubject subject, CertificateSubject issuer, DateTime startDate, DateTime expiryDate) - { - BigInteger serialNumber = BigIntegers.CreateRandomInRange(BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random); - certificateGenerator.SetSerialNumber(serialNumber); - - certificateGenerator.SetIssuerDN(GetName(issuer)); - certificateGenerator.SetSubjectDN(GetName(subject)); - - certificateGenerator.SetNotBefore(startDate); - certificateGenerator.SetNotAfter(expiryDate); - } - - private static byte[] ExportCertificate(X509Certificate certificate, AsymmetricCipherKeyPair subjectKeyPair, TCertificateFormat certificateFormat) - { - byte[] result = null; - switch (certificateFormat) - { - case TCertificateFormat.NotSet: - break; - case TCertificateFormat.PEM: - using (MemoryStream stream = new MemoryStream()) - { - using (StreamWriter writer = new StreamWriter(stream)) - { - Org.BouncyCastle.Utilities.IO.Pem.PemWriter pemWriter = new Org.BouncyCastle.Utilities.IO.Pem.PemWriter(writer); - if (subjectKeyPair.Private is ECKeyParameters) - { - ECPrivateKeyParameters priv = (ECPrivateKeyParameters)subjectKeyPair.Private; - ECDomainParameters dp = priv.Parameters; - int orderBitLength = dp.N.BitLength; - Org.BouncyCastle.Asn1.Sec.ECPrivateKeyStructure ec; - Org.BouncyCastle.Asn1.X9.X962Parameters x962; - if (priv.PublicKeyParamSet == null) - { - Org.BouncyCastle.Asn1.X9.X9ECParameters ecP = new Org.BouncyCastle.Asn1.X9.X9ECParameters(dp.Curve, dp.G, dp.N, dp.H, dp.GetSeed()); - x962 = new Org.BouncyCastle.Asn1.X9.X962Parameters(ecP); - } - else - { - x962 = new Org.BouncyCastle.Asn1.X9.X962Parameters(priv.PublicKeyParamSet); - } - ec = new Org.BouncyCastle.Asn1.Sec.ECPrivateKeyStructure(orderBitLength, priv.D, SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public).PublicKeyData, x962); - pemWriter.WriteObject(new Org.BouncyCastle.Utilities.IO.Pem.PemObject("EC PRIVATE KEY", ec.GetEncoded())); - } - else - { - pemWriter.WriteObject(new Org.BouncyCastle.OpenSsl.MiscPemGenerator(subjectKeyPair.Private)); - } - pemWriter.WriteObject(new Org.BouncyCastle.OpenSsl.MiscPemGenerator(subjectKeyPair.Public)); - pemWriter.WriteObject(new Org.BouncyCastle.OpenSsl.MiscPemGenerator(certificate)); - writer.Flush(); - result = stream.ToArray(); - } - } - break; - case TCertificateFormat.PFX: - //Asn1Sequence asn1Sequence = Asn1Sequence.GetInstance(Asn1Object.FromByteArray(certificate.GetEncoded())); - //asn1Sequence.GetObjects - //Org.BouncyCastle.Asn1.Pkcs.Pfx pfx = new Org.BouncyCastle.Asn1.Pkcs.Pfx(); - //Org.BouncyCastle.Asn1.Pkcs.PrivateKeyInfo info = Org.BouncyCastle.Pkcs.PrivateKeyInfoFactory.CreatePrivateKeyInfo(subjectKeyPair.Private); - //result = pfx.GetEncoded(Asn1Encodable.Der); - break; - case TCertificateFormat.CER: - result = certificate.GetEncoded(); - break; - default: - break; - } - return result; - } - - private static AsymmetricCipherKeyPair GenerateKeys(X509V3CertificateGenerator certificateGenerator, SecureRandom random, SignatureHashAlgorithm signatureAlgorithm) - { - AsymmetricCipherKeyPair result = null; - switch (signatureAlgorithm.Signature) - { - case TSignatureAlgorithm.Anonymous: - break; - case TSignatureAlgorithm.RSA: - KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(random, 2048); - RsaKeyPairGenerator rsaKeyPairGenerator = new RsaKeyPairGenerator(); - rsaKeyPairGenerator.Init(keyGenerationParameters); - result = rsaKeyPairGenerator.GenerateKeyPair(); - break; - case TSignatureAlgorithm.DSA: - break; - case TSignatureAlgorithm.ECDSA: - //ECDomainParameters ellipticCurveParameters = EllipticCurveFactory.GetEllipticCurveParameters(TEllipticCurve.secp256r1); - ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); - //keyPairGenerator.Init(new ECKeyGenerationParameters(ellipticCurveParameters, random)); - keyPairGenerator.Init(new ECKeyGenerationParameters(Org.BouncyCastle.Asn1.Sec.SecObjectIdentifiers.SecP256r1, random)); - result = keyPairGenerator.GenerateKeyPair(); - //certificateGenerator.AddExtension(X509Extensions.SubjectPublicKeyInfo) - //PrivateKey = (ECPrivateKeyParameters)keys.Private; - //PublicKey = (ECPublicKeyParameters)keys.Public; - break; - default: - break; - } - - certificateGenerator.SetPublicKey(result.Public); - return result; - } - - public static byte[] GenerateCertificate(CertificateSubject subject, CertificateInfo issuer, DateTime startDate, DateTime expiryDate, SignatureHashAlgorithm signatureAlgorithm, TCertificateFormat certificateFormat) - { - byte[] result = null; - AsymmetricKeyParameter privateKey = issuer.PrivateKey as AsymmetricKeyParameter; - if (privateKey != null) - { - - CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator(); - SecureRandom random = new SecureRandom(randomGenerator); - X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator(); - AddStandardCertificateInfo(certificateGenerator, random, subject, issuer.Subject, startDate, expiryDate); - AsymmetricCipherKeyPair subjectKeyPair = GenerateKeys(certificateGenerator, random, signatureAlgorithm); - - string algorithm = GetAlgorithm(signatureAlgorithm); - - certificateGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(false)); - certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyEncipherment)); - certificateGenerator.AddExtension(X509Extensions.ExtendedKeyUsage, false, new ExtendedKeyUsage(new KeyPurposeID[] { KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPClientAuth })); - byte[] subjectKeyID = new byte[20]; - random.NextBytes(subjectKeyID, 0, 20); - certificateGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(subjectKeyID)); - if (issuer.SubjectKeyID != null) - certificateGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifier(issuer.SubjectKeyID)); - - //if ((subject.AlternativeNames != null) && (subject.AlternativeNames.Count > 0)) - //{ - // certificateGenerator.AddExtension(X509Extensions.SubjectAlternativeName, true, new SubjectAlternativeNames(false)); - // //SubjectAlternativeName - // //GeneralName.DirectoryName - // //GeneralName.IPAddress - //} - - Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(new Asn1SignatureFactory(algorithm, privateKey, random)); - result = ExportCertificate(certificate, subjectKeyPair, certificateFormat); - } - return result; - } - - public static byte[] GenerateIntermediateCACertificate(CertificateSubject subject, CertificateInfo issuer, DateTime startDate, DateTime expiryDate, SignatureHashAlgorithm signatureAlgorithm, TCertificateFormat certificateFormat) - { - byte[] result = null; - AsymmetricKeyParameter privateKey = issuer.PrivateKey as AsymmetricKeyParameter; - if (privateKey != null) - { - CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator(); - SecureRandom random = new SecureRandom(randomGenerator); - X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator(); - AddStandardCertificateInfo(certificateGenerator, random, subject, issuer.Subject, startDate, expiryDate); - AsymmetricCipherKeyPair subjectKeyPair = GenerateKeys(certificateGenerator, random, signatureAlgorithm); - - certificateGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(0)); - certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyCertSign)); - byte[] subjectKeyID = new byte[20]; - random.NextBytes(subjectKeyID, 0, 20); - certificateGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(subjectKeyID)); - if (issuer.SubjectKeyID != null) - certificateGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifier(issuer.SubjectKeyID)); - - string algorithm = GetAlgorithm(signatureAlgorithm); - - Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(new Asn1SignatureFactory(algorithm, privateKey, random)); - - result = ExportCertificate(certificate, subjectKeyPair, certificateFormat); - } - return result; - } - - public static byte[] GenerateRootCACertificate(CertificateSubject subject, DateTime startDate, DateTime expiryDate, SignatureHashAlgorithm signatureAlgorithm, TCertificateFormat certificateFormat) - { - byte[] result = null; - - CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator(); - SecureRandom random = new SecureRandom(randomGenerator); - X509V3CertificateGenerator certificateGenerator = new X509V3CertificateGenerator(); - AddStandardCertificateInfo(certificateGenerator, random, subject, subject, startDate, expiryDate); - AsymmetricCipherKeyPair subjectKeyPair = GenerateKeys(certificateGenerator, random, signatureAlgorithm); - - certificateGenerator.AddExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true)); - certificateGenerator.AddExtension(X509Extensions.KeyUsage, true, new KeyUsage(KeyUsage.DigitalSignature | KeyUsage.KeyCertSign)); - byte[] subjectKeyID = new byte[20]; - random.NextBytes(subjectKeyID, 0, 20); - certificateGenerator.AddExtension(X509Extensions.SubjectKeyIdentifier, false, new SubjectKeyIdentifier(subjectKeyID)); - certificateGenerator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifier(subjectKeyID)); - - string algorithm = GetAlgorithm(signatureAlgorithm); - // selfsign certificate - Org.BouncyCastle.X509.X509Certificate certificate = certificateGenerator.Generate(new Asn1SignatureFactory(algorithm, subjectKeyPair.Private, random)); - - result = ExportCertificate(certificate, subjectKeyPair, certificateFormat); - - return result; - } - - private static string GetAlgorithm(SignatureHashAlgorithm signatureAlgorithm) - { - // eg "SHA256WithRSA", "SHA224WithECDSA",; - StringBuilder result = new StringBuilder(); - result.Append(signatureAlgorithm.Hash.ToString()); - result.Append("With"); - result.Append(signatureAlgorithm.Signature.ToString()); - return result.ToString(); - } - - public static CertificateInfo GetCertificateInfo(byte[] certificate, TCertificateFormat certificateFormat) - { - CertificateInfo result = null; - X509CertificateStructure cert = null; - switch (certificateFormat) - { - case TCertificateFormat.NotSet: - break; - case TCertificateFormat.PEM: - Org.BouncyCastle.Utilities.IO.Pem.PemReader reader = new Org.BouncyCastle.Utilities.IO.Pem.PemReader(new StreamReader(new MemoryStream(certificate))); - Org.BouncyCastle.Utilities.IO.Pem.PemObject pem = reader.ReadPemObject(); - while (pem != null) - { - if (pem.Type.EndsWith("CERTIFICATE")) - { - cert = X509CertificateStructure.GetInstance(pem.Content); - } - else if (pem.Type.EndsWith("PRIVATE KEY")) - { - if (result == null) - result = new CertificateInfo(); - - result.PrivateKey = GetPrivateKeyFromPEM(pem); - } - pem = reader.ReadPemObject(); - } - break; - case TCertificateFormat.PFX: - break; - case TCertificateFormat.CER: - cert = X509CertificateStructure.GetInstance(certificate); - break; - default: - break; - } - if (cert != null) - { - if (result == null) - result = new CertificateInfo(); - result.Subject = new CertificateSubject(cert); - X509Certificate certX509 = new X509Certificate(cert); - Asn1OctetString subjectKeyID = certX509.GetExtensionValue(X509Extensions.SubjectKeyIdentifier); - if (subjectKeyID != null) - { - byte[] encodeKeyID = subjectKeyID.GetOctets(); - byte[] keyID = new byte[encodeKeyID[1]]; - Buffer.BlockCopy(encodeKeyID, 2, keyID, 0, encodeKeyID[1]); - result.SubjectKeyID = keyID; - } - } - return result; - } - - private static X509Name GetName(CertificateSubject info) - { - List ids = new List(); - List values = new List(); - if (!string.IsNullOrEmpty(info.CommonName)) - { - ids.Add(X509Name.CN); - values.Add(info.CommonName); - } - if (!string.IsNullOrEmpty(info.Organistion)) - { - ids.Add(X509Name.O); - values.Add(info.Organistion); - } - if (!string.IsNullOrEmpty(info.OrganistionUnit)) - { - ids.Add(X509Name.OU); - values.Add(info.OrganistionUnit); - } - if (!string.IsNullOrEmpty(info.Location)) - { - ids.Add(X509Name.L); - values.Add(info.Location); - } - if (!string.IsNullOrEmpty(info.State)) - { - ids.Add(X509Name.ST); - values.Add(info.State); - } - if (!string.IsNullOrEmpty(info.Country)) - { - ids.Add(X509Name.C); - values.Add(info.Country); - } - return new X509Name(ids, values); - } - - internal static AsymmetricKeyParameter GetPrivateKeyFromPEM(Org.BouncyCastle.Utilities.IO.Pem.PemObject pem) - { - AsymmetricKeyParameter result = null; - if (pem.Type.EndsWith("EC PRIVATE KEY")) - { - Asn1Sequence sequence = Asn1Sequence.GetInstance(pem.Content); - IEnumerator e = sequence.GetEnumerator(); - e.MoveNext(); - BigInteger version = ((DerInteger)e.Current).Value; - PrivateKeyInfo privateKeyInfo; - if (version.IntValue == 0) //V1 - { - privateKeyInfo = PrivateKeyInfo.GetInstance(sequence); - } - else - { - Org.BouncyCastle.Asn1.Sec.ECPrivateKeyStructure ec = Org.BouncyCastle.Asn1.Sec.ECPrivateKeyStructure.GetInstance(sequence); - AlgorithmIdentifier algId = new AlgorithmIdentifier(Org.BouncyCastle.Asn1.X9.X9ObjectIdentifiers.IdECPublicKey, ec.GetParameters()); - privateKeyInfo = new PrivateKeyInfo(algId, ec.ToAsn1Object()); - } - result = Org.BouncyCastle.Security.PrivateKeyFactory.CreateKey(privateKeyInfo); - } - else if (pem.Type.EndsWith("PRIVATE KEY")) - { - result = Org.BouncyCastle.Security.PrivateKeyFactory.CreateKey(pem.Content); - } - return result; - } - - } -} diff --git a/src/DTLS.Net/CipherSuite/CipherSuites.cs b/src/DTLS.Net/CipherSuite/CipherSuites.cs deleted file mode 100644 index 2ed4b5b..0000000 --- a/src/DTLS.Net/CipherSuite/CipherSuites.cs +++ /dev/null @@ -1,137 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace DTLS -{ - internal class CipherSuites - { - private class CipherSuite - { - public TCipherSuite Suite { get; set; } - public TKeyExchangeAlgorithm KeyExchangeAlgorithm { get; set; } - //public TEncryptionAlgorithm EncryptionAlgorithm { get; set; } - public TSignatureAlgorithm SignatureAlgorithm { get; set; } - public Version MinVersion { get; set; } - public TPseudorandomFunction PRF { get; set; } - - public CipherSuite(TCipherSuite cipherSuite, TKeyExchangeAlgorithm keyExchangeAlgorithm, TSignatureAlgorithm signatureAlgorithm, Version minVersion,TPseudorandomFunction prf) - { - Suite = cipherSuite; - KeyExchangeAlgorithm = keyExchangeAlgorithm; - SignatureAlgorithm = signatureAlgorithm; - MinVersion = minVersion; - PRF = prf; - } - } - - private static Dictionary _CipherSuites; - - static CipherSuites() - { - _CipherSuites = new Dictionary(); - _CipherSuites.Add(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, new CipherSuite(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8, TKeyExchangeAlgorithm.ECDHE_ECDSA, TSignatureAlgorithm.ECDSA, DTLSRecord.Version1_2, TPseudorandomFunction.SHA256)); - _CipherSuites.Add(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, new CipherSuite(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TKeyExchangeAlgorithm.ECDHE_ECDSA, TSignatureAlgorithm.ECDSA, DTLSRecord.Version1_0, TPseudorandomFunction.SHA256)); - _CipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8, new CipherSuite(TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8, TKeyExchangeAlgorithm.PSK, TSignatureAlgorithm.Anonymous, DTLSRecord.Version1_2, TPseudorandomFunction.SHA256)); - _CipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256, new CipherSuite(TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256, TKeyExchangeAlgorithm.PSK, TSignatureAlgorithm.Anonymous, DTLSRecord.Version1_0, TPseudorandomFunction.SHA256)); - _CipherSuites.Add(TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, new CipherSuite(TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, TKeyExchangeAlgorithm.ECDHE_PSK, TSignatureAlgorithm.Anonymous, DTLSRecord.Version1_0, TPseudorandomFunction.SHA256)); - } - - - public static TKeyExchangeAlgorithm GetKeyExchangeAlgorithm(TCipherSuite cipherSuite) - { - TKeyExchangeAlgorithm result = TKeyExchangeAlgorithm.NotSet; - CipherSuite suite; - if (_CipherSuites.TryGetValue(cipherSuite, out suite)) - { - result = suite.KeyExchangeAlgorithm; - } - return result; - } - - public static TPseudorandomFunction GetPseudorandomFunction(Version version, TCipherSuite cipherSuite) - { - TPseudorandomFunction result = TPseudorandomFunction.Legacy; - if (version >= DTLSRecord.Version1_2) - { - CipherSuite suite; - if (_CipherSuites.TryGetValue(cipherSuite, out suite)) - { - result = suite.PRF; - } - } - return result; - } - - public static TSignatureAlgorithm GetSignatureAlgorithm(TCipherSuite cipherSuite) - { - TSignatureAlgorithm result = TSignatureAlgorithm.Anonymous; - CipherSuite suite; - if (_CipherSuites.TryGetValue(cipherSuite, out suite)) - { - result = suite.SignatureAlgorithm; - } - return result; - } - - public static bool SuiteUsable(TCipherSuite cipherSuite, Org.BouncyCastle.Crypto.AsymmetricKeyParameter privateKey, PSKIdentities pskIdentities, bool haveValidatePSKCallback) - { - bool result = false; - TKeyExchangeAlgorithm keyExchangeAlgorithm = GetKeyExchangeAlgorithm(cipherSuite); - switch (keyExchangeAlgorithm) - { - case TKeyExchangeAlgorithm.NotSet: - break; - case TKeyExchangeAlgorithm.PSK: - case TKeyExchangeAlgorithm.ECDHE_PSK: - result = haveValidatePSKCallback || ((pskIdentities != null) && (pskIdentities.Count > 0)); - break; - case TKeyExchangeAlgorithm.ECDH_ECDSA: - case TKeyExchangeAlgorithm.ECDHE_ECDSA: - result = (privateKey != null); - break; - default: - break; - } - return result; - } - - public static bool SupportedVersion(TCipherSuite cipherSuite, Version version) - { - bool result = false; - CipherSuite suite; - if (_CipherSuites.TryGetValue(cipherSuite, out suite)) - { - result = suite.MinVersion <= version; - } - return result; - } - - - - - } -} diff --git a/src/DTLS.Net/CipherSuite/TCipherSuite.cs b/src/DTLS.Net/CipherSuite/TCipherSuite.cs deleted file mode 100644 index cc69cf8..0000000 --- a/src/DTLS.Net/CipherSuite/TCipherSuite.cs +++ /dev/null @@ -1,82 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace DTLS -{ - public enum TCipherSuite - { - TLS_NULL_WITH_NULL_NULL = 0, - - TLS_RSA_WITH_NULL_MD5 = 0x01, - TLS_RSA_WITH_NULL_SHA = 0x02, - TLS_RSA_WITH_NULL_SHA256 = 0x3B, - TLS_RSA_WITH_RC4_128_MD5 = 0x04, - TLS_RSA_WITH_RC4_128_SHA = 0x05, - TLS_RSA_WITH_3DES_EDE_CBC_SHA = 0x0A, - TLS_RSA_WITH_AES_128_CBC_SHA = 0x2F, - TLS_RSA_WITH_AES_256_CBC_SHA = 0x35, - TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x3C, - TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x3D, - - TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA = 0x0D, - TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA = 0x10, - TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA = 0x13, - TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA = 0x16, - TLS_DH_DSS_WITH_AES_128_CBC_SHA = 0x30, - TLS_DH_RSA_WITH_AES_128_CBC_SHA = 0x31, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA = 0x32, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x33, - TLS_DH_DSS_WITH_AES_256_CBC_SHA = 0x36, - TLS_DH_RSA_WITH_AES_256_CBC_SHA = 0x37, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA = 0x38, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x39, - TLS_DH_DSS_WITH_AES_128_CBC_SHA256 = 0x3E, - TLS_DH_RSA_WITH_AES_128_CBC_SHA256 = 0x3F, - TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 = 0x40, - TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x67, - TLS_DH_DSS_WITH_AES_256_CBC_SHA256 = 0x68, - TLS_DH_RSA_WITH_AES_256_CBC_SHA256 = 0x69, - TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 = 0x6A, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x6B, - - TLS_DH_anon_WITH_RC4_128_MD5 = 0x18, - TLS_DH_anon_WITH_3DES_EDE_CBC_SHA = 0x1B, - TLS_DH_anon_WITH_AES_128_CBC_SHA = 0x34, - TLS_DH_anon_WITH_AES_256_CBC_SHA = 0x3A, - TLS_DH_anon_WITH_AES_128_CBC_SHA256 = 0x6C, - TLS_DH_anon_WITH_AES_256_CBC_SHA256 = 0x6D, - - TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 = 0xC0AE, - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023, - TLS_PSK_WITH_AES_128_CCM_8 = 0xC0A8, - TLS_PSK_WITH_AES_128_CBC_SHA256 = 0xAE, - TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 = 0xC037 - - } -} - - diff --git a/src/DTLS.Net/Client.cs b/src/DTLS.Net/Client.cs deleted file mode 100644 index 99198b8..0000000 --- a/src/DTLS.Net/Client.cs +++ /dev/null @@ -1,791 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Net; -using System.Net.Sockets; -using System.IO; -using Org.BouncyCastle.Crypto.Tls; -using Org.BouncyCastle.Crypto; -using System.Threading; -using Org.BouncyCastle.Utilities.IO.Pem; - -namespace DTLS -{ - public class Client - { - public delegate void DataReceivedEventHandler(System.Net.EndPoint endPoint, byte[] data); - public event DataReceivedEventHandler DataReceived; - - private static Version SupportedVersion = DTLSRecord.Version1_2; - - private EndPoint _LocalEndPoint; - private int _MaxPacketSize = 1440; - private Socket _Socket; - private List _SupportedCipherSuites; - - private bool _Terminate; - private ManualResetEvent _TriggerProcessRecords = new ManualResetEvent(false); - private Thread _ProcessRecordsThread; - - - private ManualResetEvent _Connected = new ManualResetEvent(false); - - private EndPoint _ServerEndPoint; - private ushort? _ServerEpoch; - private long _ServerSequenceNumber; - private ushort? _EncyptedServerEpoch; - - private ushort _Epoch; - private long _SequenceNumber; //realy only 48 bit - private ushort _MessageSequence; - private TlsCipher _Cipher; - private Version _Version; - - private bool _SendCertificate; - private IHandshakeMessage _ClientKeyExchange; - - private Certificate _Certificate; - private Org.BouncyCastle.Crypto.AsymmetricKeyParameter _PrivateKey; - - private HandshakeInfo _HandshakeInfo = new HandshakeInfo(); - private DTLSRecords _Records = new DTLSRecords(); - - private PSKIdentity _PSKIdentity; - private PSKIdentities _PSKIdentities; - - public EndPoint LocalEndPoint - { - get { return _LocalEndPoint; } - } - - public PSKIdentities PSKIdentities - { - get { return _PSKIdentities; } - } - - public List SupportedCipherSuites - { - get - { - return _SupportedCipherSuites; - } - } - - public Client(EndPoint localEndPoint) - : this(localEndPoint, null) - { - _SupportedCipherSuites = new List(); - } - - public Client(EndPoint localEndPoint, List supportedCipherSuites) - { - _LocalEndPoint = localEndPoint; - _PSKIdentities = new PSKIdentities(); - _SupportedCipherSuites = supportedCipherSuites; - _HandshakeInfo.ClientRandom = new RandomData(); - _HandshakeInfo.ClientRandom.Generate(); - - } - - - private void ChangeEpoch() - { - _Epoch++; - _SequenceNumber = 0; - } - - private long NextSequenceNumber() - { - long result = _SequenceNumber++; - return result; - } - - private void ProcessHandshake(DTLSRecord record) - { - byte[] data; - if (_EncyptedServerEpoch.HasValue && (_EncyptedServerEpoch.Value == record.Epoch)) - { - - int count = 0; - while ((_Cipher == null) && (count < 500)) - { - System.Threading.Thread.Sleep(10); - count++; - } - - if (_Cipher == null) - throw new Exception(); - - - if (_Cipher != null) - { - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - data = _Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); - } - else - data = record.Fragment; - } - else - data = record.Fragment; - - using (MemoryStream stream = new MemoryStream(data)) - { - HandshakeRecord handshakeRecord = HandshakeRecord.Deserialise(stream); - if (handshakeRecord != null) - { -#if DEBUG - Console.WriteLine(handshakeRecord.MessageType.ToString()); -#endif - switch (handshakeRecord.MessageType) - { - case THandshakeType.HelloRequest: - break; - case THandshakeType.ClientHello: - break; - case THandshakeType.ServerHello: - ServerHello serverHello = ServerHello.Deserialise(stream); - if (serverHello != null) - { - _ServerEpoch = record.Epoch; - _HandshakeInfo.UpdateHandshakeHash(data); - _HandshakeInfo.CipherSuite = (TCipherSuite)serverHello.CipherSuite; - _HandshakeInfo.ServerRandom = serverHello.Random; - Version version = SupportedVersion; - if (serverHello.ServerVersion < version) - version = serverHello.ServerVersion; - _Version = version; - } - break; - case THandshakeType.HelloVerifyRequest: - HelloVerifyRequest helloVerifyRequest = HelloVerifyRequest.Deserialise(stream); - if (helloVerifyRequest != null) - { - _Version = helloVerifyRequest.ServerVersion; - SendHello(helloVerifyRequest.Cookie); - } - break; - case THandshakeType.Certificate: - _HandshakeInfo.UpdateHandshakeHash(data); - break; - case THandshakeType.ServerKeyExchange: - _HandshakeInfo.UpdateHandshakeHash(data); - TKeyExchangeAlgorithm keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(_HandshakeInfo.CipherSuite); - byte[] preMasterSecret = null; - IKeyExchange keyExchange = null; - if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) - { - ECDHEServerKeyExchange serverKeyExchange = ECDHEServerKeyExchange.Deserialise(stream, _Version); - ECDHEKeyExchange keyExchangeECDHE = new ECDHEKeyExchange(); - keyExchangeECDHE.CipherSuite = _HandshakeInfo.CipherSuite; - keyExchangeECDHE.Curve = serverKeyExchange.EllipticCurve; - keyExchangeECDHE.KeyExchangeAlgorithm = keyExchangeAlgorithm; - keyExchangeECDHE.ClientRandom = _HandshakeInfo.ClientRandom; - keyExchangeECDHE.ServerRandom = _HandshakeInfo.ServerRandom; - keyExchangeECDHE.GenerateEphemeralKey(); - ECDHEClientKeyExchange clientKeyExchange = new ECDHEClientKeyExchange(keyExchangeECDHE.PublicKey); - _ClientKeyExchange = clientKeyExchange; - preMasterSecret = keyExchangeECDHE.GetPreMasterSecret(serverKeyExchange.PublicKeyBytes); - keyExchange = keyExchangeECDHE; - } - else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK) - { - ECDHEPSKServerKeyExchange serverKeyExchange = ECDHEPSKServerKeyExchange.Deserialise(stream, _Version); - ECDHEKeyExchange keyExchangeECDHE = new ECDHEKeyExchange(); - keyExchangeECDHE.CipherSuite = _HandshakeInfo.CipherSuite; - keyExchangeECDHE.Curve = serverKeyExchange.EllipticCurve; - keyExchangeECDHE.KeyExchangeAlgorithm = keyExchangeAlgorithm; - keyExchangeECDHE.ClientRandom = _HandshakeInfo.ClientRandom; - keyExchangeECDHE.ServerRandom = _HandshakeInfo.ServerRandom; - keyExchangeECDHE.GenerateEphemeralKey(); - ECDHEPSKClientKeyExchange clientKeyExchange = new ECDHEPSKClientKeyExchange(keyExchangeECDHE.PublicKey); - if (serverKeyExchange.PSKIdentityHint != null) - { - byte[] key = _PSKIdentities.GetKey(serverKeyExchange.PSKIdentityHint); - if (key != null) - _PSKIdentity = new PSKIdentity() { Identity = serverKeyExchange.PSKIdentityHint, Key = key }; - } - if (_PSKIdentity == null) - _PSKIdentity = _PSKIdentities.GetRandom(); - clientKeyExchange.PSKIdentity = _PSKIdentity.Identity; - _ClientKeyExchange = clientKeyExchange; - byte[] otherSecret = keyExchangeECDHE.GetPreMasterSecret(serverKeyExchange.PublicKeyBytes); - preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key); - keyExchange = keyExchangeECDHE; - } - else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK) - { - PSKServerKeyExchange serverKeyExchange = PSKServerKeyExchange.Deserialise(stream, _Version); - PSKClientKeyExchange clientKeyExchange = new PSKClientKeyExchange(); - if (serverKeyExchange.PSKIdentityHint != null) - { - byte[] key = _PSKIdentities.GetKey(serverKeyExchange.PSKIdentityHint); - if (key != null) - _PSKIdentity = new PSKIdentity() { Identity = serverKeyExchange.PSKIdentityHint, Key = key }; - } - if (_PSKIdentity == null) - _PSKIdentity = _PSKIdentities.GetRandom(); - byte[] otherSecret = new byte[_PSKIdentity.Key.Length]; - clientKeyExchange.PSKIdentity = _PSKIdentity.Identity; - _ClientKeyExchange = clientKeyExchange; - preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key); - } - _Cipher = TLSUtils.AssignCipher(preMasterSecret, true, _Version, _HandshakeInfo); - - break; - case THandshakeType.CertificateRequest: - _HandshakeInfo.UpdateHandshakeHash(data); - _SendCertificate = true; - break; - case THandshakeType.ServerHelloDone: - _HandshakeInfo.UpdateHandshakeHash(data); - if (_Cipher == null) - { - keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(_HandshakeInfo.CipherSuite); - if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK) - { - PSKClientKeyExchange clientKeyExchange = new PSKClientKeyExchange(); - _PSKIdentity = _PSKIdentities.GetRandom(); - byte[] otherSecret = new byte[_PSKIdentity.Key.Length]; - clientKeyExchange.PSKIdentity = _PSKIdentity.Identity; - _ClientKeyExchange = clientKeyExchange; - preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, _PSKIdentity.Key); - _Cipher = TLSUtils.AssignCipher(preMasterSecret, true, _Version, _HandshakeInfo); - } - } - - if (_SendCertificate) - { - SendHandshakeMessage(_Certificate, false); - } - SendHandshakeMessage(_ClientKeyExchange, false); - if (_SendCertificate) - { - CertificateVerify certificateVerify = new CertificateVerify(); - byte[] signatureHash = _HandshakeInfo.GetHash(); - certificateVerify.SignatureHashAlgorithm = new SignatureHashAlgorithm() { Signature = TSignatureAlgorithm.ECDSA, Hash = THashAlgorithm.SHA256 }; - certificateVerify.Signature = TLSUtils.Sign(_PrivateKey, true, _Version, _HandshakeInfo, certificateVerify.SignatureHashAlgorithm, signatureHash); - SendHandshakeMessage(certificateVerify, false); - } - SendChangeCipherSpec(); - byte[] handshakeHash = _HandshakeInfo.GetHash(); - Finished finished = new Finished(); - finished.VerifyData = TLSUtils.GetVerifyData(_Version,_HandshakeInfo,true, true, handshakeHash); - SendHandshakeMessage(finished, true); -#if DEBUG - Console.Write("Handshake Hash:"); - TLSUtils.WriteToConsole(handshakeHash); - Console.Write("Sent Verify:"); - TLSUtils.WriteToConsole(finished.VerifyData); -#endif - break; - case THandshakeType.CertificateVerify: - break; - case THandshakeType.ClientKeyExchange: - break; - case THandshakeType.Finished: - Finished serverFinished = Finished.Deserialise(stream); - handshakeHash = _HandshakeInfo.GetHash(); - byte[] calculatedVerifyData = TLSUtils.GetVerifyData(_Version,_HandshakeInfo, true, false, handshakeHash); -#if DEBUG - Console.Write("Recieved Verify:"); - TLSUtils.WriteToConsole(serverFinished.VerifyData); - Console.Write("Calc Verify:"); - TLSUtils.WriteToConsole(calculatedVerifyData); -#endif - if (TLSUtils.ByteArrayCompare(serverFinished.VerifyData, calculatedVerifyData)) - { -#if DEBUG - Console.WriteLine("Handshake Complete"); -#endif - _Connected.Set(); - } - break; - default: - break; - } - } - } - } - - private void ProcessRecord(DTLSRecord record) - { - try - { -#if DEBUG - Console.WriteLine(record.RecordType.ToString()); -#endif - switch (record.RecordType) - { - case TRecordType.ChangeCipherSpec: - if (_ServerEpoch.HasValue) - { - _ServerEpoch++; - _ServerSequenceNumber = 0; - _EncyptedServerEpoch = _ServerEpoch; - } - break; - case TRecordType.Alert: - AlertRecord alertRecord; - try - { - if ((_Cipher == null) || (!_EncyptedServerEpoch.HasValue)) - { - alertRecord = AlertRecord.Deserialise(record.Fragment); - } - else - { - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - byte[] data = _Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Alert, record.Fragment, 0, record.Fragment.Length); - alertRecord = AlertRecord.Deserialise(data); - } - } - catch - { - alertRecord = new AlertRecord(); - alertRecord.AlertLevel = TAlertLevel.Fatal; - } - if (alertRecord.AlertLevel == TAlertLevel.Fatal) - { - _Connected.Set(); - //Terminate - } - else if ((alertRecord.AlertLevel == TAlertLevel.Warning) || (alertRecord.AlertDescription == TAlertDescription.CloseNotify)) - { - if (alertRecord.AlertDescription == TAlertDescription.CloseNotify) - { - SendAlert(TAlertLevel.Warning, TAlertDescription.CloseNotify); - _Connected.Set(); - } - //_Sessions.Remove(session, address); - } - break; - case TRecordType.Handshake: - ProcessHandshake(record); - _ServerSequenceNumber = record.SequenceNumber + 1; - break; - case TRecordType.ApplicationData: - if (_Cipher != null) - { - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - byte[] data = _Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.ApplicationData, record.Fragment, 0, record.Fragment.Length); - if (DataReceived != null) - { - DataReceived(record.RemoteEndPoint, data); - } - } - _ServerSequenceNumber = record.SequenceNumber + 1; - break; - default: - break; - } - } -#if DEBUG - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); -#else - catch - { -#endif - } - } - - private void ProcessRecords() - { - while (!_Terminate) - { - _TriggerProcessRecords.Reset(); - DTLSRecord record = _Records.PeekRecord(); - while (record != null) - { - if (_ServerEpoch.HasValue) - { - if ((_ServerSequenceNumber == record.SequenceNumber) && (_ServerEpoch == record.Epoch)) - { - _Records.RemoveRecord(); - ProcessRecord(record); - record = _Records.PeekRecord(); - } - else - { - record = null; - } - } - else - { - _Records.RemoveRecord(); - ProcessRecord(record); - record = _Records.PeekRecord(); - } - } - if (!_Terminate) - _TriggerProcessRecords.WaitOne(); - } - } - - - private void ReceiveCallback(object sender, SocketAsyncEventArgs e) - { - if (e.BytesTransferred == 0) - { - - } - else - { - int count = e.BytesTransferred; - byte[] data = new byte[count]; - Buffer.BlockCopy(e.Buffer, 0, data, 0, count); - MemoryStream stream = new MemoryStream(data); - while (stream.Position < stream.Length) - { - DTLSRecord record = DTLSRecord.Deserialise(stream); - if (record != null) - { - record.RemoteEndPoint = e.RemoteEndPoint; - _Records.Add(record); - _TriggerProcessRecords.Set(); - } - } - Socket socket = sender as Socket; - if (socket != null) - { - System.Net.EndPoint remoteEndPoint; - if (socket.AddressFamily == AddressFamily.InterNetwork) - remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - else - remoteEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0); - e.RemoteEndPoint = remoteEndPoint; - e.SetBuffer(0, 4096); - socket.ReceiveFromAsync(e); - } - } - } - - private Socket SetupSocket(AddressFamily addressFamily) - { - Socket result = new Socket(addressFamily, SocketType.Dgram, ProtocolType.Udp); - if (addressFamily == AddressFamily.InterNetworkV6) - { - result.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, true); - } - if (Environment.OSVersion.Platform != PlatformID.Unix) - { - // do not throw SocketError.ConnectionReset by ignoring ICMP Port Unreachable - const Int32 SIO_UDP_CONNRESET = -1744830452; - result.IOControl(SIO_UDP_CONNRESET, new Byte[] { 0 }, null); - } - return result; - } - - - public void Send(byte[] data) - { - try - { - DTLSRecord record = new DTLSRecord(); - record.RecordType = TRecordType.ApplicationData; - record.Epoch = _Epoch; - record.SequenceNumber = NextSequenceNumber(); - if (_Version != null) - record.Version = _Version; - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - record.Fragment = _Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.ApplicationData, data, 0, data.Length); - int responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; - byte[] response = new byte[responseSize]; - using (MemoryStream stream = new MemoryStream(response)) - { - record.Serialise(stream); - } - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs() - { - RemoteEndPoint = _ServerEndPoint - }; - parameters.SetBuffer(response, 0, responseSize); - if (_Socket != null) - _Socket.SendToAsync(parameters); - } -#if DEBUG - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); -#else - catch - { -#endif - - } - } - - private void SendAlert(TAlertLevel alertLevel, TAlertDescription alertDescription) - { - DTLSRecord record = new DTLSRecord(); - record.RecordType = TRecordType.Alert; - record.Epoch = _Epoch; - record.SequenceNumber = NextSequenceNumber(); - if (_Version != null) - record.Version = _Version; - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - - byte[] data = new byte[2]; - data[0] = (byte)alertLevel; - data[1] = (byte)alertDescription; - if (_Cipher == null) - record.Fragment = data; - else - record.Fragment = _Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.ApplicationData, data, 0, data.Length); - int responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; - byte[] response = new byte[responseSize]; - using (MemoryStream stream = new MemoryStream(response)) - { - record.Serialise(stream); - } - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs() - { - RemoteEndPoint = _ServerEndPoint - }; - parameters.SetBuffer(response, 0, responseSize); - _Socket.SendToAsync(parameters); - } - - private void SendChangeCipherSpec() - { - int size = 1; - int responseSize = DTLSRecord.RECORD_OVERHEAD + size; - byte[] response = new byte[responseSize]; - DTLSRecord record = new DTLSRecord(); - record.RecordType = TRecordType.ChangeCipherSpec; - record.Epoch = _Epoch; - record.SequenceNumber = NextSequenceNumber(); - record.Fragment = new byte[size]; - record.Fragment[0] = 1; - if (_Version != null) - record.Version = _Version; - using (MemoryStream stream = new MemoryStream(response)) - { - record.Serialise(stream); - } - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs() - { - RemoteEndPoint = _ServerEndPoint - }; - parameters.SetBuffer(response, 0, responseSize); - _Socket.SendToAsync(parameters); - ChangeEpoch(); - } - - private void SendHello(byte[] cookie) - { - ClientHello clientHello = new ClientHello(); - clientHello.ClientVersion = SupportedVersion; - clientHello.Random = _HandshakeInfo.ClientRandom; - clientHello.Cookie = cookie; - ushort[] cipherSuites = new ushort[_SupportedCipherSuites.Count]; - int index = 0; - foreach (TCipherSuite item in _SupportedCipherSuites) - { - cipherSuites[index] = (ushort)item; - index++; - } - clientHello.CipherSuites = cipherSuites; - clientHello.CompressionMethods = new byte[1]; - clientHello.CompressionMethods[0] = 0; - clientHello.Extensions = new Extensions(); - - clientHello.Extensions.Add(new Extension() { ExtensionType = TExtensionType.EncryptThenMAC}); - clientHello.Extensions.Add(new Extension() { ExtensionType = TExtensionType.ExtendedMasterSecret }); - - EllipticCurvesExtension ellipticCurvesExtension = new EllipticCurvesExtension(); - for (int curve = 0; curve < (int)TEllipticCurve.secp521r1; curve++) - { - if (EllipticCurveFactory.SupportedCurve((TEllipticCurve)curve)) - { - ellipticCurvesExtension.SupportedCurves.Add((TEllipticCurve)curve); - - } - } - clientHello.Extensions.Add(new Extension(ellipticCurvesExtension)); - EllipticCurvePointFormatsExtension cllipticCurvePointFormatsExtension = new EllipticCurvePointFormatsExtension(); - cllipticCurvePointFormatsExtension.SupportedPointFormats.Add(TEllipticCurvePointFormat.Uncompressed); - clientHello.Extensions.Add(new Extension(cllipticCurvePointFormatsExtension)); - SignatureAlgorithmsExtension signatureAlgorithmsExtension = new SignatureAlgorithmsExtension(); - signatureAlgorithmsExtension.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash= THashAlgorithm.SHA256, Signature = TSignatureAlgorithm.ECDSA }); - clientHello.Extensions.Add(new Extension(signatureAlgorithmsExtension)); - _HandshakeInfo.InitaliseHandshakeHash(false); - SendHandshakeMessage(clientHello, false); - } - - private void SendHandshakeMessage(IHandshakeMessage handshakeMessage, bool encrypt) - { - int size = handshakeMessage.CalculateSize(_Version); - int maxPayloadSize = _MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD; - if (size > maxPayloadSize) - { - - } - else - { - - DTLSRecord record = new DTLSRecord(); - record.RecordType = TRecordType.Handshake; - record.Epoch = _Epoch; - record.SequenceNumber = NextSequenceNumber(); - record.Fragment = new byte[HandshakeRecord.RECORD_OVERHEAD + size]; - if (_Version != null) - record.Version = _Version; - HandshakeRecord handshakeRecord = new HandshakeRecord(); - handshakeRecord.MessageType = handshakeMessage.MessageType; - handshakeRecord.MessageSeq = _MessageSequence; - _MessageSequence++; - handshakeRecord.Length = (uint)size; - handshakeRecord.FragmentLength = (uint)size; - using (MemoryStream stream = new MemoryStream(record.Fragment)) - { - handshakeRecord.Serialise(stream); - handshakeMessage.Serialise(stream, _Version); - } - if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest) - { - _HandshakeInfo.UpdateHandshakeHash(record.Fragment); - } - int responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + size; - if ((_Cipher != null) && encrypt) - { - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - record.Fragment = _Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); - responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; - } - byte[] response = new byte[responseSize]; - using (MemoryStream stream = new MemoryStream(response)) - { - record.Serialise(stream); - } - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs() - { - RemoteEndPoint = _ServerEndPoint - }; - parameters.SetBuffer(response, 0, responseSize); - _Socket.SendToAsync(parameters); - } - - - } - - public void ConnectToServer(EndPoint serverEndPoint) - { - ConnectToServerAsync(serverEndPoint); - _Connected.WaitOne(); - } - - public void ConnectToServerAsync(EndPoint serverEndPoint) - { - _ServerEndPoint = serverEndPoint; - if (_SupportedCipherSuites.Count == 0) - { - _SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); //Test 1.2 - _SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 - _SupportedCipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8); //Test 1.2 - _SupportedCipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 - _SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 - } - _Socket = SetupSocket(_LocalEndPoint.AddressFamily); - if (_Socket != null) - { - _Socket.Bind(_LocalEndPoint); - _ProcessRecordsThread = new Thread(new ThreadStart(ProcessRecords)); - if (_ProcessRecordsThread.Name == null) - _ProcessRecordsThread.Name = "ProcessRecordsThread"; - _ProcessRecordsThread.IsBackground = true; - _ProcessRecordsThread.Start(); - StartReceive(_Socket); - SendHello(null); - } - - } - - - public void LoadCertificateFromPem(string filename) - { - using (FileStream stream = File.OpenRead(filename)) - { - LoadCertificateFromPem(stream); - } - } - - public void LoadCertificateFromPem(Stream stream) - { - List chain = new List(); - PemReader reader = new PemReader(new StreamReader(stream)); - PemObject pem = reader.ReadPemObject(); - - while (pem != null) - { - if (pem.Type.EndsWith("CERTIFICATE")) - { - chain.Add(pem.Content); - } - else if (pem.Type.EndsWith("PRIVATE KEY")) - { - _PrivateKey = Certificates.GetPrivateKeyFromPEM(pem); - } - pem = reader.ReadPemObject(); - } - _Certificate = new Certificate(); - _Certificate.CertChain = chain; - _Certificate.CertificateType = TCertificateType.X509; - } - - private void StartReceive(Socket socket) - { - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs(); - if (socket.AddressFamily == AddressFamily.InterNetwork) - parameters.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - else - parameters.RemoteEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0); - parameters.Completed += new EventHandler(ReceiveCallback); - parameters.SetBuffer(new byte[4096], 0, 4096); - socket.ReceiveFromAsync(parameters); - } - - public void SetVersion(Version version) - { - _Version = version; - } - - public void Stop() - { - if (_Socket != null) - { - _Terminate = true; - _TriggerProcessRecords.Set(); - SendAlert(TAlertLevel.Fatal, TAlertDescription.CloseNotify); - Thread.Sleep(100); - _Socket.Dispose(); - _Socket = null; - } - } - - } -} diff --git a/src/DTLS.Net/DTLS.Net.xproj b/src/DTLS.Net/DTLS.Net.xproj deleted file mode 100644 index 5f1e2b7..0000000 --- a/src/DTLS.Net/DTLS.Net.xproj +++ /dev/null @@ -1,26 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - 6d15ed53-d821-4909-8318-859d1f98f1da - DTLS - ..\..\artifacts\obj\$(MSBuildProjectName) - .\bin\ - - - 2.0 - - - True - - - - - - - - \ No newline at end of file diff --git a/src/DTLS.Net/DTLSContext.cs b/src/DTLS.Net/DTLSContext.cs deleted file mode 100644 index 4d673e2..0000000 --- a/src/DTLS.Net/DTLSContext.cs +++ /dev/null @@ -1,138 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Org.BouncyCastle.Crypto.Tls; -using Org.BouncyCastle.Crypto.Prng; -using Org.BouncyCastle.Utilities; - -namespace DTLS -{ - internal class DTLSContext : TlsContext - { - private class DTLSSecurityParameters : SecurityParameters - { - private HandshakeInfo _HandshakeInfo; - private byte[] _ClientRandom; - private byte[] _ServerRandom; - private int _PrfAlgorithm; - - public override int CipherSuite { get { return (int)_HandshakeInfo.CipherSuite; } } - public override byte[] ClientRandom { get { return _ClientRandom; } } - public override byte[] MasterSecret { get { return _HandshakeInfo.MasterSecret; } } - public override int PrfAlgorithm { get { return _PrfAlgorithm; } } - public override byte[] ServerRandom { get { return _ServerRandom; } } - - public DTLSSecurityParameters(Version version, HandshakeInfo handshakeInfo) - { - _HandshakeInfo = handshakeInfo; - if (handshakeInfo != null) - { - _ClientRandom = handshakeInfo.ClientRandom.Serialise(); - _ServerRandom = handshakeInfo.ServerRandom.Serialise(); - } - TPseudorandomFunction prf = CipherSuites.GetPseudorandomFunction(version, handshakeInfo.CipherSuite); - switch (prf) - { - case TPseudorandomFunction.NotSet: - break; - case TPseudorandomFunction.Legacy: - _PrfAlgorithm = Org.BouncyCastle.Crypto.Tls.PrfAlgorithm.tls_prf_legacy; - break; - case TPseudorandomFunction.SHA256: - _PrfAlgorithm = Org.BouncyCastle.Crypto.Tls.PrfAlgorithm.tls_prf_sha256; - break; - case TPseudorandomFunction.SHA384: - _PrfAlgorithm = Org.BouncyCastle.Crypto.Tls.PrfAlgorithm.tls_prf_sha384; - break; - default: - break; - } - } - } - - public ProtocolVersion ClientVersion { get; private set; } - - public byte[] ExportKeyingMaterial(string asciiLabel, byte[] context_value, int length) - { - throw new NotImplementedException(); - } - - public bool IsServer { get; private set; } - - public Org.BouncyCastle.Crypto.Prng.IRandomGenerator NonceRandomGenerator { get; private set; } - - public TlsSession ResumableSession - { - get { throw new NotImplementedException(); } - } - - public Org.BouncyCastle.Security.SecureRandom SecureRandom - { - get; - set; - } - - public SecurityParameters SecurityParameters { get; private set; } - - public ProtocolVersion ServerVersion { get; private set; } - - public object UserObject - { - get - { - throw new NotImplementedException(); - } - set - { - throw new NotImplementedException(); - } - } - - public DTLSContext() - { - - } - - public DTLSContext(bool client, Version version, HandshakeInfo handshakeInfo) - { - IsServer = !client; - if (version == DTLSRecord.Version1_2) - { - ClientVersion = ProtocolVersion.DTLSv12; - ServerVersion = ProtocolVersion.DTLSv12; - } - else - { - ClientVersion = ProtocolVersion.DTLSv10; - ServerVersion = ProtocolVersion.DTLSv10; - } - SecurityParameters = new DTLSSecurityParameters(version, handshakeInfo); - NonceRandomGenerator = new DigestRandomGenerator(TlsUtilities.CreateHash(HashAlgorithm.sha256)); - NonceRandomGenerator.AddSeedMaterial(Times.NanoTime()); - - } - } -} diff --git a/src/DTLS.Net/EllipticCurves/EllipticCurveFactory.cs b/src/DTLS.Net/EllipticCurves/EllipticCurveFactory.cs deleted file mode 100644 index ff88bce..0000000 --- a/src/DTLS.Net/EllipticCurves/EllipticCurveFactory.cs +++ /dev/null @@ -1,243 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Numerics; -using Org.BouncyCastle.Asn1.Sec; - -namespace DTLS -{ - internal class EllipticCurveFactory - { - private static EllipticCurve _secp192k1; - private static EllipticCurve _secp192r1; - private static EllipticCurve _secp224k1; - private static EllipticCurve _secp224r1; - private static EllipticCurve _secp256k1; - private static EllipticCurve _secp256r1; - private static EllipticCurve _secp384r1; - private static EllipticCurve _secp521r1; - - private static Dictionary _SupportedCurves = new Dictionary(); - private static Dictionary _CurveParameters = new Dictionary(); - - - static EllipticCurveFactory() - { - BigInteger baseX; - BigInteger baseY; - BigInteger a; - BigInteger b; - BigInteger p; - BigInteger n; - BigInteger h; - - - baseX = new BigInteger(new byte[] { 0x7D, 0x6C, 0xE0, 0xEA, 0xB1, 0xD1, 0xA5, 0x1D, 0x34, 0xF4, 0xB7, 0x80, 0x02, 0x7D, 0xB0, 0x26, 0xAE, 0xE9, 0x57, 0xC0, 0x0E, 0xF1, 0x4F, 0xDB }); - baseY = new BigInteger(new byte[] { 0x9D, 0x2F, 0x5E, 0xD9, 0x88, 0xAA, 0x82, 0x40, 0x34, 0x86, 0xBE, 0x15, 0xD0, 0x63, 0x41, 0x84, 0xA7, 0x28, 0x56, 0x9C, 0x6D, 0x2F, 0x2F, 0x9B }); - a = new BigInteger(0); - b = new BigInteger(3); - p = new BigInteger(new byte[] { 0x37, 0xEE, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - n = new BigInteger(new byte[] { 0x8D, 0xFD, 0xDE, 0x74, 0x6A, 0x46, 0x69, 0x0F, 0x17, 0xFC, 0xF2, 0x26, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - h = new BigInteger(1); - _secp192k1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); - _SupportedCurves.Add(TEllipticCurve.secp192k1, _secp192k1); - AddCurveParameters(TEllipticCurve.secp192k1, SecObjectIdentifiers.SecP192k1); - - baseX = new BigInteger(new byte[] { 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4, 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C, 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18 }); - baseY = new BigInteger(new byte[] { 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73, 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63, 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07 }); - a = new BigInteger(new byte[] { 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - b = new BigInteger(new byte[] { 0xB1, 0xB9, 0x46, 0xC1, 0xEC, 0xDE, 0xB8, 0xFE, 0x49, 0x30, 0x24, 0x72, 0xAB, 0xE9, 0xA7, 0x0F, 0xE7, 0x80, 0x9C, 0xE5, 0x19, 0x05, 0x21, 0x64 }); - p = new BigInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - n = new BigInteger(new byte[] { 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14, 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - h = new BigInteger(1); - _secp192r1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); - _SupportedCurves.Add(TEllipticCurve.secp192r1, _secp192r1); - AddCurveParameters(TEllipticCurve.secp192r1, SecObjectIdentifiers.SecP192r1); - - - baseX = new BigInteger(new byte[] { 0x5C, 0xA4, 0xB7, 0xB6, 0x0E, 0x65, 0x7E, 0x0F, 0xA9, 0x75, 0x70, 0xE4, 0xE9, 0x67, 0xA4, 0x69, 0xA1, 0x28, 0xFC, 0x30, 0xDF, 0x99, 0xF0, 0x4D, 0x33, 0x5B, 0x45, 0xA1 }); - baseY = new BigInteger(new byte[] { 0xA5, 0x61, 0x6D, 0x55, 0xDB, 0x4B, 0xCA, 0xE2, 0x59, 0xBD, 0xB0, 0xC0, 0xF7, 0x19, 0xE3, 0xF7, 0xD6, 0xFB, 0xCA, 0x82, 0x42, 0x34, 0xBA, 0x7F, 0xED, 0x9F, 0x08, 0x7E }); - a = new BigInteger(0); - b = new BigInteger(5); - p = new BigInteger(new byte[] { 0x6D, 0xE5, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - n = new BigInteger(new byte[] { 0xF7, 0xB1, 0x9F, 0x76, 0x71, 0xA9, 0xF0, 0xCA, 0x84, 0x61, 0xEC, 0xD2, 0xE8, 0xDC, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }); - h = new BigInteger(1); - _secp224k1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); - _SupportedCurves.Add(TEllipticCurve.secp224k1, _secp224k1); - AddCurveParameters(TEllipticCurve.secp224k1, SecObjectIdentifiers.SecP224k1); - - - baseX = new BigInteger(new byte[] { 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34, 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A, 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B, 0xBD, 0x0C, 0x0E, 0xB7 }); - baseY = new BigInteger(new byte[] { 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44, 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD, 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5, 0x88, 0x63, 0x37, 0xBD }); - a = new BigInteger(new byte[] { 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - b = new BigInteger(new byte[] { 0xB4, 0xFF, 0x55, 0x23, 0x43, 0x39, 0x0B, 0x27, 0xBA, 0xD8, 0xBF, 0xD7, 0xB7, 0xB0, 0x44, 0x50, 0x56, 0x32, 0x41, 0xF5, 0xAB, 0xB3, 0x04, 0x0C, 0x85, 0x0A, 0x05, 0xB4 }); - p = new BigInteger(new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - n = new BigInteger(new byte[] { 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13, 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - h = new BigInteger(1); - _secp224r1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); - _SupportedCurves.Add(TEllipticCurve.secp224r1, _secp224r1); - AddCurveParameters(TEllipticCurve.secp224r1, SecObjectIdentifiers.SecP224r1); - - baseX = new BigInteger(new byte[] { 0x98, 0x17, 0xF8, 0x16, 0x5B, 0x81, 0xF2, 0x59, 0xD9, 0x28, 0xCE, 0x2D, 0xDB, 0xFC, 0x9B, 0x02, 0x07, 0x0B, 0x87, 0xCE, 0x95, 0x62, 0xA0, 0x55, 0xAC, 0xBB, 0xDC, 0xF9, 0x7E, 0x66, 0xBE, 0x79 }); - baseY = new BigInteger(new byte[] { 0xB8, 0xD4, 0x10, 0xFB, 0x8F, 0xD0, 0x47, 0x9C, 0x19, 0x54, 0x85, 0xA6, 0x48, 0xB4, 0x17, 0xFD, 0xA8, 0x08, 0x11, 0x0E, 0xFC, 0xFB, 0xA4, 0x5D, 0x65, 0xC4, 0xA3, 0x26, 0x77, 0xDA, 0x3A, 0x48 }); - a = new BigInteger(0); - b = new BigInteger(7); - p = new BigInteger(new byte[] { 0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - n = new BigInteger(new byte[] { 0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - h = new BigInteger(1); - _secp256k1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); - _SupportedCurves.Add(TEllipticCurve.secp256k1, _secp256k1); - AddCurveParameters(TEllipticCurve.secp256k1, SecObjectIdentifiers.SecP256k1); - - baseX = new BigInteger(new byte[] { 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4, 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77, 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8, 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B }); - baseY = new BigInteger(new byte[] { 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB, 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B, 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E, 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F }); - a = new BigInteger(new byte[] { 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }); - b = new BigInteger(new byte[] { 0x4B, 0x60, 0xD2, 0x27, 0x3E, 0x3C, 0xCE, 0x3B, 0xF6, 0xB0, 0x53, 0xCC, 0xB0, 0x06, 0x1D, 0x65, 0xBC, 0x86, 0x98, 0x76, 0x55, 0xBD, 0xEB, 0xB3, 0xE7, 0x93, 0x3A, 0xAA, 0xD8, 0x35, 0xC6, 0x5A }); - p = new BigInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }); - n = new BigInteger(new byte[] { 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF }); - h = new BigInteger(1); - _secp256r1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); - _SupportedCurves.Add(TEllipticCurve.secp256r1, _secp256r1); - AddCurveParameters(TEllipticCurve.secp256r1, SecObjectIdentifiers.SecP256r1); - - baseX = new BigInteger(new byte[] { 0xB7, 0x0A, 0x76, 0x72, 0x38, 0x5E, 0x54, 0x3A, 0x6C, 0x29, 0x55, 0xBF, 0x5D, 0xF2, 0x02, 0x55, 0x38, 0x2A, 0x54, 0x82, 0xE0, 0x41, 0xF7, 0x59, 0x98, 0x9B, 0xA7, 0x8B, 0x62, 0x3B, 0x1D, 0x6E, 0x74, 0xAD, 0x20, 0xF3, 0x1E, 0xC7, 0xB1, 0x8E, 0x37, 0x05, 0x8B, 0xBE, 0x22, 0xCA, 0x87, 0xAA }); - baseY = new BigInteger(new byte[] { 0x5F, 0x0E, 0xEA, 0x90, 0x7C, 0x1D, 0x43, 0x7A, 0x9D, 0x81, 0x7E, 0x1D, 0xCE, 0xB1, 0x60, 0x0A, 0xC0, 0xB8, 0xF0, 0xB5, 0x13, 0x31, 0xDA, 0xE9, 0x7C, 0x14, 0x9A, 0x28, 0xBD, 0x1D, 0xF4, 0xF8, 0x29, 0xDC, 0x92, 0x92, 0xBF, 0x98, 0x9E, 0x5D, 0x6F, 0x2C, 0x26, 0x96, 0x4A, 0xDE, 0x17, 0x36 }); - a = new BigInteger(new byte[] { 0xFC, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - b = new BigInteger(new byte[] { 0xEF, 0x2A, 0xEC, 0xD3, 0xED, 0xC8, 0x85, 0x2A, 0x9D, 0xD1, 0x2E, 0x8A, 0x8D, 0x39, 0x56, 0xC6, 0x5A, 0x87, 0x13, 0x50, 0x8F, 0x08, 0x14, 0x03, 0x12, 0x41, 0x81, 0xFE, 0x6E, 0x9C, 0x1D, 0x18, 0x19, 0x2D, 0xF8, 0xE3, 0x6B, 0x05, 0x8E, 0x98, 0xE4, 0xE7, 0x3E, 0xE2, 0xA7, 0x2F, 0x31, 0xB3 }); - p = new BigInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - n = new BigInteger(new byte[] { 0x73, 0x29, 0xC5, 0xCC, 0x6A, 0x19, 0xEC, 0xEC, 0x7A, 0xA7, 0xB0, 0x48, 0xB2, 0x0D, 0x1A, 0x58, 0xDF, 0x2D, 0x37, 0xF4, 0x81, 0x4D, 0x63, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }); - h = new BigInteger(1); - _secp384r1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); - AddCurveParameters(TEllipticCurve.secp384r1, SecObjectIdentifiers.SecP384r1); - _SupportedCurves.Add(TEllipticCurve.secp384r1, _secp384r1); - - baseX = new BigInteger(new byte[] { 0x66, 0xBD, 0xE5, 0xC2, 0x31, 0x7E, 0x7E, 0xF9, 0x9B, 0x42, 0x6A, 0x85, 0xC1, 0xB3, 0x48, 0x33, 0xDE, 0xA8, 0xFF, 0xA2, 0x27, 0xC1, 0x1D, 0xFE, 0x28, 0x59, 0xE7, 0xEF, 0x77, 0x5E, 0x4B, 0xA1, 0xBA, 0x3D, 0x4D, 0x6B, 0x60, 0xAF, 0x28, 0xF8, 0x21, 0xB5, 0x3F, 0x05, 0x39, 0x81, 0x64, 0x9C, 0x42, 0xB4, 0x95, 0x23, 0x66, 0xCB, 0x3E, 0x9E, 0xCD, 0xE9, 0x04, 0x04, 0xB7, 0x06, 0x8E, 0x85, 0xC6, 0x00 }); - baseY = new BigInteger(new byte[] { 0x50, 0x66, 0xD1, 0x9F, 0x76, 0x94, 0xBE, 0x88, 0x40, 0xC2, 0x72, 0xA2, 0x86, 0x70, 0x3C, 0x35, 0x61, 0x07, 0xAD, 0x3F, 0x01, 0xB9, 0x50, 0xC5, 0x40, 0x26, 0xF4, 0x5E, 0x99, 0x72, 0xEE, 0x97, 0x2C, 0x66, 0x3E, 0x27, 0x17, 0xBD, 0xAF, 0x17, 0x68, 0x44, 0x9B, 0x57, 0x49, 0x44, 0xF5, 0x98, 0xD9, 0x1B, 0x7D, 0x2C, 0xB4, 0x5F, 0x8A, 0x5C, 0x04, 0xC0, 0x3B, 0x9A, 0x78, 0x6A, 0x29, 0x39, 0x18, 0x01 }); - a = new BigInteger(new byte[] { 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }); - b = new BigInteger(new byte[] { 0x00, 0x3F, 0x50, 0x6B, 0xD4, 0x1F, 0x45, 0xEF, 0xF1, 0x34, 0x2C, 0x3D, 0x88, 0xDF, 0x73, 0x35, 0x07, 0xBF, 0xB1, 0x3B, 0xBD, 0xC0, 0x52, 0x16, 0x7B, 0x93, 0x7E, 0xEC, 0x51, 0x39, 0x19, 0x56, 0xE1, 0x09, 0xF1, 0x8E, 0x91, 0x89, 0xB4, 0xB8, 0xF3, 0x15, 0xB3, 0x99, 0x5B, 0x72, 0xDA, 0xA2, 0xEE, 0x40, 0x85, 0xB6, 0xA0, 0x21, 0x9A, 0x92, 0x1F, 0x9A, 0x1C, 0x8E, 0x61, 0xB9, 0x3E, 0x95, 0x51, 0x00 }); - p = new BigInteger(new byte[] { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }); - n = new BigInteger(new byte[] { 0x09, 0x64, 0x38, 0x91, 0x1E, 0xB7, 0x6F, 0xBB, 0xAE, 0x47, 0x9C, 0x89, 0xB8, 0xC9, 0xB5, 0x3B, 0xD0, 0xA5, 0x09, 0xF7, 0x48, 0x01, 0xCC, 0x7F, 0x6B, 0x96, 0x2F, 0xBF, 0x83, 0x87, 0x86, 0x51, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01 }); - h = new BigInteger(1); - _secp521r1 = new PrimeFiniteFieldCurve(p, a, b, n, h, new EllipticCurvePoint(baseX, baseY)); - AddCurveParameters(TEllipticCurve.secp521r1, SecObjectIdentifiers.SecP521r1); - _SupportedCurves.Add(TEllipticCurve.secp521r1, _secp521r1); - - } - - private static void AddCurveParameters(TEllipticCurve curve, Org.BouncyCastle.Asn1.DerObjectIdentifier id) - { - Org.BouncyCastle.Asn1.X9.X9ECParameters ecP = Org.BouncyCastle.Crypto.EC.CustomNamedCurves.GetByOid(id); - _CurveParameters.Add(curve, new Org.BouncyCastle.Crypto.Parameters.ECDomainParameters(ecP.Curve, ecP.G, ecP.N, ecP.H, ecP.GetSeed())); - } - - - public static EllipticCurve GetEllipticCurve(TEllipticCurve curve) - { - EllipticCurve result = null; - switch (curve) - { - case TEllipticCurve.sect163k1: - break; - case TEllipticCurve.sect163r1: - break; - case TEllipticCurve.sect163r2: - break; - case TEllipticCurve.sect193r1: - break; - case TEllipticCurve.sect193r2: - break; - case TEllipticCurve.sect233k1: - break; - case TEllipticCurve.sect233r1: - break; - case TEllipticCurve.sect239k1: - break; - case TEllipticCurve.sect283k1: - break; - case TEllipticCurve.sect283r1: - break; - case TEllipticCurve.sect409k1: - break; - case TEllipticCurve.sect409r1: - break; - case TEllipticCurve.sect571k1: - break; - case TEllipticCurve.sect571r1: - break; - case TEllipticCurve.secp160k1: - break; - case TEllipticCurve.secp160r1: - break; - case TEllipticCurve.secp160r2: - break; - case TEllipticCurve.secp192k1: - result = _secp192k1; - break; - case TEllipticCurve.secp192r1: - result = _secp192r1; - break; - case TEllipticCurve.secp224k1: - result = _secp224k1; - break; - case TEllipticCurve.secp224r1: - result = _secp224r1; - break; - case TEllipticCurve.secp256k1: - result = _secp256k1; - break; - case TEllipticCurve.secp256r1: - result = _secp256r1; - break; - case TEllipticCurve.secp384r1: - result = _secp384r1; - break; - case TEllipticCurve.secp521r1: - result = _secp521r1; - break; - case TEllipticCurve.arbitrary_explicit_prime_curves: - break; - case TEllipticCurve.arbitrary_explicit_char2_curves: - break; - default: - break; - } - return result; - } - - public static bool SupportedCurve(TEllipticCurve curve) - { - return _SupportedCurves.ContainsKey(curve); - } - - - internal static Org.BouncyCastle.Crypto.Parameters.ECDomainParameters GetEllipticCurveParameters(TEllipticCurve curve) - { - Org.BouncyCastle.Crypto.Parameters.ECDomainParameters result; - _CurveParameters.TryGetValue(curve, out result); - return result; - } - } -} diff --git a/src/DTLS.Net/HandshakeMessages/Certificate.cs b/src/DTLS.Net/HandshakeMessages/Certificate.cs deleted file mode 100644 index 5c724ba..0000000 --- a/src/DTLS.Net/HandshakeMessages/Certificate.cs +++ /dev/null @@ -1,144 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using System.Net; - -using Org.BouncyCastle.Asn1.X509; - -namespace DTLS -{ - - //opaque ASN.1Cert<1..2^24-1>; - //struct { - // ASN.1Cert certificate_list<0..2^24-1>; - //} Certificate; - - internal class Certificate : IHandshakeMessage - { - - private List _CertChain; - private TCertificateType _CertificateType; - - public List CertChain - { - get { return _CertChain; } - set { _CertChain = value; } - } - - public TCertificateType CertificateType - { - get { return _CertificateType; } - set { _CertificateType = value; } - } - - public THandshakeType MessageType { get { return THandshakeType.Certificate; } } - - public int CalculateSize(Version version) - { - int result = 3; // overall Length - switch (_CertificateType) - { - case TCertificateType.X509: - if (_CertChain != null) - { - foreach (byte[] item in _CertChain) - { - result += (3 + item.Length); - } - } - break; - case TCertificateType.OpenPGP: - break; - case TCertificateType.RawPublicKey: - break; - case TCertificateType.Unknown: - break; - default: - break; - } - return result; - } - - public static Certificate Deserialise(Stream stream, TCertificateType certificateType) - { - Certificate result = new Certificate(); - int certificateChainLength = NetworkByteOrderConverter.ToInt24(stream); - if (certificateChainLength > 0) - { - result._CertificateType = certificateType; - if (certificateType == TCertificateType.X509) - { - result._CertChain = new List(); - while (certificateChainLength > 0) - { - int certificateLength = NetworkByteOrderConverter.ToInt24(stream); - byte[] certificate = new byte[certificateLength]; - stream.Read(certificate, 0, certificateLength); - result._CertChain.Add(certificate); - certificateChainLength = certificateChainLength - certificateLength - 3; - } - } - else - { - - } - } - return result; - } - - public void Serialise(Stream stream, Version version) - { - int totalLength = CalculateSize(version); - NetworkByteOrderConverter.WriteInt24(stream, totalLength-3); - switch (_CertificateType) - { - case TCertificateType.X509: - if (_CertChain != null) - { - foreach (byte[] item in _CertChain) - { - NetworkByteOrderConverter.WriteInt24(stream, item.Length); - stream.Write(item, 0, item.Length); - } - } - break; - case TCertificateType.OpenPGP: - break; - case TCertificateType.RawPublicKey: - break; - case TCertificateType.Unknown: - break; - default: - break; - } - } - - - - - } -} diff --git a/src/DTLS.Net/HandshakeMessages/ClientHello.cs b/src/DTLS.Net/HandshakeMessages/ClientHello.cs deleted file mode 100644 index 6dba7ce..0000000 --- a/src/DTLS.Net/HandshakeMessages/ClientHello.cs +++ /dev/null @@ -1,238 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using System.Net; - -namespace DTLS -{ - - //opaque SessionID<0..32>; - - // uint8 CipherSuite[2]; /* Cryptographic suite selector */ - - // enum { null(0), (255) } CompressionMethod; - - - // struct { - // ExtensionType extension_type; - // opaque extension_data<0..2^16-1>; - //} Extension; - - //enum { - // signature_algorithms(13), (65535) - //} ExtensionType; - - // struct { - //ProtocolVersion client_version; - //Random random; - //SessionID session_id; - //opaque cookie<0..2^8-1>; // New field - //CipherSuite cipher_suites<2..2^16-1>; - //CompressionMethod compression_methods<1..2^8-1>; - // select (extensions_present) { - // case false: - // struct {}; - // case true: - // Extension extensions<0..2^16-1>; - // }; - //} ClientHello; - internal class ClientHello: IHandshakeMessage - { - private Version _ClientVersion; - private RandomData _Random; - private byte[] _SessionID; - private byte[] _Cookie; - private ushort[] _CipherSuites; - private byte[] _CompressionMethods; - private Extensions _Extensions; - - public THandshakeType MessageType { get { return THandshakeType.ClientHello; } } - - public Version ClientVersion - { - get { return _ClientVersion; } - set { _ClientVersion = value; } - } - - public RandomData Random - { - get { return _Random; } - set { _Random = value; } - } - - - public byte[] SessionID - { - get { return _SessionID; } - set { _SessionID = value; } - } - - - public byte[] Cookie - { - get { return _Cookie; } - set { _Cookie = value; } - } - - public ushort[] CipherSuites - { - get { return _CipherSuites; } - set { _CipherSuites = value; } - } - - public byte[] CompressionMethods - { - get { return _CompressionMethods; } - set { _CompressionMethods = value; } - } - - public Extensions Extensions - { - get { return _Extensions; } - set { _Extensions = value; } - } - - - public int CalculateSize(Version version) - { - int result = 39; // Version (2 bytes) + Random (32 bytes) + SessionIDLength (1 byte) + _CompressionMethodsLength (1 byte) - // + CookieLength (1 byte) + CipherSuitesLength (2 bytes) - if (_SessionID != null) - result += _SessionID.Length; - if (_Cookie != null) - result += Cookie.Length; - if (_CipherSuites != null) - result += (_CipherSuites.Length * 2); - if (_CompressionMethods != null) - result += _CompressionMethods.Length; - if (_Extensions == null) - result += 2; - else - result += _Extensions.CalculateSize(); - return result; - } - - public byte[] CalculateCookie(EndPoint remoteEndPoint, byte[] secret) - { - //Cookie = HMAC(Secret, Client-IP, Client-Parameters) - //(version, random, session_id, cipher_suites, compression_method) - byte[] result = new byte[32]; - SocketAddress socketAddress = remoteEndPoint.Serialize(); - int socketAddressSize = socketAddress.Size; - byte[] message = new byte[socketAddressSize + 34]; - for (int index = 0; index < socketAddressSize; index++) - { - message[0] = socketAddress[index]; - } - NetworkByteOrderConverter.WriteUInt32(message, socketAddressSize, _Random.UnixTime); - Buffer.BlockCopy(_Random.RandomBytes, 0, message, socketAddressSize + 4, 28); - System.Security.Cryptography.HMACSHA256 hmac = new System.Security.Cryptography.HMACSHA256(secret); - byte[] hash = hmac.ComputeHash(message); - Buffer.BlockCopy(hash, 0, result, 0, 32); - return result; - } - - public static ClientHello Deserialise(Stream stream) - { - ClientHello result = new ClientHello(); - result._ClientVersion = new Version(255 - stream.ReadByte(), 255 - stream.ReadByte()); - result._Random = RandomData.Deserialise(stream); - int length = stream.ReadByte(); - if (length > 0) - { - result._SessionID = new byte[length]; - stream.Read(result._SessionID, 0, length); - } - length = stream.ReadByte(); - if (length > 0) - { - result._Cookie = new byte[length]; - stream.Read(result._Cookie, 0, length); - } - ushort cipherSuitesLength = (ushort)(NetworkByteOrderConverter.ToUInt16(stream) / 2); - if (cipherSuitesLength > 0) - { - result._CipherSuites = new ushort[cipherSuitesLength]; - for (uint index = 0; index < cipherSuitesLength; index++) - { - result._CipherSuites[index] = NetworkByteOrderConverter.ToUInt16(stream); - } - } - length = stream.ReadByte(); - if (length > 0) - { - result._CompressionMethods = new byte[length]; - stream.Read(result._CompressionMethods, 0, length); - } - result._Extensions = Extensions.Deserialise(stream, true); - return result; - } - - public void Serialise(System.IO.Stream stream, Version version) - { - stream.WriteByte((byte)(255 - _ClientVersion.Major)); - stream.WriteByte((byte)(255 - _ClientVersion.Minor)); - _Random.Serialise(stream); - if (_SessionID == null) - { - stream.WriteByte(0); - } - else - { - stream.WriteByte((byte)_SessionID.Length); - stream.Write(_SessionID, 0, _SessionID.Length); - } - if (_Cookie == null) - { - stream.WriteByte(0); - } - else - { - stream.WriteByte((byte)_Cookie.Length); - stream.Write(_Cookie, 0, _Cookie.Length); - } - if (_CipherSuites.Length > 0) - { - NetworkByteOrderConverter.WriteUInt16(stream,(ushort)(_CipherSuites.Length * 2)); - for (uint index = 0; index < _CipherSuites.Length; index++) - { - NetworkByteOrderConverter.WriteUInt16(stream,_CipherSuites[index]); - } - } - stream.WriteByte((byte)_CompressionMethods.Length); - stream.Write(_CompressionMethods, 0, _CompressionMethods.Length); - if (_Extensions == null) - NetworkByteOrderConverter.WriteUInt16(stream, 0); - else - { - _Extensions.Serialise(stream); - } - - } - - } -} diff --git a/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEServerKeyExchange.cs b/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEServerKeyExchange.cs deleted file mode 100644 index a5242d4..0000000 --- a/src/DTLS.Net/HandshakeMessages/KeyExchange/EllipticCurves/ECDHEServerKeyExchange.cs +++ /dev/null @@ -1,336 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Org.BouncyCastle.Crypto; -using Org.BouncyCastle.Security; -using Org.BouncyCastle.Crypto.Digests; -using Org.BouncyCastle.Crypto.Signers; - -namespace DTLS -{ - // struct { - // opaque a <1..2^8-1>; - // opaque b <1..2^8-1>; - //} ECCurve; - - //enum { explicit_prime (1), explicit_char2 (2), - // named_curve (3), reserved(248..255) } ECCurveType; - // struct { - // opaque point <1..2^8-1>; - //} ECPoint; - //enum { ec_basis_trinomial, ec_basis_pentanomial } ECBasisType; -// struct { -// ECCurveType curve_type; -// select (curve_type) { -// case explicit_prime: -// opaque prime_p <1..2^8-1>; -// ECCurve curve; -// ECPoint base; -// opaque order <1..2^8-1>; -// opaque cofactor <1..2^8-1>; -// case explicit_char2: -// uint16 m; -// ECBasisType basis; -// select (basis) { -// case ec_trinomial: -// opaque k <1..2^8-1>; -// case ec_pentanomial: -// opaque k1 <1..2^8-1>; -// opaque k2 <1..2^8-1>; -// opaque k3 <1..2^8-1>; -// }; -// ECCurve curve; -// ECPoint base; -// opaque order <1..2^8-1>; -// opaque cofactor <1..2^8-1>; - - - -//Blake-Wilson, et al. Informational [Page 18] - -//RFC 4492 ECC Cipher Suites for TLS May 2006 - - -// case named_curve: -// NamedCurve namedcurve; -// }; -// } ECParameters; - - //struct { - // ECParameters curve_params; - // ECPoint public; - //} ServerECDHParams; - - - // enum { ec_diffie_hellman } KeyExchangeAlgorithm; - - //ec_diffie_hellman: Indicates the ServerKeyExchange message contains - // an ECDH public key. - - // select (KeyExchangeAlgorithm) { - // case ec_diffie_hellman: - // ServerECDHParams params; - // Signature signed_params; - // } ServerKeyExchange; - - - - // enum { ecdsa } SignatureAlgorithm; - - // select (SignatureAlgorithm) { - // case ecdsa: - // digitally-signed struct { - // opaque sha_hash[sha_size]; - // }; - // } Signature; - - - //ServerKeyExchange.signed_params.sha_hash - // SHA(ClientHello.random + ServerHello.random + - // ServerKeyExchange.params); - - - // struct { - // SignatureAndHashAlgorithm algorithm; - // opaque signature<0..2^16-1>; - //} DigitallySigned; - - internal class ECDHEServerKeyExchange : IHandshakeMessage - { - private TEllipticCurveType _EllipticCurveType; - private TEllipticCurve _EllipticCurve; - private byte[] _PublicKeyBytes; - - - private byte[] _ServerParams; - THashAlgorithm _HashAlgorithm; - TSignatureAlgorithm _SignatureAlgorithm; - private byte[] _Signature; - - public THandshakeType MessageType - { - get { return THandshakeType.ServerKeyExchange; } - } - - public TEllipticCurveType EllipticCurveType - { - get { return _EllipticCurveType; } - } - - public TEllipticCurve EllipticCurve - { - get { return _EllipticCurve; } - } - - public byte[] PublicKeyBytes - { - get { return _PublicKeyBytes; } - } - - public THashAlgorithm HashAlgorithm - { - get { return _HashAlgorithm; } - } - - public TSignatureAlgorithm SignatureAlgorithm - { - get { return _SignatureAlgorithm; } - } - - public byte[] Signature - { - get { return _Signature; } - } - - public ECDHEServerKeyExchange() - { - _EllipticCurveType = TEllipticCurveType.NamedCurve; - } - - public ECDHEServerKeyExchange(ECDHEKeyExchange keyExchange, THashAlgorithm hashAlgorithm, TSignatureAlgorithm signatureAlgorithm, AsymmetricKeyParameter serverPrivateKey) - { - _EllipticCurveType = TEllipticCurveType.NamedCurve; - _EllipticCurve = keyExchange.Curve; - _HashAlgorithm = hashAlgorithm; - _SignatureAlgorithm = signatureAlgorithm; - - System.IO.MemoryStream stream = new System.IO.MemoryStream(); - stream.WriteByte((byte)_EllipticCurveType); - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)_EllipticCurve); - byte[] pointEncoded = keyExchange.PublicKey.Q.GetEncoded(false); - stream.WriteByte((byte)pointEncoded.Length); - stream.Write(pointEncoded, 0, pointEncoded.Length); - _ServerParams = stream.ToArray(); - - - //IDigest hashMD5 = GetDigest(THashAlgorithm.MD5); - //IDigest hashSHA = GetDigest(THashAlgorithm.SHA1); - //int size = hashMD5.GetDigestSize(); - //byte[] hash = new byte[size + hashSHA.GetDigestSize()]; - //hashMD5.BlockUpdate(clientRandom.RandomBytes, 0, clientRandom.RandomBytes.Length); - //hashMD5.BlockUpdate(serverRandom.RandomBytes, 0, serverRandom.RandomBytes.Length); - //hashMD5.BlockUpdate(_ServerParams, 0, _ServerParams.Length); - //hashMD5.DoFinal(hash, 0); - //hashSHA.BlockUpdate(clientRandom.RandomBytes, 0, clientRandom.RandomBytes.Length); - //hashSHA.BlockUpdate(serverRandom.RandomBytes, 0, serverRandom.RandomBytes.Length); - //hashSHA.BlockUpdate(_ServerParams, 0, _ServerParams.Length); - //hashSHA.DoFinal(hash, size); - - //ISigner signer = GetSigner(signatureAlgorithm, THashAlgorithm.None, serverPrivateKey); - //signer.BlockUpdate(hash, 0, hash.Length); - //_Signature = signer.GenerateSignature(); - - ISigner signer = GetSigner(signatureAlgorithm, hashAlgorithm, serverPrivateKey); - byte[] clientRandomBytes = keyExchange.ClientRandom.Serialise(); - byte[] serverRandomBytes = keyExchange.ServerRandom.Serialise(); - signer.BlockUpdate(clientRandomBytes, 0, clientRandomBytes.Length); - signer.BlockUpdate(serverRandomBytes, 0, serverRandomBytes.Length); - signer.BlockUpdate(_ServerParams, 0, _ServerParams.Length); - _Signature = signer.GenerateSignature(); - - } - - - public int CalculateSize(Version version) - { - int result = 0; - if (_ServerParams != null) - { - result += _ServerParams.Length; - } - - if (_Signature != null) - { - if (version >= DTLSRecord.Version1_2) - result += 2; - result += 2; - result += _Signature.Length; - } - return result; - } - - public static ECDHEServerKeyExchange Deserialise(System.IO.Stream stream, Version version) - { - ECDHEServerKeyExchange result = new ECDHEServerKeyExchange(); - result._EllipticCurveType = (TEllipticCurveType)stream.ReadByte(); - result._EllipticCurve = (TEllipticCurve)NetworkByteOrderConverter.ToUInt16(stream); - int length = stream.ReadByte(); - if (length > 0) - { - result._PublicKeyBytes = new byte[length]; - stream.Read(result._PublicKeyBytes, 0, length); - } - if (version >= DTLSRecord.Version1_2) - { - result._HashAlgorithm = (THashAlgorithm)stream.ReadByte(); - result._SignatureAlgorithm = (TSignatureAlgorithm)stream.ReadByte(); - } - int signatureLength = NetworkByteOrderConverter.ToUInt16(stream); - if (signatureLength > 0) - { - result._Signature = new byte[signatureLength]; - stream.Read(result._Signature, 0, signatureLength); - } - return result; - } - - public void Serialise(System.IO.Stream stream, Version version) - { - if (_ServerParams != null) - { - stream.Write(_ServerParams, 0, _ServerParams.Length); - } - if (version >= DTLSRecord.Version1_2) - { - stream.WriteByte((byte)_HashAlgorithm); - stream.WriteByte((byte)_SignatureAlgorithm); - } - if (_Signature != null) - { - NetworkByteOrderConverter.WriteUInt16(stream, (ushort)_Signature.Length); - stream.Write(_Signature, 0, _Signature.Length); - } - } - - - - private IDigest GetDigest(THashAlgorithm hashAlgorithm) - { - IDigest result = null; - switch (hashAlgorithm) - { - case THashAlgorithm.None: - result = new NullDigest(); - break; - case THashAlgorithm.MD5: - result = new MD5Digest(); - break; - case THashAlgorithm.SHA1: - result = new Sha1Digest(); - break; - case THashAlgorithm.SHA224: - result = new Sha224Digest(); - break; - case THashAlgorithm.SHA256: - result = new Sha256Digest(); - break; - case THashAlgorithm.SHA384: - result = new Sha384Digest(); - break; - case THashAlgorithm.SHA512: - result = new Sha512Digest(); - break; - default: - break; - } - return result; - } - - - private ISigner GetSigner(TSignatureAlgorithm signatureAlgorithm, THashAlgorithm hashAlgorithm, AsymmetricKeyParameter serverPrivateKey) - { - ISigner result = null; - switch (signatureAlgorithm) - { - case TSignatureAlgorithm.Anonymous: - break; - case TSignatureAlgorithm.RSA: - break; - case TSignatureAlgorithm.DSA: - break; - case TSignatureAlgorithm.ECDSA: - result = new DsaDigestSigner(new ECDsaSigner(), GetDigest(hashAlgorithm)); - break; - default: - break; - } - result.Init(true, serverPrivateKey); - //result.Init(true, new ParametersWithRandom(serverPrivateKey, this.mContext.SecureRandom)); - return result; - } - - } -} diff --git a/src/DTLS.Net/HandshakeMessages/KeyExchange/ServerKeyExchange.cs b/src/DTLS.Net/HandshakeMessages/KeyExchange/ServerKeyExchange.cs deleted file mode 100644 index 236112e..0000000 --- a/src/DTLS.Net/HandshakeMessages/KeyExchange/ServerKeyExchange.cs +++ /dev/null @@ -1,124 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace DTLS -{ - - // enum { rsa, diffie_hellman } KeyExchangeAlgorithm; - - //struct { - // opaque rsa_modulus<1..2^16-1>; - // opaque rsa_exponent<1..2^16-1>; - //} ServerRSAParams; - - //rsa_modulus - // The modulus of the server's temporary RSA key. - - //rsa_exponent - // The public exponent of the server's temporary RSA key. - - // struct { - // opaque dh_p<1..2^16-1>; - // opaque dh_g<1..2^16-1>; - // opaque dh_Ys<1..2^16-1>; - //} ServerDHParams; /* Ephemeral DH parameters */ - - //dh_p - // The prime modulus used for the Diffie-Hellman operation. - - //dh_g - // The generator used for the Diffie-Hellman operation. - - //dh_Ys - // The server's Diffie-Hellman public value (g^X mod p). - - - // struct { - // select (KeyExchangeAlgorithm) { - // case diffie_hellman: - // ServerDHParams params; - // Signature signed_params; - // case rsa: - // ServerRSAParams params; - // Signature signed_params; - // }; - //} ServerKeyExchange; - - - - // struct { - // select (SignatureAlgorithm) { - // case anonymous: struct { }; - // case rsa: - // digitally-signed struct { - // opaque md5_hash[16]; - // opaque sha_hash[20]; - // }; - // case dsa: - // digitally-signed struct { - // opaque sha_hash[20]; - // }; - // }; - // }; - //} Signature; - - - - // enum { ecdsa } SignatureAlgorithm; - - // select (SignatureAlgorithm) { - // case ecdsa: - // digitally-signed struct { - // opaque sha_hash[sha_size]; - // }; - // } Signature; - - - //ServerKeyExchange.signed_params.sha_hash - // SHA(ClientHello.random + ServerHello.random + - // ServerKeyExchange.params); - - internal class ServerKeyExchange : IHandshakeMessage - { - - - public THandshakeType MessageType - { - get { return THandshakeType.ServerKeyExchange; } - } - - public virtual int CalculateSize(Version version) - { - return 0; - } - - public virtual void Serialise(System.IO.Stream stream, Version version) - { - - } - } -} diff --git a/src/DTLS.Net/HandshakeMessages/ServerHello.cs b/src/DTLS.Net/HandshakeMessages/ServerHello.cs deleted file mode 100644 index c2c6984..0000000 --- a/src/DTLS.Net/HandshakeMessages/ServerHello.cs +++ /dev/null @@ -1,163 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; - -namespace DTLS -{ - - // struct { - // ProtocolVersion server_version; - // Random random; - // SessionID session_id; - // CipherSuite cipher_suite; - // CompressionMethod compression_method; - // select (extensions_present) { - // case false: - // struct {}; - // case true: - // Extension extensions<0..2^16-1>; - // }; - //} ServerHello; - - internal class ServerHello : IHandshakeMessage - { - public static Version DefaultVersion = new Version(1, 0); - - Version _ServerVersion; - RandomData _Random; - byte[] _SessionID; - ushort _CipherSuite; - byte _CompressionMethod; - Extensions _Extensions; - - public THandshakeType MessageType { get { return THandshakeType.ServerHello; } } - - - public Version ServerVersion - { - get { return _ServerVersion; } - set { _ServerVersion = value; } - } - - public RandomData Random - { - get { return _Random; } - set { _Random = value; } - } - - - public byte[] SessionID - { - get { return _SessionID; } - set { _SessionID = value; } - } - - public ushort CipherSuite - { - get { return _CipherSuite; } - set { _CipherSuite = value; } - } - - public byte CompressionMethod - { - get { return _CompressionMethod; } - set { _CompressionMethod = value; } - } - - public Extensions Extensions - { - get { return _Extensions; } - set { _Extensions = value; } - } - - public ServerHello() - { - _ServerVersion = DefaultVersion; - } - - public void AddExtension(IExtension extension) - { - if (_Extensions == null) - { - _Extensions = new Extensions(); - } - Extension item = new Extension(); - item.ExtensionType = extension.ExtensionType; - item.SpecifcExtension = extension; - _Extensions.Add(item); - } - - public int CalculateSize(Version version) - { - int result = 38; //Version + Length of cookie - if (_SessionID != null) - result += _SessionID.Length; - if (_Extensions != null) - result += _Extensions.CalculateSize(); - return result; - } - - public static ServerHello Deserialise(Stream stream) - { - ServerHello result = new ServerHello(); - result._ServerVersion = new Version(255 - stream.ReadByte(), 255 - stream.ReadByte()); - result._Random = RandomData.Deserialise(stream); - int length = stream.ReadByte(); - if (length > 0) - { - result._SessionID = new byte[length]; - stream.Read(result._SessionID, 0, length); - } - result._CipherSuite = NetworkByteOrderConverter.ToUInt16(stream); - result._CompressionMethod = (byte)stream.ReadByte(); - result._Extensions = Extensions.Deserialise(stream, false); - return result; - } - - public void Serialise(System.IO.Stream stream, Version version) - { - stream.WriteByte((byte)(255 - _ServerVersion.Major)); - stream.WriteByte((byte)(255 - _ServerVersion.Minor)); - _Random.Serialise(stream); - if (_SessionID == null) - { - stream.WriteByte(0); - } - else - { - stream.WriteByte((byte)_SessionID.Length); - stream.Write(_SessionID, 0, _SessionID.Length); - } - NetworkByteOrderConverter.WriteUInt16(stream, _CipherSuite); - stream.WriteByte(_CompressionMethod); - if (_Extensions != null) - _Extensions.Serialise(stream); - } - - - } -} diff --git a/src/DTLS.Net/PSK/PSKIdentities.cs b/src/DTLS.Net/PSK/PSKIdentities.cs deleted file mode 100644 index 99eab1e..0000000 --- a/src/DTLS.Net/PSK/PSKIdentities.cs +++ /dev/null @@ -1,162 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; -using System.IO; - -namespace DTLS -{ - public class PSKIdentities: IEqualityComparer - { - private Dictionary _Identities; - - public int Count { get {return _Identities.Count;} } - - public PSKIdentities() - { - _Identities = new Dictionary(10,this); - } - - public void AddIdentity(byte[] identity, byte[] key) - { - PSKIdentity pskIdentity = new PSKIdentity() { Identity = identity, Key = key }; - _Identities.Add(pskIdentity.Identity, pskIdentity); - } - - public void AddIdentity(string identity, byte[] key) - { - PSKIdentity pskIdentity = new PSKIdentity() { Identity = Encoding.UTF8.GetBytes(identity), Key = key }; - _Identities.Add(pskIdentity.Identity, pskIdentity); - } - - public byte[] GetKey(byte[] identity) - { - byte[] result = null; - PSKIdentity pskIdentity; - if (_Identities.TryGetValue(identity, out pskIdentity)) - { - result = pskIdentity.Key; - } - return result; - } - - internal PSKIdentity GetRandom() - { - PSKIdentity result = null; - if (_Identities.Count > 0) - { - Random random = new Random(); - int index = random.Next(_Identities.Count); - int count = 0; - foreach (byte[] identity in _Identities.Keys) - { - if (count == index) - { - _Identities.TryGetValue(identity, out result); - break; - } - count++; - } - } - return result; - } - - private static byte[] HexToBytes(string hex) - { - byte[] result = new byte[hex.Length / 2]; - int count = 0; - for (int index = 0; index < hex.Length; index += 2) - { - result[count] = Convert.ToByte(hex.Substring(index, 2), 16); - count++; - } - return result; - } - - public void LoadFromFile(string fileName) - { - if (File.Exists(fileName)) - { - using (XmlReader reader = XmlReader.Create(fileName)) - { - while (reader.Read()) - { - if ((reader.NodeType == XmlNodeType.Element) && (reader.Name == "Identity")) - { - if (reader.HasAttributes) - { - string name = null; - byte[] key = null; - reader.MoveToFirstAttribute(); - do - { - if (reader.Name == "name") - name = reader.Value; - else if (reader.Name == "key") - key = HexToBytes(reader.Value); - } while (reader.MoveToNextAttribute()); - reader.MoveToElement(); - if ((name != null) && (key != null)) - AddIdentity(name, key); - } - } - } - } - } - } - - bool IEqualityComparer.Equals(byte[] x, byte[] y) - { - return TLSUtils.ByteArrayCompare(x, y); - } - - int IEqualityComparer.GetHashCode(byte[] obj) - { - int result = 0; - for (int i = 0; i < obj.Length; i++) - { - switch (i % 4) - { - case 0: - result = result | obj[i]; - break; - case 1: - result = result | (obj[i] << 8); - break; - case 2: - result = result | (obj[i] << 16); - break; - case 3: - result = result | (obj[i] << 24); - break; - default: - break; - } - } - return result; - } - - } -} diff --git a/src/DTLS.Net/Properties/AssemblyInfo.cs b/src/DTLS.Net/Properties/AssemblyInfo.cs deleted file mode 100644 index fa5ed43..0000000 --- a/src/DTLS.Net/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,45 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("DTLS.Net")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Imagination Technologies Limited")] -[assembly: AssemblyProduct("DTLS.Net")] -[assembly: AssemblyCopyright("Copyright © Imagination Technologies Limited 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("6d15ed53-d821-4909-8318-859d1f98f1da")] diff --git a/src/DTLS.Net/Records/AlertRecord.cs b/src/DTLS.Net/Records/AlertRecord.cs deleted file mode 100644 index 462f8a7..0000000 --- a/src/DTLS.Net/Records/AlertRecord.cs +++ /dev/null @@ -1,106 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace DTLS -{ - - //enum { warning(1), fatal(2), (255) } AlertLevel; - - // enum { - // close_notify(0), - // unexpected_message(10), - // bad_record_mac(20), - // decryption_failed_RESERVED(21), - // record_overflow(22), - // decompression_failure(30), - // handshake_failure(40), - // no_certificate_RESERVED(41), - // bad_certificate(42), - // unsupported_certificate(43), - // certificate_revoked(44), - // certificate_expired(45), - // certificate_unknown(46), - // illegal_parameter(47), - // unknown_ca(48), - // access_denied(49), - // decode_error(50), - // decrypt_error(51), - // export_restriction_RESERVED(60), - // protocol_version(70), - // insufficient_security(71), - // internal_error(80), - // user_canceled(90), - // no_renegotiation(100), - // unsupported_extension(110), - // (255) - // } AlertDescription; - - // struct { - // AlertLevel level; - // AlertDescription description; - // } Alert; - - internal class AlertRecord - { - private TAlertLevel _AlertLevel; - private TAlertDescription _AlertDescription; - - public TAlertLevel AlertLevel - { - get { return _AlertLevel; } - set { _AlertLevel = value; } - } - - public TAlertDescription AlertDescription - { - get { return _AlertDescription; } - set { _AlertDescription = value; } - } - - public static AlertRecord Deserialise(byte[] data) - { - AlertRecord result = new AlertRecord(); - result._AlertLevel = (TAlertLevel)data[0]; - result._AlertDescription = (TAlertDescription)data[1]; - return result; - } - - public static AlertRecord Deserialise(System.IO.Stream stream) - { - AlertRecord result = new AlertRecord(); - result._AlertLevel = (TAlertLevel)stream.ReadByte(); - result._AlertDescription = (TAlertDescription)stream.ReadByte(); - return result; - } - - public void Serialise(System.IO.Stream stream) - { - stream.WriteByte((byte)_AlertLevel); - stream.WriteByte((byte)_AlertDescription); - } - } -} diff --git a/src/DTLS.Net/Records/DTLSRecord.cs b/src/DTLS.Net/Records/DTLSRecord.cs deleted file mode 100644 index f44fdc3..0000000 --- a/src/DTLS.Net/Records/DTLSRecord.cs +++ /dev/null @@ -1,151 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using System.Net; - -namespace DTLS -{ - - //RFC 6347 DTLS1.2 - // RFC 4347 DTLS - //RFC 5246 TLS1.2 - internal class DTLSRecord - { - public static Version DefaultVersion = new Version(1, 0); - public static Version Version1_0 = new Version(1, 0); - public static Version Version1_2 = new Version(1, 2); - - public const int RECORD_OVERHEAD = 13; - - TRecordType _RecordType; - Version _Version; - ushort _Epoch; - long _SequenceNumber; //realy only 48 bit - ushort _Length; - byte[] _Fragment; - EndPoint _RemoteEndPoint; - - // struct { - // ContentType type; - // ProtocolVersion version; - // uint16 epoch; // New field - // uint48 sequence_number; // New field - // uint16 length; - // opaque fragment[DTLSPlaintext.length]; - //} DTLSPlaintext; - - public TRecordType RecordType - { - get { return _RecordType; } - set { _RecordType = value; } - } - - public Version Version - { - get { return _Version; } - set { _Version = value; } - } - - public ushort Epoch - { - get { return _Epoch; } - set { _Epoch = value; } - } - - public long SequenceNumber - { - get { return _SequenceNumber; } - set { _SequenceNumber = value; } - } - - public byte[] Fragment - { - get { return _Fragment; } - set - { - _Fragment = value; - if (_Fragment != null) - _Length = (ushort)_Fragment.Length; - } - } - - public EndPoint RemoteEndPoint - { - get { return _RemoteEndPoint; } - set { _RemoteEndPoint = value; } - } - - public DTLSRecord() - { - _Version = DefaultVersion; - } - - public static DTLSRecord Deserialise(Stream stream) - { - DTLSRecord result = new DTLSRecord(); - result._RecordType = (TRecordType)stream.ReadByte(); - // could check here for a valid type, and bail out if invalid - result._Version = new Version(255 - stream.ReadByte(), 255 - stream.ReadByte()); - result._Epoch = NetworkByteOrderConverter.ToUInt16(stream); - result._SequenceNumber = NetworkByteOrderConverter.ToInt48(stream); - result._Length = NetworkByteOrderConverter.ToUInt16(stream); - if (result._Length > 0) - { - result._Fragment = new byte[result._Length]; - int length = stream.Read(result._Fragment, 0, result._Length); - while (length < result._Length) - { - int bytesRead = stream.Read(result._Fragment, length, result._Length - length); - if (bytesRead > 0) - { - length += bytesRead; - } - else - { - break; - } - } - } - return result; - } - - - public void Serialise(Stream stream) - { - stream.WriteByte((byte)_RecordType); - stream.WriteByte((byte)(255 - _Version.Major)); - stream.WriteByte((byte)(255 - _Version.Minor)); - NetworkByteOrderConverter.WriteUInt16(stream, _Epoch); - NetworkByteOrderConverter.WriteInt48(stream, _SequenceNumber); - NetworkByteOrderConverter.WriteUInt16(stream, _Length); - if (_Length > 0) - { - stream.Write(_Fragment, 0, _Length); - } - } - } -} diff --git a/src/DTLS.Net/Records/HandshakeRecord.cs b/src/DTLS.Net/Records/HandshakeRecord.cs deleted file mode 100644 index 49c7d6e..0000000 --- a/src/DTLS.Net/Records/HandshakeRecord.cs +++ /dev/null @@ -1,118 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace DTLS -{ - - //struct { - // HandshakeType msg_type; - // uint24 length; - // uint16 message_seq; // New field - // uint24 fragment_offset; // New field - // uint24 fragment_length; // New field - // select (HandshakeType) { - // case hello_request: HelloRequest; - // case client_hello: ClientHello; - // case server_hello: ServerHello; - // case hello_verify_request: HelloVerifyRequest; // New field - // case certificate:Certificate; - // case server_key_exchange: ServerKeyExchange; - // case certificate_request: CertificateRequest; - // case server_hello_done:ServerHelloDone; - // case certificate_verify: CertificateVerify; - // case client_key_exchange: ClientKeyExchange; - // case finished: Finished; - // } body; } Handshake; - - internal class HandshakeRecord - { - public const int RECORD_OVERHEAD = 12; - - THandshakeType _MessageType; - uint _Length; - ushort _MessageSeq; - uint _FragmentOffset; - uint _FragmentLength; - - public THandshakeType MessageType - { - get { return _MessageType; } - set { _MessageType = value; } - } - - public uint Length - { - get { return _Length; } - set { _Length = value; } - } - - public ushort MessageSeq - { - get { return _MessageSeq; } - set { _MessageSeq = value; } - } - - public uint FragmentOffset - { - get { return _FragmentOffset; } - set { _FragmentOffset = value; } - } - - public uint FragmentLength - { - get { return _FragmentLength; } - set { _FragmentLength = value; } - } - - - public static HandshakeRecord Deserialise(System.IO.Stream stream) - { - HandshakeRecord result = new HandshakeRecord(); - result._MessageType = (THandshakeType)stream.ReadByte(); - result._Length = NetworkByteOrderConverter.ToUInt24(stream); - result._MessageSeq = NetworkByteOrderConverter.ToUInt16(stream); - result._FragmentOffset = NetworkByteOrderConverter.ToUInt24(stream); - result._FragmentLength = NetworkByteOrderConverter.ToUInt24(stream); - return result; - } - - public void Serialise(System.IO.Stream stream) - { - stream.WriteByte((byte)_MessageType); - NetworkByteOrderConverter.WriteUInt24(stream, _Length); - NetworkByteOrderConverter.WriteUInt16(stream, _MessageSeq); - NetworkByteOrderConverter.WriteUInt24(stream, _FragmentOffset); - NetworkByteOrderConverter.WriteUInt24(stream, _FragmentLength); - } - } - - - -// struct { -// ProtocolVersion server_version; -// opaque cookie<0..2^8-1>; } HelloVerifyRequest; -} diff --git a/src/DTLS.Net/Server.cs b/src/DTLS.Net/Server.cs deleted file mode 100644 index 318f7db..0000000 --- a/src/DTLS.Net/Server.cs +++ /dev/null @@ -1,552 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using System.Net; -using System.Net.Sockets; -using System.Threading; -using Org.BouncyCastle.Utilities.IO.Pem; - -namespace DTLS -{ - public class Server - { - public delegate void DataReceivedEventHandler(System.Net.EndPoint endPoint, byte[] data); - public event DataReceivedEventHandler DataReceived; - - public delegate byte[] ValidatePSKEventHandler(byte[] identity); - public event ValidatePSKEventHandler ValidatePSK; - - private int _ReceiveBufferSize; - private int _SendBufferSize; - private int _MaxPacketSize = 1440; - private Socket _Socket; - private EndPoint _LocalEndPoint; - private ServerHandshake _Handshake; - private List _SupportedCipherSuites; - private Certificate _Certificate; - private Org.BouncyCastle.Crypto.AsymmetricKeyParameter _PrivateKey; - private Sessions _Sessions; - private PSKIdentities _PSKIdentities; - private bool _RequireClientCertificate; - - public EndPoint LocalEndPoint - { - get { return _LocalEndPoint; } - } - - public int MaxPacketSize - { - get { return _MaxPacketSize; } - set { _MaxPacketSize = value; } - } - - public PSKIdentities PSKIdentities - { - get { return _PSKIdentities; } - set { _PSKIdentities = value; } - } - - public int ReceiveBufferSize - { - get { return _ReceiveBufferSize; } - set - { - _ReceiveBufferSize = value; - if (_Socket != null) - _Socket.ReceiveBufferSize = value; - } - } - - public bool RequireClientCertificate - { - get { return _RequireClientCertificate; } - set { _RequireClientCertificate = value; } - } - - public int SendBufferSize - { - get { return _SendBufferSize; } - set - { - _SendBufferSize = value; - if (_Socket != null) - _Socket.SendBufferSize = value; - - } - } - - public List SupportedCipherSuites - { - get - { - return _SupportedCipherSuites; - } - } - - public Server(EndPoint localEndPoint) - { - _LocalEndPoint = localEndPoint; - _Sessions = new Sessions(); - _PSKIdentities = new PSKIdentities(); - _SupportedCipherSuites = new List(); - } - - public Server(EndPoint localEndPoint, List supportedCipherSuites) - { - _LocalEndPoint = localEndPoint; - _Sessions = new Sessions(); - _PSKIdentities = new PSKIdentities(); - _SupportedCipherSuites = supportedCipherSuites; - } - - private void CheckSession(Session session, DTLSRecord record) - { - if ((session.ClientEpoch == record.Epoch) && (session.ClientSequenceNumber == record.SequenceNumber)) - { - ThreadPool.QueueUserWorkItem(ProcessRecord, record); - } - else if (session.ClientEpoch > record.Epoch) - { - ThreadPool.QueueUserWorkItem(ProcessRecord, record); - } - else if ((session.ClientEpoch == record.Epoch) && (session.ClientSequenceNumber > record.SequenceNumber)) - { - ThreadPool.QueueUserWorkItem(ProcessRecord, record); - } - else - { - bool canProcessNow = false; - lock (session) - { - if ((session.ClientSequenceNumber == record.SequenceNumber) && (session.ClientEpoch == record.Epoch)) - { - canProcessNow = true; - } - else - { - session.Records.Add(record); - } - } - if (canProcessNow) - CheckSession(session, record); - } - } - - public void LoadCertificateFromPem(string filename) - { - using (FileStream stream = File.OpenRead(filename)) - { - LoadCertificateFromPem(stream); - } - } - - public void LoadCertificateFromPem(Stream stream) - { - List chain = new List(); - PemReader reader = new PemReader(new StreamReader(stream)); - PemObject pem = reader.ReadPemObject(); - - while (pem != null) - { - if (pem.Type.EndsWith("CERTIFICATE")) - { - chain.Add(pem.Content); - } - else if (pem.Type.EndsWith("PRIVATE KEY")) - { - _PrivateKey = Certificates.GetPrivateKeyFromPEM(pem); - } - pem = reader.ReadPemObject(); - } - _Certificate = new Certificate(); - _Certificate.CertChain = chain; - _Certificate.CertificateType = TCertificateType.X509; - } - - public string GetClientPSKIdentity(EndPoint clientEndPoint) - { - string result = null; - SocketAddress address = clientEndPoint.Serialize(); - Session session = _Sessions.GetSession(address); - if (session != null) - result = session.PSKIdentity; - return result; - } - - public CertificateInfo GetClientCertificateInfo(EndPoint clientEndPoint) - { - CertificateInfo result = null; - SocketAddress address = clientEndPoint.Serialize(); - Session session = _Sessions.GetSession(address); - if (session != null) - result = session.CertificateInfo; - return result; - } - - private void ProcessRecord(object state) - { - DTLSRecord record = state as DTLSRecord; - if (record != null) - { - SocketAddress address = null; - Session session = null; - try - { - address = record.RemoteEndPoint.Serialize(); - session = _Sessions.GetSession(address); - if (session == null) - { - ProcessRecord(address, session, record); - session = _Sessions.GetSession(address); - if (session != null) - { - lock (session) - { - if (record.RecordType != TRecordType.ChangeCipherSpec) - session.ClientSequenceNumber++; - } - } - } - else - { - bool processRecord = false; - if ((session.ClientEpoch == record.Epoch) && (session.ClientSequenceNumber == record.SequenceNumber)) - { - processRecord = true; - } - else if (session.ClientEpoch > record.Epoch) - { - processRecord = true; - } - else if ((session.ClientEpoch == record.Epoch) && (session.ClientSequenceNumber > record.SequenceNumber)) - { - processRecord = true; - } - if (processRecord) - { - do - { - ProcessRecord(address, session, record); - lock (session) - { - if (record.RecordType != TRecordType.ChangeCipherSpec) - session.ClientSequenceNumber++; - } - record = session.Records.PeekRecord(); - if (record != null) - { - if ((session.ClientSequenceNumber == record.SequenceNumber) && (session.ClientEpoch == record.Epoch)) - { - session.Records.RemoveRecord(); - } - else - { - record = null; - } - } - - } while (record != null); - } - } - } - catch (Org.BouncyCastle.Crypto.Tls.TlsFatalAlert ex) - { - SendAlert(session, address, TAlertLevel.Fatal, (TAlertDescription)ex.AlertDescription); - } - catch - { - SendAlert(session, address, TAlertLevel.Fatal, TAlertDescription.InternalError); - } - } - } - - private void ProcessRecord(SocketAddress address, Session session, DTLSRecord record) - { - try - { -#if DEBUG - Console.WriteLine(record.RecordType.ToString()); -#endif - switch (record.RecordType) - { - case TRecordType.ChangeCipherSpec: - if (session != null) - { - session.ClientEpoch++; - session.ClientSequenceNumber = 0; - session.SetEncyptChange(record); - } - break; - case TRecordType.Alert: - if (session != null) - { - AlertRecord alertRecord; - try - { - if (session.Cipher == null) - { - alertRecord = AlertRecord.Deserialise(record.Fragment); - } - else - { - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - byte[] data = session.Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Alert, record.Fragment, 0, record.Fragment.Length); - alertRecord = AlertRecord.Deserialise(data); - } - } - catch - { - alertRecord = new AlertRecord(); - alertRecord.AlertLevel = TAlertLevel.Fatal; - } - if (alertRecord.AlertLevel == TAlertLevel.Fatal) - _Sessions.Remove(session, address); - else if ((alertRecord.AlertLevel == TAlertLevel.Warning) || (alertRecord.AlertDescription == TAlertDescription.CloseNotify)) - { - if (alertRecord.AlertDescription == TAlertDescription.CloseNotify) - SendAlert(session, address, TAlertLevel.Warning, TAlertDescription.CloseNotify); - _Sessions.Remove(session, address); - } - } - break; - case TRecordType.Handshake: - _Handshake.ProcessHandshake(record); - break; - case TRecordType.ApplicationData: - if (session != null) - { - if (session.Cipher != null) - { - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - byte[] data = session.Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.ApplicationData, record.Fragment, 0, record.Fragment.Length); - if (DataReceived != null) - { - DataReceived(record.RemoteEndPoint, data); - } - } - } - break; - default: - break; - } - } -#if DEBUG - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); -#else - catch - { -#endif - SendAlert(session, address, TAlertLevel.Fatal, TAlertDescription.InternalError); - } - } - - private void ReceiveCallback(object sender, SocketAsyncEventArgs e) - { - if (e.BytesTransferred == 0) - { - - } - else - { - int count = e.BytesTransferred; - byte[] data = new byte[count]; - Buffer.BlockCopy(e.Buffer, 0, data, 0, count); - MemoryStream stream = new MemoryStream(data); - while (stream.Position < stream.Length) - { - DTLSRecord record = DTLSRecord.Deserialise(stream); - if (record != null) - { - record.RemoteEndPoint = e.RemoteEndPoint; - SocketAddress address = record.RemoteEndPoint.Serialize(); - Session session = _Sessions.GetSession(address); - if (session == null) - { - ThreadPool.QueueUserWorkItem(ProcessRecord, record); - } - else - { - CheckSession(session, record); - } - } - } - Socket socket = sender as Socket; - if (socket != null) - { - System.Net.EndPoint remoteEndPoint; - if (socket.AddressFamily == AddressFamily.InterNetwork) - remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - else - remoteEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0); - e.RemoteEndPoint = remoteEndPoint; - e.SetBuffer(0, 4096); - socket.ReceiveFromAsync(e); - } - } - } - - private Socket SetupSocket(AddressFamily addressFamily) - { - Socket result = new Socket(addressFamily, SocketType.Dgram, ProtocolType.Udp); - if (addressFamily == AddressFamily.InterNetworkV6) - { - result.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, true); - } - if (Environment.OSVersion.Platform != PlatformID.Unix) - { - // Do not throw SocketError.ConnectionReset by ignoring ICMP Port Unreachable - const Int32 SIO_UDP_CONNRESET = -1744830452; - result.IOControl(SIO_UDP_CONNRESET, new Byte[] { 0 }, null); - } - return result; - } - - public void Send(EndPoint remoteEndPoint, byte[] data) - { - SocketAddress address = remoteEndPoint.Serialize(); - Session session = _Sessions.GetSession(address); - if (session != null) - { - try - { - DTLSRecord record = new DTLSRecord(); - record.RecordType = TRecordType.ApplicationData; - record.Epoch = session.Epoch; - record.SequenceNumber = session.NextSequenceNumber(); - if (session.Version != null) - record.Version = session.Version; - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.ApplicationData, data, 0, data.Length); - int responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; - byte[] response = new byte[responseSize]; - using (MemoryStream stream = new MemoryStream(response)) - { - record.Serialise(stream); - } - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs() - { - RemoteEndPoint = session.RemoteEndPoint - }; - parameters.SetBuffer(response, 0, responseSize); - _Socket.SendToAsync(parameters); - } -#if DEBUG - catch (Exception ex) - { - Console.WriteLine(ex.ToString()); -#else - catch - { -#endif - } - } - } - - private void SendAlert(Session session, SocketAddress address, TAlertLevel alertLevel, TAlertDescription alertDescription) - { - if (session != null) - { - DTLSRecord record = new DTLSRecord(); - record.RecordType = TRecordType.Alert; - record.Epoch = session.Epoch; - record.SequenceNumber = session.NextSequenceNumber(); - if (session.Version != null) - record.Version = session.Version; - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - - byte[] data = new byte[2]; - data[0] = (byte)alertLevel; - data[1] = (byte)alertDescription; - if (session.Cipher == null) - record.Fragment = data; - else - record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.ApplicationData, data, 0, data.Length); - int responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; - byte[] response = new byte[responseSize]; - using (MemoryStream stream = new MemoryStream(response)) - { - record.Serialise(stream); - } - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs() - { - RemoteEndPoint = session.RemoteEndPoint - }; - parameters.SetBuffer(response, 0, responseSize); - _Socket.SendToAsync(parameters); - } - } - - public void Start() - { - if (_SupportedCipherSuites.Count == 0) - { - _SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8); //Test 1.2 - _SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 - _SupportedCipherSuites.Add(TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 - _SupportedCipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8); //Test 1.2 - _SupportedCipherSuites.Add(TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256); //Tested 1.0 1.2 - } - - _Socket = SetupSocket(_LocalEndPoint.AddressFamily); - - if (_Socket != null) - { - _Handshake = new ServerHandshake(_Socket, _MaxPacketSize, _PSKIdentities, _SupportedCipherSuites, _RequireClientCertificate, ValidatePSK); - _Handshake.Certificate = _Certificate; - _Handshake.PrivateKey = _PrivateKey; - _Handshake.Sessions = _Sessions; - _Socket.Bind(_LocalEndPoint); - StartReceive(_Socket); - } - - } - - private void StartReceive(Socket socket) - { - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs(); - if (socket.AddressFamily == AddressFamily.InterNetwork) - parameters.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0); - else - parameters.RemoteEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0); - parameters.Completed += new EventHandler(ReceiveCallback); - parameters.SetBuffer(new byte[4096], 0, 4096); - socket.ReceiveFromAsync(parameters); - } - - public void Stop() - { - if (_Socket != null) - { - _Socket.Dispose(); - _Socket = null; - } - } - - } -} diff --git a/src/DTLS.Net/ServerHandshake.cs b/src/DTLS.Net/ServerHandshake.cs deleted file mode 100644 index 349ce8d..0000000 --- a/src/DTLS.Net/ServerHandshake.cs +++ /dev/null @@ -1,630 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; -using System.Net; -using System.Net.Sockets; - -namespace DTLS -{ - internal class ServerHandshake - { - private Socket _Socket; - private int _MaxPacketSize; - private PSKIdentities _PSKIdentities; - private byte[] _HelloSecret = new byte[] { 0x12, 0x84, 0x65, 0x94, 0xD5, 0x5E, 0x4B, 0x3A, 0xF3, 0x68, 0x56, 0x6F, 0xD7, 0x1B, 0x09, 0x8A }; - private Dictionary _SupportedCipherSuites; - private bool _RequireClientCertificate; - private DTLS.Server.ValidatePSKEventHandler _ValidatePSK; - - public Certificate Certificate { get; set; } - public Org.BouncyCastle.Crypto.AsymmetricKeyParameter PrivateKey { get; set; } - public Version ServerVersion { get; set; } - public Sessions Sessions { get; set; } - private const int HANDSHAKE_DWELL_TIME = 10; - public static int HandshakeTimeout { get; set; } = 5000; - - - - public ServerHandshake(Socket socket, int maxPacketSize, PSKIdentities pskIdentities, List supportedCipherSuites, bool requireClientCertificate, DTLS.Server.ValidatePSKEventHandler validatePSK) - { - this._Socket = socket; - _ValidatePSK = validatePSK; - _MaxPacketSize = maxPacketSize; - _PSKIdentities = pskIdentities; - _SupportedCipherSuites = new Dictionary(); - _RequireClientCertificate = requireClientCertificate; - foreach (TCipherSuite item in supportedCipherSuites) - { - _SupportedCipherSuites.Add(item, null); - } - ServerVersion = new Version(1, 2); - - } - - - public void ProcessHandshake(DTLSRecord record) - { - SocketAddress address = record.RemoteEndPoint.Serialize(); - Session session = Sessions.GetSession(address); - byte[] data; - if ((session != null) && session.IsEncypted(record)) - { - int count = 0; - while ((session.Cipher == null) && (count < (HandshakeTimeout / HANDSHAKE_DWELL_TIME))) - { - System.Threading.Thread.Sleep(HANDSHAKE_DWELL_TIME); - count++; - } - - if (session.Cipher == null) - { - throw new Exception($"HandshakeTimeout: >{HandshakeTimeout}"); - } - - if (session.Cipher != null) - { - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - data = session.Cipher.DecodeCiphertext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); - } - else - data = record.Fragment; - } - else - data = record.Fragment; - using (MemoryStream stream = new MemoryStream(data)) - { - HandshakeRecord handshakeRecord = HandshakeRecord.Deserialise(stream); - if (handshakeRecord != null) - { -#if DEBUG - Console.WriteLine(handshakeRecord.MessageType.ToString()); -#endif - switch (handshakeRecord.MessageType) - { - case THandshakeType.HelloRequest: - //HelloReq - break; - case THandshakeType.ClientHello: - ClientHello clientHello = ClientHello.Deserialise(stream); - if (clientHello != null) - { - - byte[] cookie = clientHello.CalculateCookie(record.RemoteEndPoint, _HelloSecret); - - if (clientHello.Cookie == null) - { - Version version = clientHello.ClientVersion; - if (ServerVersion < version) - version = ServerVersion; - if (session == null) - { - session = new Session(); - session.SessionID = Guid.NewGuid(); - session.RemoteEndPoint = record.RemoteEndPoint; - session.Version = version; - Sessions.AddSession(address, session); - } - else - { - session.Reset(); - session.Version = version; - } - session.ClientEpoch = record.Epoch; - session.ClientSequenceNumber = record.SequenceNumber; - //session.Handshake.UpdateHandshakeHash(data); - HelloVerifyRequest helloVerifyRequest = new HelloVerifyRequest(); - helloVerifyRequest.Cookie = cookie; - helloVerifyRequest.ServerVersion = ServerVersion; - SendResponse(session, (IHandshakeMessage)helloVerifyRequest, 0); - - } - else - { - - if (session != null && session.Cipher != null && !session.IsEncypted(record)) - { - session.Reset(); - } - - if (TLSUtils.ByteArrayCompare(clientHello.Cookie, cookie)) - { - Version version = clientHello.ClientVersion; - if (ServerVersion < version) - version = ServerVersion; - if (clientHello.SessionID == null) - { - if (session == null) - { - session = new Session(); - session.NextSequenceNumber(); - session.SessionID = Guid.NewGuid(); - session.RemoteEndPoint = record.RemoteEndPoint; - Sessions.AddSession(address, session); - } - } - else - { - Guid sessionID = Guid.Empty; - if (clientHello.SessionID.Length >= 16) - { - byte[] receivedSessionID = new byte[16]; - Buffer.BlockCopy(clientHello.SessionID, 0, receivedSessionID, 0, 16); - sessionID = new Guid(receivedSessionID); - } - if (sessionID != Guid.Empty) - session = Sessions.GetSession(sessionID); - if (session == null) - { - //need to Find Session - session = new Session(); - session.SessionID = Guid.NewGuid(); - session.NextSequenceNumber(); - session.RemoteEndPoint = record.RemoteEndPoint; - Sessions.AddSession(address, session); - //session.Version = clientHello.ClientVersion; - } - } - session.Version = version; - session.Handshake.InitaliseHandshakeHash(version < DTLSRecord.Version1_2); - session.Handshake.UpdateHandshakeHash(data); - TCipherSuite cipherSuite = TCipherSuite.TLS_NULL_WITH_NULL_NULL; - foreach (TCipherSuite item in clientHello.CipherSuites) - { - if (_SupportedCipherSuites.ContainsKey(item) && CipherSuites.SupportedVersion(item, session.Version) && CipherSuites.SuiteUsable(item, PrivateKey, _PSKIdentities, _ValidatePSK != null)) - { - cipherSuite = item; - break; - } - } - - TKeyExchangeAlgorithm keyExchangeAlgorithm = CipherSuites.GetKeyExchangeAlgorithm(cipherSuite); - - ServerHello serverHello = new ServerHello(); - byte[] clientSessionID = new byte[32]; - byte[] temp = session.SessionID.ToByteArray(); - Buffer.BlockCopy(temp, 0, clientSessionID, 0, 16); - Buffer.BlockCopy(temp, 0, clientSessionID, 16, 16); - - serverHello.SessionID = clientSessionID;// session.SessionID.ToByteArray(); - serverHello.Random = new RandomData(); - serverHello.Random.Generate(); - serverHello.CipherSuite = (ushort)cipherSuite; - serverHello.ServerVersion = session.Version; - - THashAlgorithm hash = THashAlgorithm.SHA256; - TEllipticCurve curve = TEllipticCurve.secp521r1; - if (clientHello.Extensions != null) - { - foreach (Extension extension in clientHello.Extensions) - { - if (extension.SpecifcExtension is ClientCertificateTypeExtension) - { - ClientCertificateTypeExtension clientCertificateType = extension.SpecifcExtension as ClientCertificateTypeExtension; - //TCertificateType certificateType = TCertificateType.Unknown; - //foreach (TCertificateType item in clientCertificateType.CertificateTypes) - //{ - - //} - //serverHello.AddExtension(new ClientCertificateTypeExtension(certificateType)); - } - else if (extension.SpecifcExtension is EllipticCurvesExtension) - { - EllipticCurvesExtension ellipticCurves = extension.SpecifcExtension as EllipticCurvesExtension; - foreach (TEllipticCurve item in ellipticCurves.SupportedCurves) - { - if (EllipticCurveFactory.SupportedCurve(item)) - { - curve = item; - break; - } - } - } - else if (extension.SpecifcExtension is ServerCertificateTypeExtension) - { - //serverHello.AddExtension(); - } - else if (extension.SpecifcExtension is SignatureAlgorithmsExtension) - { - SignatureAlgorithmsExtension signatureAlgorithms = extension.SpecifcExtension as SignatureAlgorithmsExtension; - foreach (SignatureHashAlgorithm item in signatureAlgorithms.SupportedAlgorithms) - { - if (item.Signature == TSignatureAlgorithm.ECDSA) - { - hash = item.Hash; - break; - } - } - } - } - - } - - session.Handshake.CipherSuite = cipherSuite; - session.Handshake.ClientRandom = clientHello.Random; - session.Handshake.ServerRandom = serverHello.Random; - - - if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) - { - EllipticCurvePointFormatsExtension pointFormatsExtension = new EllipticCurvePointFormatsExtension(); - pointFormatsExtension.SupportedPointFormats.Add(TEllipticCurvePointFormat.Uncompressed); - serverHello.AddExtension(pointFormatsExtension); - } - session.Handshake.MessageSequence = 1; - SendResponse(session, serverHello, session.Handshake.MessageSequence); - session.Handshake.MessageSequence++; - - if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) - { - if (Certificate != null) - { - SendResponse(session, Certificate, session.Handshake.MessageSequence); - session.Handshake.MessageSequence++; - } - ECDHEKeyExchange keyExchange = new ECDHEKeyExchange(); - keyExchange.Curve = curve; - keyExchange.KeyExchangeAlgorithm = keyExchangeAlgorithm; - keyExchange.ClientRandom = clientHello.Random; - keyExchange.ServerRandom = serverHello.Random; - keyExchange.GenerateEphemeralKey(); - session.Handshake.KeyExchange = keyExchange; - if (session.Version == DTLSRecord.DefaultVersion) - hash = THashAlgorithm.SHA1; - ECDHEServerKeyExchange serverKeyExchange = new ECDHEServerKeyExchange(keyExchange, hash, TSignatureAlgorithm.ECDSA, PrivateKey); - SendResponse(session, serverKeyExchange, session.Handshake.MessageSequence); - session.Handshake.MessageSequence++; - if (_RequireClientCertificate) - { - CertificateRequest certificateRequest = new CertificateRequest(); - certificateRequest.CertificateTypes.Add(TClientCertificateType.ECDSASign); - certificateRequest.SupportedAlgorithms.Add(new SignatureHashAlgorithm() { Hash = THashAlgorithm.SHA256, Signature = TSignatureAlgorithm.ECDSA }); - SendResponse(session, certificateRequest, session.Handshake.MessageSequence); - session.Handshake.MessageSequence++; - } - } - else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK) - { - ECDHEKeyExchange keyExchange = new ECDHEKeyExchange(); - keyExchange.Curve = curve; - keyExchange.KeyExchangeAlgorithm = keyExchangeAlgorithm; - keyExchange.ClientRandom = clientHello.Random; - keyExchange.ServerRandom = serverHello.Random; - keyExchange.GenerateEphemeralKey(); - session.Handshake.KeyExchange = keyExchange; - ECDHEPSKServerKeyExchange serverKeyExchange = new ECDHEPSKServerKeyExchange(keyExchange); - SendResponse(session, serverKeyExchange, session.Handshake.MessageSequence); - session.Handshake.MessageSequence++; - - } - else if (keyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK) - { - PSKKeyExchange keyExchange = new PSKKeyExchange(); - keyExchange.KeyExchangeAlgorithm = keyExchangeAlgorithm; - keyExchange.ClientRandom = clientHello.Random; - keyExchange.ServerRandom = serverHello.Random; - session.Handshake.KeyExchange = keyExchange; - //Need to be able to hint identity?? for PSK if not hinting don't really need key exchange message - //PSKServerKeyExchange serverKeyExchange = new PSKServerKeyExchange(); - //SendResponse(session, serverKeyExchange, session.Handshake.MessageSequence); - //session.Handshake.MessageSequence++; - } - SendResponse(session, new ServerHelloDone(), session.Handshake.MessageSequence); - session.Handshake.MessageSequence++; - } - } - } - break; - case THandshakeType.ServerHello: - break; - case THandshakeType.HelloVerifyRequest: - break; - case THandshakeType.Certificate: - Certificate clientCertificate = Certificate.Deserialise(stream, TCertificateType.X509); - if (clientCertificate.CertChain.Count > 0) - { - session.CertificateInfo = Certificates.GetCertificateInfo(clientCertificate.CertChain[0], TCertificateFormat.CER); - } - session.Handshake.UpdateHandshakeHash(data); - break; - case THandshakeType.ServerKeyExchange: - break; - case THandshakeType.CertificateRequest: - break; - case THandshakeType.ServerHelloDone: - break; - case THandshakeType.CertificateVerify: - CertificateVerify certificateVerify = CertificateVerify.Deserialise(stream, session.Version); - session.Handshake.UpdateHandshakeHash(data); - break; - case THandshakeType.ClientKeyExchange: - if ((session == null) || (session.Handshake.KeyExchange == null)) - { - - } - else - { - session.Handshake.UpdateHandshakeHash(data); - byte[] preMasterSecret = null; - if (session.Handshake.KeyExchange.KeyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_ECDSA) - { - ECDHEClientKeyExchange clientKeyExchange = ECDHEClientKeyExchange.Deserialise(stream); - if (clientKeyExchange != null) - { - ECDHEKeyExchange ecKeyExchange = session.Handshake.KeyExchange as ECDHEKeyExchange; - preMasterSecret = ecKeyExchange.GetPreMasterSecret(clientKeyExchange.PublicKeyBytes); - } - } - else if (session.Handshake.KeyExchange.KeyExchangeAlgorithm == TKeyExchangeAlgorithm.ECDHE_PSK) - { - ECDHEPSKClientKeyExchange clientKeyExchange = ECDHEPSKClientKeyExchange.Deserialise(stream); - if (clientKeyExchange != null) - { - session.PSKIdentity = Encoding.UTF8.GetString(clientKeyExchange.PSKIdentity); - byte[] psk = _PSKIdentities.GetKey(clientKeyExchange.PSKIdentity); - - if (psk == null) - { - psk = _ValidatePSK(clientKeyExchange.PSKIdentity); - if (psk != null) - { - _PSKIdentities.AddIdentity(clientKeyExchange.PSKIdentity, psk); - } - } - - if (psk != null) - { - ECDHEKeyExchange ecKeyExchange = session.Handshake.KeyExchange as ECDHEKeyExchange; - byte[] otherSecret = ecKeyExchange.GetPreMasterSecret(clientKeyExchange.PublicKeyBytes); - preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, psk); - - } - } - } - else if (session.Handshake.KeyExchange.KeyExchangeAlgorithm == TKeyExchangeAlgorithm.PSK) - { - PSKClientKeyExchange clientKeyExchange = PSKClientKeyExchange.Deserialise(stream); - if (clientKeyExchange != null) - { - session.PSKIdentity = Encoding.UTF8.GetString(clientKeyExchange.PSKIdentity); - byte[] psk = _PSKIdentities.GetKey(clientKeyExchange.PSKIdentity); - - if (psk == null) - { - psk = _ValidatePSK(clientKeyExchange.PSKIdentity); - if (psk != null) - { - _PSKIdentities.AddIdentity(clientKeyExchange.PSKIdentity, psk); - } - } - - if (psk != null) - { - ECDHEKeyExchange ecKeyExchange = session.Handshake.KeyExchange as ECDHEKeyExchange; - byte[] otherSecret = new byte[psk.Length]; - preMasterSecret = TLSUtils.GetPSKPreMasterSecret(otherSecret, psk); - } - } - } - - if (preMasterSecret != null) - { - //session.MasterSecret = TLSUtils.CalculateMasterSecret(preMasterSecret, session.KeyExchange); - //TLSUtils.AssignCipher(session); - - session.Cipher = TLSUtils.AssignCipher(preMasterSecret, false, session.Version, session.Handshake); - } - } - break; - case THandshakeType.Finished: - Finished finished = Finished.Deserialise(stream); - if (session != null) - { - byte[] handshakeHash = session.Handshake.GetHash(); - byte[] calculatedVerifyData = TLSUtils.GetVerifyData(session.Version,session.Handshake,false, true, handshakeHash); -#if DEBUG - Console.Write("Handshake Hash:"); - TLSUtils.WriteToConsole(handshakeHash); - Console.Write("Sent Verify:"); - TLSUtils.WriteToConsole(finished.VerifyData); - Console.Write("Calc Verify:"); - TLSUtils.WriteToConsole(calculatedVerifyData); -#endif - if (TLSUtils.ByteArrayCompare(finished.VerifyData, calculatedVerifyData)) - { - - SendChangeCipherSpec(session); - session.Handshake.UpdateHandshakeHash(data); - handshakeHash = session.Handshake.GetHash(); - Finished serverFinished = new Finished(); - serverFinished.VerifyData = TLSUtils.GetVerifyData(session.Version,session.Handshake,false, false, handshakeHash); - SendResponse(session, serverFinished, session.Handshake.MessageSequence); - session.Handshake.MessageSequence++; - } - else - { - throw new Exception(); - } - } - break; - default: - break; - } - } - } - } - - - - private void SendResponse(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence) - { - int size = handshakeMessage.CalculateSize(session.Version); - int maxPayloadSize = _MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD; - if (size > maxPayloadSize) - { - - } - else - { - - DTLSRecord record = new DTLSRecord(); - record.RecordType = TRecordType.Handshake; - record.Epoch = session.Epoch; - record.SequenceNumber = session.NextSequenceNumber(); - record.Fragment = new byte[HandshakeRecord.RECORD_OVERHEAD + size]; - if (session.Version != null) - record.Version = session.Version; - HandshakeRecord handshakeRecord = new HandshakeRecord(); - handshakeRecord.MessageType = handshakeMessage.MessageType; - handshakeRecord.MessageSeq = messageSequence; - handshakeRecord.Length = (uint)size; - handshakeRecord.FragmentLength = (uint)size; - using (MemoryStream stream = new MemoryStream(record.Fragment)) - { - handshakeRecord.Serialise(stream); - handshakeMessage.Serialise(stream, session.Version); - } - if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest) - { - session.Handshake.UpdateHandshakeHash(record.Fragment); - } - int responseSize = DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD + size; - if (session.Cipher != null) - { - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); - responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length; - } - byte[] response = new byte[responseSize]; - using (MemoryStream stream = new MemoryStream(response)) - { - record.Serialise(stream); - } - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs() - { - RemoteEndPoint = session.RemoteEndPoint - }; - parameters.SetBuffer(response, 0, responseSize); - _Socket.SendToAsync(parameters); - } - - - } - - private void SendResponseEnd(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence) - { - int size = handshakeMessage.CalculateSize(session.Version); - int maxPayloadSize = _MaxPacketSize - DTLSRecord.RECORD_OVERHEAD + HandshakeRecord.RECORD_OVERHEAD; - if (size > maxPayloadSize) - { - - } - else - { - DTLSRecord record = CreateRecord(session, handshakeMessage, messageSequence); - session.Handshake.MessageSequence++; - DTLSRecord recordEnd = CreateRecord(session, new ServerHelloDone(), session.Handshake.MessageSequence); - session.Handshake.MessageSequence++; - int responseSize = DTLSRecord.RECORD_OVERHEAD + record.Fragment.Length + DTLSRecord.RECORD_OVERHEAD + recordEnd.Fragment.Length; - - byte[] response = new byte[responseSize]; - using (MemoryStream stream = new MemoryStream(response)) - { - record.Serialise(stream); - recordEnd.Serialise(stream); - } - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs() - { - RemoteEndPoint = session.RemoteEndPoint - }; - parameters.SetBuffer(response, 0, responseSize); - _Socket.SendToAsync(parameters); - } - - - } - - private DTLSRecord CreateRecord(Session session, IHandshakeMessage handshakeMessage, ushort messageSequence) - { - int size = handshakeMessage.CalculateSize(session.Version); - DTLSRecord record = new DTLSRecord(); - record.RecordType = TRecordType.Handshake; - record.Epoch = session.Epoch; - record.SequenceNumber = session.NextSequenceNumber(); - record.Fragment = new byte[HandshakeRecord.RECORD_OVERHEAD + size]; - if (session.Version != null) - record.Version = session.Version; - HandshakeRecord handshakeRecord = new HandshakeRecord(); - handshakeRecord.MessageType = handshakeMessage.MessageType; - handshakeRecord.MessageSeq = messageSequence; - handshakeRecord.Length = (uint)size; - handshakeRecord.FragmentLength = (uint)size; - using (MemoryStream stream = new MemoryStream(record.Fragment)) - { - handshakeRecord.Serialise(stream); - handshakeMessage.Serialise(stream, session.Version); - } - if (handshakeMessage.MessageType != THandshakeType.HelloVerifyRequest) - { - session.Handshake.UpdateHandshakeHash(record.Fragment); - } - if (session.Cipher != null) - { - long sequenceNumber = ((long)record.Epoch << 48) + record.SequenceNumber; - record.Fragment = session.Cipher.EncodePlaintext(sequenceNumber, (byte)TRecordType.Handshake, record.Fragment, 0, record.Fragment.Length); - } - return record; - } - - - private void SendChangeCipherSpec(Session session) - { - int size = 1; - int responseSize = DTLSRecord.RECORD_OVERHEAD + size; - byte[] response = new byte[responseSize]; - DTLSRecord record = new DTLSRecord(); - record.RecordType = TRecordType.ChangeCipherSpec; - record.Epoch = session.Epoch; - record.SequenceNumber = session.NextSequenceNumber(); - record.Fragment = new byte[size]; - record.Fragment[0] = 1; - if (session.Version != null) - record.Version = session.Version; - using (MemoryStream stream = new MemoryStream(response)) - { - record.Serialise(stream); - } - SocketAsyncEventArgs parameters = new SocketAsyncEventArgs() - { - RemoteEndPoint = session.RemoteEndPoint - }; - parameters.SetBuffer(response, 0, responseSize); - _Socket.SendToAsync(parameters); - session.ChangeEpoch(); - } - - } -} diff --git a/src/DTLS.Net/Util/NetworkByteOrderConverter.cs b/src/DTLS.Net/Util/NetworkByteOrderConverter.cs deleted file mode 100644 index 49da398..0000000 --- a/src/DTLS.Net/Util/NetworkByteOrderConverter.cs +++ /dev/null @@ -1,292 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.IO; - -namespace DTLS -{ - internal static class NetworkByteOrderConverter - { - public static short ToInt16(Stream stream) - { - short result = 0; - byte[] buffer = new byte[2]; - int read = stream.Read(buffer, 0, 2); - if (read == 2) - result = ToInt16(buffer, 0); - else - throw new EndOfStreamException(); - return result; - } - - public static short ToInt16(byte[] value, uint startIndex) - { - short result; - result = (short)((int)(value[startIndex]) << 8 | (int)value[startIndex + 1]); - return result; - } - - public static int ToInt24(Stream stream) - { - int result = 0; - byte[] buffer = new byte[3]; - int read = stream.Read(buffer, 0, 3); - if (read == 3) - result = ToInt24(buffer, 0); - else - throw new EndOfStreamException(); - return result; - } - - public static int ToInt24(byte[] value, uint startIndex) - { - int result; - result = (((int)value[startIndex]) << 16 | ((int)value[startIndex + 1]) << 8 | (int)value[startIndex + 2]); - return result; - } - - public static int ToInt32(Stream stream) - { - int result = 0; - byte[] buffer = new byte[4]; - int read = stream.Read(buffer, 0, 4); - if (read == 4) - result = ToInt32(buffer, 0); - else - throw new EndOfStreamException(); - return result; - } - - public static int ToInt32(byte[] value, uint startIndex) - { - int result; - result = (((int)value[startIndex]) << 24 | ((int)value[startIndex + 1]) << 16 | ((int)value[startIndex + 2]) << 8 | (int)value[startIndex + 3]); - return result; - } - - public static long ToInt48(Stream stream) - { - long result = 0; - byte[] buffer = new byte[6]; - int read = stream.Read(buffer, 0, 6); - if (read == 6) - result = ToInt48(buffer, 0); - else - throw new EndOfStreamException(); - return result; - } - - public static long ToInt48(byte[] value, uint startIndex) - { - long result; - result = ToUInt32(value, startIndex + 2); - result = result | (((long)ToUInt16(value, startIndex)) << 32); - return result; - } - - - public static ushort ToUInt16(Stream stream) - { - ushort result = 0; - byte[] buffer = new byte[2]; - int read = stream.Read(buffer, 0, 2); - if (read == 2) - result = ToUInt16(buffer, 0); - else - throw new EndOfStreamException(); - return result; - } - - public static ushort ToUInt16(byte[] value, uint startIndex) - { - ushort result; - result = (ushort)((uint)(value[startIndex]) << 8 | (uint)value[startIndex + 1]); - return result; - } - - public static uint ToUInt24(Stream stream) - { - uint result = 0; - byte[] buffer = new byte[3]; - int read = stream.Read(buffer, 0, 3); - if (read == 3) - result = ToUInt24(buffer, 0); - else - throw new EndOfStreamException(); - return result; - } - - public static uint ToUInt24(byte[] value, uint startIndex) - { - uint result; - result = (((uint)value[startIndex]) << 16 | ((uint)value[startIndex + 1]) << 8 | (uint)value[startIndex + 2]); - return result; - } - - public static uint ToUInt32(Stream stream) - { - uint result = 0; - byte[] buffer = new byte[4]; - int read = stream.Read(buffer, 0, 4); - if (read == 4) - result = ToUInt32(buffer, 0); - else - throw new EndOfStreamException(); - return result; - } - - public static uint ToUInt32(byte[] value, uint startIndex) - { - uint result; - result = (((uint)value[startIndex]) << 24 | ((uint)value[startIndex + 1]) << 16 | ((uint)value[startIndex + 2]) << 8 | (uint)value[startIndex + 3]); - return result; - } - - public static ulong ToUInt48(Stream stream) - { - ulong result = 0; - byte[] buffer = new byte[6]; - int read = stream.Read(buffer, 0, 6); - if (read == 6) - result = ToUInt48(buffer, 0); - else - throw new EndOfStreamException(); - return result; - } - - public static ulong ToUInt48(byte[] value, uint startIndex) - { - ulong result; - result = ToUInt32(value, startIndex + 2); - result = result | (((ulong)ToUInt16(value,startIndex)) << 32); - return result; - } - - - public static void WriteInt16(Stream stream, short value) - { - byte[] buffer = new byte[4]; - buffer[0] = (byte)(value >> 8); - buffer[1] = (byte)(value & 0xFF); - stream.Write(buffer, 0, 2); - } - - public static void WriteInt24(Stream stream, int value) - { - byte[] buffer = new byte[3]; - buffer[0] = (byte)(value >> 16); - buffer[1] = (byte)(value >> 8); - buffer[2] = (byte)(value & 0xFF); - stream.Write(buffer, 0, 3); - } - - public static void WriteInt32(Stream stream, int value) - { - byte[] buffer = new byte[4]; - buffer[0] = (byte)(value >> 24); - buffer[1] = (byte)(value >> 16); - buffer[2] = (byte)(value >> 8); - buffer[3] = (byte)(value & 0xFF); - stream.Write(buffer, 0, 4); - } - - public static void WriteInt32(byte[] buffer, int startIndex, int value) - { - buffer[startIndex] = (byte)(value >> 24); - buffer[startIndex + 1] = (byte)(value >> 16); - buffer[startIndex + 2] = (byte)(value >> 8); - buffer[startIndex + 3] = (byte)(value & 0xFF); - } - - public static void WriteInt48(Stream stream, long value) - { - byte[] buffer = new byte[6]; - buffer[0] = (byte)(value >> 40); - buffer[1] = (byte)(value >> 32); - buffer[2] = (byte)(value >> 24); - buffer[3] = (byte)(value >> 16); - buffer[4] = (byte)(value >> 8); - buffer[5] = (byte)(value & 0xFF); - stream.Write(buffer, 0, 6); - } - - public static void WriteUInt16(Stream stream, ushort value) - { - byte[] buffer = new byte[4]; - buffer[0]= (byte)(value >> 8); - buffer[1] = (byte)(value & 0xFF); - stream.Write(buffer, 0, 2); - } - - public static void WriteUInt24(Stream stream, uint value) - { - byte[] buffer = new byte[3]; - buffer[0] = (byte)(value >> 16); - buffer[1] = (byte)(value >> 8); - buffer[2] = (byte)(value & 0xFF); - stream.Write(buffer, 0, 3); - } - - public static void WriteUInt32(Stream stream, uint value) - { - byte[] buffer = new byte[4]; - buffer[0]= (byte)(value >> 24); - buffer[1]= (byte)(value >> 16); - buffer[2]= (byte)(value >> 8); - buffer[3]= (byte)(value & 0xFF); - stream.Write(buffer, 0, 4); - } - - public static void WriteUInt16(byte[] buffer, int startIndex, ushort value) - { - buffer[startIndex] = (byte)(value >> 8); - buffer[startIndex+ 1] = (byte)(value & 0xFF); - } - - public static void WriteUInt32(byte[] buffer, int startIndex, uint value) - { - buffer[startIndex] = (byte)(value >> 24); - buffer[startIndex + 1] = (byte)(value >> 16); - buffer[startIndex + 2] = (byte)(value >> 8); - buffer[startIndex + 3] = (byte)(value & 0xFF); - } - - public static void WriteUInt48(Stream stream, ulong value) - { - byte[] buffer = new byte[6]; - buffer[0] = (byte)(value >> 40); - buffer[1] = (byte)(value >> 32); - buffer[2] = (byte)(value >> 24); - buffer[3] = (byte)(value >> 16); - buffer[4] = (byte)(value >> 8); - buffer[5] = (byte)(value & 0xFF); - stream.Write(buffer, 0, 6); - } - - - } - -} diff --git a/src/DTLS.Net/Util/TLSUtils.cs b/src/DTLS.Net/Util/TLSUtils.cs deleted file mode 100644 index dd30752..0000000 --- a/src/DTLS.Net/Util/TLSUtils.cs +++ /dev/null @@ -1,233 +0,0 @@ -/*********************************************************************************************************************** - Copyright (c) 2016, Imagination Technologies Limited and/or its affiliated group companies. - All rights reserved. - - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the - following conditions are met: - 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the - following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other materials provided with the distribution. - 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote - products derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -***********************************************************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Org.BouncyCastle.Crypto.Tls; - -namespace DTLS -{ - internal class TLSUtils - { - public static DateTime UnixEpoch = new DateTime(1970, 1, 1); - - private static byte[] MASTER_SECRET_LABEL; - private const int MASTER_SECRET_LENGTH = 48; - private static TlsCipherFactory CipherFactory; - - static TLSUtils() - { - MASTER_SECRET_LABEL = Encoding.ASCII.GetBytes("master secret"); - CipherFactory = new DefaultTlsCipherFactory(); - } - - public static bool ByteArrayCompare(byte[] x, byte[] y) - { - bool result = true; - if (x.Length == y.Length) - { - for (int index = 0; index < x.Length; index++) - { - if (x[index] != y[index]) - { - result = false; - break; - } - } - } - else - result = false; - return result; - } - - public static byte[] CalculateMasterSecret(byte[] preMasterSecret, IKeyExchange keyExchange) - { - byte[] result; - byte[] clientRandom = keyExchange.ClientRandom.Serialise(); - byte[] serverRandom = keyExchange.ServerRandom.Serialise(); - byte[] seed = new byte[MASTER_SECRET_LABEL.Length + clientRandom.Length + serverRandom.Length]; - Buffer.BlockCopy(MASTER_SECRET_LABEL, 0, seed, 0, MASTER_SECRET_LABEL.Length); - Buffer.BlockCopy(clientRandom, 0, seed, MASTER_SECRET_LABEL.Length, clientRandom.Length); - Buffer.BlockCopy(serverRandom, 0, seed, MASTER_SECRET_LABEL.Length + clientRandom.Length, serverRandom.Length); - result = PseudorandomFunction(preMasterSecret, seed, MASTER_SECRET_LENGTH); - Array.Clear(preMasterSecret, 0, preMasterSecret.Length); - return result; - } - - public static byte[] PseudorandomFunction(byte[] secret, byte[] seed, int length) - { - byte[] result = new byte[length]; - System.Security.Cryptography.HMACSHA256 hmac = new System.Security.Cryptography.HMACSHA256(secret); - int iterations = (int)Math.Ceiling(length / (double)hmac.HashSize); - byte[] dataToHash = seed; - int offset = 0; - for (int index = 0; index < iterations; index++) - { - dataToHash = hmac.ComputeHash(dataToHash); - hmac.TransformBlock(dataToHash, 0, dataToHash.Length, dataToHash, 0); - byte[] hash = hmac.TransformFinalBlock(seed, 0, seed.Length); - Buffer.BlockCopy(hash, 0, result, offset, Math.Min(hash.Length, length - offset)); - offset += hash.Length; - } - return result; - } - - private static int GetEncryptionAlgorithm(TCipherSuite cipherSuite) - { - int result = 0; - if (cipherSuite == TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) - result = EncryptionAlgorithm.AES_128_CCM_8; - else if (cipherSuite == TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) - result = EncryptionAlgorithm.AES_128_CBC; - else if (cipherSuite == TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8) - result = EncryptionAlgorithm.AES_128_CCM_8; - else if (cipherSuite == TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256) - result = EncryptionAlgorithm.AES_128_CBC; - else if (cipherSuite == TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256) - result = EncryptionAlgorithm.AES_128_CBC; - return result; - } - - private static int GetMACAlgorithm(TCipherSuite cipherSuite) - { - int result = 0; - if (cipherSuite == TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8) - result = MacAlgorithm.cls_null; - else if (cipherSuite == TCipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256) - result = MacAlgorithm.hmac_sha256; - else if (cipherSuite == TCipherSuite.TLS_PSK_WITH_AES_128_CCM_8) - result = MacAlgorithm.cls_null; - else if (cipherSuite == TCipherSuite.TLS_PSK_WITH_AES_128_CBC_SHA256) - result = MacAlgorithm.hmac_sha256; - else if (cipherSuite == TCipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256) - result = MacAlgorithm.hmac_sha256; - return result; - } - - public static TlsCipher AssignCipher(byte[] preMasterSecret, bool client, Version version, HandshakeInfo handshakeInfo) - { - int encryptionAlgorithm = GetEncryptionAlgorithm(handshakeInfo.CipherSuite); - int macAlgorithm = GetMACAlgorithm(handshakeInfo.CipherSuite); - TlsContext context = new DTLSContext(client, version, handshakeInfo); - SecurityParameters securityParameters = context.SecurityParameters; - byte[] seed = Concat(securityParameters.ClientRandom, securityParameters.ServerRandom); - string asciiLabel = ExporterLabel.master_secret; - handshakeInfo.MasterSecret = TlsUtilities.PRF(context, preMasterSecret, asciiLabel, seed, 48); - //session.Handshake.MasterSecret = TlsUtilities.PRF_legacy(preMasterSecret, asciiLabel, seed, 48); -#if DEBUG - Console.Write("MasterSecret :"); - WriteToConsole(handshakeInfo.MasterSecret); -#endif - - seed = Concat(securityParameters.ServerRandom, securityParameters.ClientRandom); - byte[] key_block = TlsUtilities.PRF(context, handshakeInfo.MasterSecret, ExporterLabel.key_expansion, seed, 96); - //byte[] key_block = TlsUtilities.PRF_legacy(session.Handshake.MasterSecret, ExporterLabel.key_expansion, seed, 96); -#if DEBUG - Console.Write("Key block :"); - WriteToConsole(key_block); -#endif - return CipherFactory.CreateCipher(context, encryptionAlgorithm, macAlgorithm); - } - - public static byte[] Sign(Org.BouncyCastle.Crypto.AsymmetricKeyParameter privateKey, bool client, Version version, HandshakeInfo handshakeInfo, SignatureHashAlgorithm signatureHashAlgorithm, byte[] hash) - { - TlsSigner signer = null; - switch (signatureHashAlgorithm.Signature) - { - case TSignatureAlgorithm.Anonymous: - break; - case TSignatureAlgorithm.RSA: - signer = new TlsRsaSigner(); - break; - case TSignatureAlgorithm.DSA: - signer = new TlsDssSigner(); - break; - case TSignatureAlgorithm.ECDSA: - - signer = new TlsECDsaSigner(); - break; - default: - break; - } - DTLSContext context = new DTLSContext(client, version, handshakeInfo); - Org.BouncyCastle.Crypto.Prng.CryptoApiRandomGenerator randomGenerator = new Org.BouncyCastle.Crypto.Prng.CryptoApiRandomGenerator(); - context.SecureRandom = new Org.BouncyCastle.Security.SecureRandom(randomGenerator); - - signer.Init(context); - if (TlsUtilities.IsTlsV12(context)) - { - SignatureAndHashAlgorithm signatureAndHashAlgorithm = new SignatureAndHashAlgorithm((byte)signatureHashAlgorithm.Hash, (byte)signatureHashAlgorithm.Signature); - return signer.GenerateRawSignature(signatureAndHashAlgorithm, privateKey, hash); - } - else - { - return signer.GenerateRawSignature(privateKey, hash); - } - } - - - internal static byte[] Concat(byte[] a, byte[] b) - { - byte[] c = new byte[a.Length + b.Length]; - Array.Copy(a, 0, c, 0, a.Length); - Array.Copy(b, 0, c, a.Length, b.Length); - return c; - } - - public static void WriteToConsole(byte[] data) - { - Console.Write("0x"); - foreach (byte item in data) - { - byte b = ((byte)(item >> 4)); - Console.Write((char)(b > 9 ? b + 0x37 : b + 0x30)); - b = ((byte)(item & 0xF)); - Console.Write((char)(b > 9 ? b + 0x37 : b + 0x30)); - } - Console.WriteLine(); - } - - public static byte[] GetVerifyData(Version version, HandshakeInfo handshakeInfo, bool client, bool isClientFinished, byte[] handshakeHash) - { - string asciiLabel; - TlsContext context = new DTLSContext(client, version, handshakeInfo); - if (isClientFinished) - asciiLabel = ExporterLabel.client_finished; - else - asciiLabel = ExporterLabel.server_finished; - //return TlsUtilities.PRF_legacy(masterSecret, asciiLabel, handshakeHash, 12); - return TlsUtilities.PRF(context, handshakeInfo.MasterSecret, asciiLabel, handshakeHash, 12); - } - - internal static byte[] GetPSKPreMasterSecret(byte[] otherSecret, byte[] psk) - { - byte[] result = new byte[4 + otherSecret.Length + psk.Length]; - NetworkByteOrderConverter.WriteUInt16(result, 0, (ushort)otherSecret.Length); - Buffer.BlockCopy(otherSecret, 0, result, 2, otherSecret.Length); - NetworkByteOrderConverter.WriteUInt16(result, 2 + otherSecret.Length, (ushort)psk.Length); - Buffer.BlockCopy(psk, 0, result, 4 + otherSecret.Length, psk.Length); - return result; - } - } -} diff --git a/src/DTLS.Net/project.json b/src/DTLS.Net/project.json deleted file mode 100644 index 9adf073..0000000 --- a/src/DTLS.Net/project.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "version": "1.0.21-*", - "title": "DTLS.Net", - "description": "DTLS.Net Class Library", - "authors": [ "Delme Thomas" ], - "packOptions": { - "owners": [ "Imagination Technologies Limited" ], - "tags": [ "" ], - "projectUrl": "https://github.com/CreatorDev/DTLS.Net", - "licenseUrl": "https://github.com/CreatorDev/DTLS.Net/blob/master/LICENSE" - }, - "frameworks": { - "net451": { - "imports": "netstandard1.5", - "frameworkAssemblies": { - "System.Numerics": "4.0.0.0", - "System.Xml": "4.0.0.0" - } - } - }, - "dependencies": { - "BouncyCastle": "1.8.1" - } -} diff --git a/test/TestClient/Properties/AssemblyInfo.cs b/test/TestClient/Properties/AssemblyInfo.cs deleted file mode 100644 index b763b42..0000000 --- a/test/TestClient/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Hewlett-Packard Company")] -[assembly: AssemblyProduct("TestClient")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("ef71b497-e9d0-41d1-aeed-49f5532a4524")] diff --git a/test/TestClient/TestClient.xproj b/test/TestClient/TestClient.xproj deleted file mode 100644 index 3ef0b05..0000000 --- a/test/TestClient/TestClient.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - ef71b497-e9d0-41d1-aeed-49f5532a4524 - TestClient - .\obj - .\bin\ - v4.5.2 - - - - 2.0 - - - diff --git a/test/TestClient/project.json b/test/TestClient/project.json deleted file mode 100644 index a0b05d2..0000000 --- a/test/TestClient/project.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "version": "1.0.0-*", - "buildOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "DTLS.Net": "1.0.18-*", - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.0-rc2-3002702" - } - }, - - "frameworks": { - "net451": { - "imports": "netstandard1.5", - "frameworkAssemblies": { - "System.Numerics": "4.0.0.0", - "System.Xml": "4.0.0.0" - } - } - } -} diff --git a/test/TestServer/Properties/AssemblyInfo.cs b/test/TestServer/Properties/AssemblyInfo.cs deleted file mode 100644 index 2f079d9..0000000 --- a/test/TestServer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,19 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Hewlett-Packard Company")] -[assembly: AssemblyProduct("TestServer")] -[assembly: AssemblyTrademark("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("a5380ce2-6da3-44d2-b495-af167cef7520")] diff --git a/test/TestServer/TestServer.xproj b/test/TestServer/TestServer.xproj deleted file mode 100644 index d02a879..0000000 --- a/test/TestServer/TestServer.xproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - 14.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - a5380ce2-6da3-44d2-b495-af167cef7520 - TestServer - .\obj - .\bin\ - v4.5.2 - - - - 2.0 - - - diff --git a/test/TestServer/project.json b/test/TestServer/project.json deleted file mode 100644 index a0b05d2..0000000 --- a/test/TestServer/project.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "version": "1.0.0-*", - "buildOptions": { - "emitEntryPoint": true - }, - - "dependencies": { - "DTLS.Net": "1.0.18-*", - "Microsoft.NETCore.App": { - "type": "platform", - "version": "1.0.0-rc2-3002702" - } - }, - - "frameworks": { - "net451": { - "imports": "netstandard1.5", - "frameworkAssemblies": { - "System.Numerics": "4.0.0.0", - "System.Xml": "4.0.0.0" - } - } - } -}