MQTTnet icon indicating copy to clipboard operation
MQTTnet copied to clipboard

Using encrypted TCP and WebSockets together

Open leemorton opened this issue 1 year ago • 5 comments

Describe the bug

Hello. I am trying to spawn a server which offers both encrypted TCP and encrypted Web Socket protocols.

I can get this to work fine when i relax the TCP protocol to unencrypted using WithDefaultEndpoint(), however cannot get it to work using WithEncryptedEndpoint();

The following error occurs, using both MQTTx and mosquito_sub commands to connect, supplying the correct certificates. The supplied client certificates are working through the web socket endpoint without any issue.

dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[14]
      Connection id "0HN0O7K6QU4G7" communication error.
      MQTTnet.Exceptions.MqttProtocolViolationException: CONNECT packet must have at least 7 bytes.
         at MQTTnet.Formatter.MqttPacketFormatterAdapter.ParseProtocolVersion(ReceivedMqttPacket receivedMqttPacket)
         at MQTTnet.Formatter.MqttPacketFormatterAdapter.DetectProtocolVersion(ReceivedMqttPacket receivedMqttPacket)
         at MQTTnet.AspNetCore.ReaderExtensions.TryDecode(MqttPacketFormatterAdapter formatter, ReadOnlySequence`1& input, MqttPacket& packet, SequencePosition& consumed, SequencePosition& observed, Int32& bytesRead)
         at MQTTnet.AspNetCore.MqttConnectionContext.ReceivePacketAsync(CancellationToken cancellationToken)
         at System.IO.Pipelines.Pipe.GetReadResult(ReadResult& result)
         at System.IO.Pipelines.Pipe.GetReadAsyncResult()
         at Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.Internal.SocketConnection.DoSend()
dbug: Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets[8]
      Connection id "0HN0O7K6QU4G7" sending RST because: "CONNECT packet must have at least 7 bytes."

Which component is your bug related to?

  • Server

To Reproduce

Steps to reproduce the behavior:

  1. Using this version of MQTTnet '4.3.3.952'.
  2. Run the below dotnet 8.0 code (also attached as a csproj)
  3. Try to connect using mosquitto_sub -h localhost -p 8883 -t 'sometopic' -v, (no need to supply client cert argument it replicates without it anyway)
  4. See error.

Expected behavior

Connection to the TCP endpoint using encryption

Code example

// Base64 Test Certs
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Builder;
using MQTTnet.AspNetCore;
using Microsoft.Extensions.Logging;

string rootCertBase64 = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZlekNDQTJNQ0ZDckJWZDQ0dGZxczN0R0hob0ZadHY0RVBKU25NQTBHQ1NxR1NJYjNEUUVCQ3dVQU1Ib3gKQ3pBSkJnTlZCQVlUQWtsRk1RMHdDd1lEVlFRSURBUkRiM0pyTVJZd0ZBWURWUVFIREExTWFYUjBiR1VnU1hOcwpZVzVrTVJBd0RnWURWUVFLREFkRFlYUmhiSGw0TVJRd0VnWURWUVFMREF0RVpYWmxiRzl3YldWdWRERWNNQm9HCkExVUVBd3dUUTJGMFlXeDVlQ0JFWlhabGJHOXdiV1Z1ZERBZUZ3MHlNekE1TURZeE5ESXpNRFZhRncweU9EQTUKTURReE5ESXpNRFZhTUhveEN6QUpCZ05WQkFZVEFrbEZNUTB3Q3dZRFZRUUlEQVJEYjNKck1SWXdGQVlEVlFRSApEQTFNYVhSMGJHVWdTWE5zWVc1a01SQXdEZ1lEVlFRS0RBZERZWFJoYkhsNE1SUXdFZ1lEVlFRTERBdEVaWFpsCmJHOXdiV1Z1ZERFY01Cb0dBMVVFQXd3VFEyRjBZV3g1ZUNCRVpYWmxiRzl3YldWdWREQ0NBaUl3RFFZSktvWkkKaHZjTkFRRUJCUUFEZ2dJUEFEQ0NBZ29DZ2dJQkFLNFl3VDdpYTVialVBakd6cVR0V253eEV0OGVNUUF3MHRsbwoyeXovZW1BNU1HdUQ3d09ibG5DUUI4d0wvR0NaK252TllWYnlYOFQ5T01vKytPVDhIK0duZVVmRHFvdkVFTVJNClNaS1JEWXJOUTRsUURjVXdJWUFvZDgyQ1hMY3FmM2hjbTZwMXRCTUhUZThTKytFanFXZFI1OTFzTHdXa1k3Y2cKODdqRW1LSnhFZUcxY2swUHJ6dGtIby9iaDJiRUdHeTdPM3dnVGhMdkcrWUZRRmlJbHU2ZXBaT0N1MGlQNkVTTgo0Q1g5ZzR1S1BveHp5NlNiampOOE8yekZzeE9RQ01UOXFERWdmb2dreXJpNThmK0Ria2NPYVV4eDhhUnVsZTBFCkxuUi8yd0Yzbk1lUlVtYkU5R05YdGlzVWQ2NGZuQjV0UjBoanBqU3lRVmJEWWRaN045d0N6SHFtMndSSVNEbkgKSmt3d3cxSFR5Vjc2VzZzNjZZVFhlcTdnMllsVFJMeW42MUxhdTZPU1hLN1ZZOGJYRERqVEZnaUF6SlVxdGw2SQpTeWF3V3FRa2UrMCtmUGJ1dmR4TkNYQXROa1R1dkpuQzZFczBlY2M3dmU5UG9UOXByajd2Z0dMUkM5dkhWZklOClFBMDhPaEdLY2VON3RLWDdEcGtueDJDbm5iUnhmZk4xdnl3aVpXbzlMZ0lEWVM5dzJKQUQvd1dGVUdJeXhqM1oKMkM5R0oweCt4djgwcTZCRDJWcnREK3lrM0sybUZIZVBuY1crS3I2eHUxdk92UldxOVZWeXozRHhFVHpSOGhQMQpLL2ZCejhMVGFoTFZ3RmZmcGp3T1RzVWs2S2RpOWpjWjdneXNHZlFVVG9uV2JNZ2VXU0FmZjhVTE93bG03WjUxCnpEWkVNTzJyQWdNQkFBRXdEUVlKS29aSWh2Y05BUUVMQlFBRGdnSUJBSzFSallORWZvbGlzS1BOVEw0a3RmN0UKSi91UWJWenVUWTdhaHBGTUF4djkzNGtWWEF5MVdkSmJsMG1mamV3T3RCdUVYdjVscWUwTnZ1blVrcHpyc1Y4bgpkRVlnM2dUSDc2MmNNRTZPUE14RmpMRlhCeTBXemp5RGJaNTFqZjBWa0JvOGRXclpOM3F3b29VSTNOQzJHdEMxCmFyQkwvdnFhQlUwZWVMOWVIUFB1WkxvMGVRUzBjVk9OQW5yU2xYZEgwcExyTjBWTEk4NTdGNWpzU1lIZld3clMKbFh5eG50Ri9BWjhiT05Eb3JrTm1BTWpsRFV1ZDVXc3B6SW42SWRNWGMyTGhyZ1dFbWdSclB6NTg1WlhsLzlzMgoxMmdOYXFxSmhRUElwUVVuOTB1cU5ZTHRjUkg5N1ROK3UvNXc4REdRQXYycGI3ZXVURE5tVjNFY0dQN091ZnNPClJINSthdzlMK1oyRjVlK0NqeW5tM3M4S1BWSWQ5UE1JMFNMaXVJM282czkza0JYTXJ0MWpGNjN1RXZRTVp0UXIKcFFQRWRRRzZtallFb29mUWpvMFdJK3lzNGU5dUFMdjN6UUsxOVRqNm9FVXg5eWY2dmlVOWx4RkxZRS9qZWNiNwpkT09ROW9JNFRBUi85K3pVaUdqQUdVNHJDd2hDOWFGWVBRTnB3ZERBRTFkZE5uZmkwdFp0VW02eUVMMWo3TnU3CjlTY09XVnl3N3pnd1NuR1RoQ2RsSWJsMDNOZE5jTCtZZDd5R1U3eDh3Slp3Zm1pUEdra201RGVBQVhDMHZkc3MKV3A5bjMyTXdjR3EzWlJRYjRGUGNCN2pGT20rSENvUU5zMWgyMml5RmxacCtJRWpESTFTZmxqVkMvc1lneFFBMQpYVXJoMzdTZFBHWHJla1pZTWhBaAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0t";
string serverCertBase64 = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUZ2VENDQTZXZ0F3SUJBZ0lVZGEvUTBSZ3VtUXA0OEVxemxEVTZCZENic2hjd0RRWUpLb1pJaHZjTkFRRUwKQlFBd2VqRUxNQWtHQTFVRUJoTUNTVVV4RFRBTEJnTlZCQWdNQkVOdmNtc3hGakFVQmdOVkJBY01EVXhwZEhScwpaU0JKYzJ4aGJtUXhFREFPQmdOVkJBb01CME5oZEdGc2VYZ3hGREFTQmdOVkJBc01DMFJsZG1Wc2IzQnRaVzUwCk1Sd3dHZ1lEVlFRRERCTkRZWFJoYkhsNElFUmxkbVZzYjNCdFpXNTBNQjRYRFRJek1UQXhOekE1TVRrMU1sb1gKRFRJNE1UQXhOVEE1TVRrMU1sb3djREVMTUFrR0ExVUVCaE1DU1VVeERUQUxCZ05WQkFnTUJFTnZjbXN4RmpBVQpCZ05WQkFjTURVeHBkSFJzWlNCSmMyeGhibVF4RURBT0JnTlZCQW9NQjBOaGRHRnNlWGd4RkRBU0JnTlZCQXNNCkMwUmxkbVZzYjNCdFpXNTBNUkl3RUFZRFZRUUREQWxzYjJOaGJHaHZjM1F3Z2dJaU1BMEdDU3FHU0liM0RRRUIKQVFVQUE0SUNEd0F3Z2dJS0FvSUNBUUR0Wk9CQ0RKU1RTbHhQYmx1ZGhaOThReG1TQWE4bkxIeW8wTmpEQ0dTQwpucGFNOWo1YldtYmt2dnF3TFpUTDkvRHNtV3FpVGY5aStwT1hkK3QvTzNGUG1CSmhNMGFMN1ZyKzFVdXlqMGJxClJpZ1V3Q1hwR29SL3hHemFXWktnVmtUNWNrOUcydW45RjVBNU1OZmI3dE05dlhER0hLdjAybWt6blVGTTlPenMKSXVrYlFhNjU0d0drSTFTTDVvVnFNdmJ0RTFpaWh2RXhZc1VSSnpjakFaZVZIOThUL3VYNk54UXpZeFlhRGFGego3UkFIdHhEOWl0RGcyVE00K1pReUdVTUdrZlZvM2w5bzJwTFNpK0kxeW8zZXIrVVViUkFnS2t5TDVLOG1PK0NzCm83MWdKWjJPTXdmL2xNcHluNkV3eEVIMkRGOWpJTnBEdy9TM005eUcyMXE1c2M1cW9pOWkvNXVoM0lObnJ3OTEKWWtibjdxa1IvOUIya3J2bVJhaU5TUjZ2VzdhTkZSMmJaWm4weTd1UUhzYTlsY3ZhYnpHS3VzSnE5SHR5eVRyRApJY2JaMzZTNnJYTzQyeWkrNzB3WXl0SjUrbnlVc3ZGMkNlVU5rWWlEVDNteU1lYklqYjd2QUE3WVZ4RW12Y0JrCmx1OU9NRy9lMTVBRE5mdmpHbHlJNkF6Sy9idEJhblA3TkpPblFnQVRVRWpzczlDWXYzWkx6UzVxNEhsWmllWkMKbHh2ODV4OFM5NldDZnpRTXBSUFZocnBCQ2k3amVlNDdRbHlSUFNmdTBEVkMwZS9WbU0zZCt2RVVOWEZlaVpYNwpmRlZ6Rk9uWGtMTjZCZmw5Z0FyTjVHZHE2K2t4NEJEQXpLejR5ZXhQdER4em1DMmtidXQ1YkNWS2N4S2k1M3VkClJRSURBUUFCbzBVd1F6QVRCZ05WSFNVRUREQUtCZ2dyQmdFRkJRY0RBVEFzQmdOVkhSRUVKVEFqZ2dsc2IyTmgKYkdodmMzU0hCSDhBQUFHSEVBQUFBQUFBQUFBQUFBQUFBQUFBQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dJQgpBRGZCdngvRXh0cXNlOXY3NHBJS2ZXWXBpRXhDQTlYQ0JpdGlZNXJwdUlJQVNPSnU5M01GYWtsUUtNakZabWpTCkZxRkRndU9OZzBlOU5lS0NZVVRWeUszVXZZQmI3SHVRd3Y5cWdhdytZS2tjREdMNFdUcFprdW1iaFBITzMvaDcKL1FnVlZVRnRENzVaTS9PZEw3R3FmNTBtMkdBdkFQR2VaNEJaU29ZVDduTklaZnZkL3NTbEZxM2ZPM0pRZk41OApIZUVrVkhhTWVzMUZPRkplL1plUlNDMGZXaWFLbEJieklKUEhkaFlMZFBoZ2ZIL0F5NDNvbjcrYmlWUUJ3QUtECkhrcVZNTlBFVGtiOW42eDRsOWQxMWdFVkVPK085Uis3S2Vncm1NSUErWGMxaWVxdUZNYUJjaWE3OE1sdnU2Z0EKbm1MOUNabzdoRnozWUR5dUFHL1lqQjlKV2huaHNUOGtHSUJSVi8vb3pUR0ZBWDlzd21SREN3Yy9vSGRLaEpucgp2MG41aWp2Q0I2L2g4LzcxdExCL1RicVpsYlc3Vi9FWjYyQ241WVd4V0pvU3BKbCsvN1dpQ3gxbG9PdWJrQWVyCkpFU29SMGV6VWh3SGd6ME9POG1FbTk5Nko4bjVEditOMm82ajlxTmdLaHJFbkVOelo2cFBWOUZsTnh6Zlg3em0KbTBjWmFzTlF0UHlaUGdrRnNvUGZOWVI1MW9pU1RHU1RmOThrbEExZk5hZ3c4YU8xK1hFZFU4WDNCOEdUQy9zbAo0QkFxYUhoRjU5MEYxTzZ0TS9kNm1EbzJSUVZiTWxmZXBwRFR5eTV1c0t0MEJDckRLOFdyRHlIZDJlMUNhWWUzCkxTaUVmUlpiSVBBak84UmJKcGdwM0hGQlFESXNTdSs0M3lYRFQ0TVFQT2VPCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0=";
string serverKeyBase64 = "LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlKS1FJQkFBS0NBZ0VBN1dUZ1FneVVrMHBjVDI1Ym5ZV2ZmRU1aa2dHdkp5eDhxTkRZd3doa2dwNldqUFkrClcxcG01TDc2c0MyVXkvZnc3Smxxb2szL1l2cVRsM2ZyZnp0eFQ1Z1NZVE5HaSsxYS90VkxzbzlHNmtZb0ZNQWwKNlJxRWY4UnMybG1Tb0ZaRStYSlBSdHJwL1JlUU9URFgyKzdUUGIxd3hoeXI5TnBwTTUxQlRQVHM3Q0xwRzBHdQp1ZU1CcENOVWkrYUZhakwyN1JOWW9vYnhNV0xGRVNjM0l3R1hsUi9mRS83bCtqY1VNMk1XR2cyaGMrMFFCN2NRCi9ZclE0Tmt6T1BtVU1obERCcEgxYU41ZmFOcVMwb3ZpTmNxTjNxL2xGRzBRSUNwTWkrU3ZKanZncktPOVlDV2QKampNSC81VEtjcCtoTU1SQjlneGZZeURhUThQMHR6UGNodHRhdWJIT2FxSXZZditib2R5RFo2OFBkV0pHNSs2cApFZi9RZHBLNzVrV29qVWtlcjF1MmpSVWRtMldaOU11N2tCN0d2WlhMMm04eGlyckNhdlI3Y3NrNnd5SEcyZCtrCnVxMXp1TnNvdnU5TUdNclNlZnA4bExMeGRnbmxEWkdJZzA5NXNqSG15STIrN3dBTzJGY1JKcjNBWkpidlRqQnYKM3RlUUF6WDc0eHBjaU9nTXl2MjdRV3B6K3pTVHAwSUFFMUJJN0xQUW1MOTJTODB1YXVCNVdZbm1RcGNiL09jZgpFdmVsZ244MERLVVQxWWE2UVFvdTQzbnVPMEpja1Qwbjd0QTFRdEh2MVpqTjNmcnhGRFZ4WG9tViszeFZjeFRwCjE1Q3plZ1g1ZllBS3plUm5hdXZwTWVBUXdNeXMrTW5zVDdROGM1Z3RwRzdyZVd3bFNuTVNvdWQ3blVVQ0F3RUEKQVFLQ0FnRUF0eXdHL2UvSEZIOWtDc1lVV3M4bjZERytJVEs3ZTNhUUdaSk1MdkRpM1FhUkUrTk02aUF2RklGbgozVmpPWHpQSTZrYldTTFgyUU9FbjBNL3ZIaFUzc1RxZHMvSmtsTU5vV3drcGgzV1dPbDQzdndza05XRUlxNjFjCmNINTg3TXFrSGZWZHhrWlVGYjJBd3lBMDdyYXd1QXJjWVlEdURkZ1pKSUpLU0o4VDBJQi9iVkNaQ1VWbmxzYk0KRGNhcFd2QklKMVd1Sm5vSTBScHRCSGRGeS9VR2lVSTJWcTl2dEVtYmhLc0grc0padWFGSnBTcFVLYzVhcmFQcQpLaVFwZlI2UTRSanVTeVNLYWRWOVJJZzYyMWFYY1NRM2xqTXhKaUI5UDlRTWNXdnlTRU52ZENpU0VZNit0UzZSCnB6QVVxQlJHOFJ0SzNxb1N3QWNMWS9EWVVCWWhRWHFQRWVFeTRwZ0ZQZ3I2TE1BNUlYWkNvWUFSWXozU2JvZ1oKNWZiWGZ2OFNNbXRTTEdLNE82ajc4K3BUU3NNZGN2S2sxaDhUQU9TTDNvQU9yZlhySXY4VTJXL3lLOG9nUDYxNApwMEZhVEd6bjdQTnhPbC80Uzd4TEtqN3VKclR3aTVaSGtHWWZnZFhIc2NvRVdYaXBNZ3VsK2t6T1c3ZTU1RkczCmtHVVlaeFd4RGtCZGNsZjlUZHNkcEk4TWF5OFJnZmlRK3grL0ZIS1dwQVZHaHRTSWhQaWtrZktSK25VeXlreloKQ1dYOTVFRktETVJNRmJHSzlwZU5pQjkxTDZYRE5WeklSTzZWTktmNjRzWVdNVGZpUGR2ekZZaXdYRjN3bGRIKwpNWjlXT2ZYN2k1TitNQ0dtMjBYeEZmTXVYZkZ5NjRtakhucVJJN0djN1ZKM0RjTjBsZ0VDZ2dFQkFQOHo3NW5LCkx4MTBwdUNIcjcvSVZHbHA3bXdwcU9ibCtUK1ZQQUozM3BHam16U2dqb3pwVkZFSmhKTEN2cTROaE9rVnh3UE0KTDVBa2JxVE1KS1RHQ1ROdmtGWXdqaDNFUmI3a2xNZ3dsdGtNS0kyNWN1YXREdzdTZS9DdlVkald2NjR1dHArRQp4dE9MRXBXbEs1Y0d3RFdoZmV3VWZEODZIMitTdVVqZUMwQkplYlZiWG5wSXBwWXhjSUpvY0l4VXlwWVJZb0IrCndFaGE0ZWVDWTBpRmo2ZXdxc0FDbitkOUZSK2k3clJWaHQyRTZ3cnZia1RUMjNyT3BXc21zaDVhOG5DaHhFRFUKWEdpcU1scEpJM0NLaDh1UHRvMmJvTlM0Z0pDZTV1amsrbTlGZFBwY00ydXlUUElJZFdjM3cxSmRjMzZqZmFWcgpTNEIzMHZoVTNtZnRZSlVDZ2dFQkFPNGlzeW9STDhjNGZIWWhRMmQrQ2NUTTBQOEZOSjBKMnQzbXpuYzBkYjJYCkdOejlBZDVudUlPeXJTOERVb1dLRnR0VDVuSGV4bW1jWkFMK0FiSWVmMUQvNHNPc3B3MUJVanhyNldJYm8rMksKYU1hNHhteU5aNlZoV1QzbnRFTTBsUlpRRXF2WktPcW5kSUVKVGp0VGZOUGd6Rk1PRzgrVzZZSDhuT1ZCQ0FOQQpadHlxb3JmZ1M0dHBkd25kUG0zeTFQNXM4Qml1OHFub21oL3BxRHl1MnkrdlRxSTJCUndvNm5CYmdRSVV1UVNWCnNmQzBQK0dNWVhlL3FCNms4VHA4TFNVc3IrZ2FZQ3hYUlZHbnNBZmxUL3FPK1JqcDFGUDk4OURkQlNydXg3RDIKc3V2S2RGbkVBRjFRVmE0WUljbVdSeDBSNkJyZDhndzhoSkJpOXpFRHJmRUNnZ0VCQU5TS041RllmcmJFY1RycwpKbVhOL09jeUR4eEw4ZHdqU2RzM2Vad0FvditlUjJPa0dEU3BHc3pHNVgrbzYwOWYrUUo2WFozL0R0bTRUZUc0CkZ3aVgyZy9aYVZjdTV4MUpXbURxVkRNSnJJZ2xoUnpMaHpNd2pDcm5COHZpNTRKMUQzeU1jUklYYmRPK3JvS3MKNWNuSkdJbFI3dUtRQ1E1TFpPVHlTSmUwUGFDVDBPWkdxeitpaEFMd04raVQvTEFTNmduamZxclBaV3FkTGlrMgpRV09qd0ltRExDSHZ6YWJvV0pCWmpQM3BnUUc2Y2xwUUlBRDRoSUVaMjFDTEVLc1JTWHFlYnlraTg3ZERqOTM3CnJhVkw2bDZSV1JORXVzU095SndwaXR3SjM3eU9GeWR2WkcvY05oTVpFbFlkYmZHSjNPZHFWL2xOaTdyNWtGMjcKcU9MYklxVUNnZ0VBQXlXT1BJWVJuWTVQaHJnVnplNUtic0ZPR2JDVjYyVlA4UksxczdtTHZMK2NZbjh0WVNUNQp1VFBKT2cvUExWaVB5TUlwRDJRa053MEwvVVloKzVxUGtDQnhmS2h4WktseVRyNFdUV2VVR1BWMVFQcjhGRDhpCkdYdFoxSW1WUmpZUnFrUFFtMWk1UTdDR3g1VzU1T3JMZ1hrOCtmUDd4aGgyYVhOUEYzQnVqS3h6TDROSnR5aE4KbDBBRGhLdlp3Vll1SGxhT0xhVlNLNUNaU01hcnBIR2pEOVEvTThHRys4Skdwc2x1d1BwSkg1aGl5NDEyTXFMSwpQdXpYYWVCQUY4ZkFTUGQ0TTViMW9tQmMyQ0ZoSUJtVm52ZjRycTJZVXF2T1p2b2tzVmFLYVBvNWp3Z1QxWVBUCmhXZ2tXYktUNzdmK3BKR3lBWGpoVSt3UXpGK2lhSkZsNFFLQ0FRQU5YNDdGRU5MYTJvOStTbUVSQnI5ajZmakMKSFVHK0hpdVVQbTlhNGVVUEFqQWd6dnVFOHVtMFhOaDFKWWR1ak4zY29hTkZkUjd6Unc3MDR6YkFLZDlxcEVKRwpoa1hRWUU5R3VGc2E4MzZUZ09LQzlSRVhjYkJnMDNKWFRPaDgyU2RFS01DMElvWlpCSXFkZ0pBOStRV2IvWFdxCjcwQlEzZTl3VHppYlYzK0tyWjRBekU1WkR6MHRwQ2JaaWFsMDhPVGdjNlRnNm5QbWVaOGdxMW1FdHhyaEh3SkcKa2dSYkJoVnRxOFl6S1c3ZWUxOUQraloyV3VMc0RZTEVjazlwQlRLN1dGUjA5SXdYTzY0YkNLTWJsN3pYUjJ2QwpnVW0rNFhDMlAraC9oN1RaSjVDdEcyR1NrTXNpYTVFODI0d1Z5WVd5NkZOZ3hXaWozSk1BdlpKYXhEZ1AKLS0tLS1FTkQgUlNBIFBSSVZBVEUgS0VZLS0tLS0=";

// x509 Test Certs
X509Certificate2 rootCert = new X509Certificate2(Convert.FromBase64String(rootCertBase64));
X509Certificate2 serverCert = new X509Certificate2(Convert.FromBase64String(serverCertBase64));
X509Certificate2 serverCertAndKey;
using (RSA rsa = RSA.Create())
{
    // Unpem
    string pem = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(serverKeyBase64));
    const string dashes = "-----";
    int index0 = pem.IndexOf(dashes);
    int index1 = pem.IndexOf('\n', index0 + dashes.Length);
    int index2 = pem.IndexOf(dashes, index1 + 1);
    var unpem = Convert.FromBase64String(pem.Substring(index1, index2 - index1));
    rsa.ImportRSAPrivateKey(unpem, out _);
    serverCertAndKey = serverCert.CopyWithPrivateKey(rsa);
}

var mqttHostedServer = Host.CreateDefaultBuilder([])
    .ConfigureWebHostDefaults(
    webBuilder =>
    {
        webBuilder.ConfigureLogging(logging => logging.SetMinimumLevel(LogLevel.Trace));
        webBuilder
            .UseKestrel(
            o =>
            {
                o.ListenAnyIP(8883, l => l.UseMqtt());
                
                o.ListenAnyIP(443, options => {
                    options.UseHttps(serverCertAndKey);
                });
                
            })
            .ConfigureServices(
                services => {
                    services
                        .AddHostedMqttServer(
                            options => {
                                options.WithoutDefaultEndpoint().WithEncryptedEndpoint()
                                    .WithEncryptedEndpointPort(443)
                                    .WithEncryptionCertificate(serverCertAndKey.Export(X509ContentType.Pfx))
                                    .WithEncryptionSslProtocol(SslProtocols.Tls13)
                                    .WithRemoteCertificateValidationCallback((sender, cer, chain, sslPolicyErrors) =>
                                        {
                                            try
                                            {
                                                if (sslPolicyErrors == SslPolicyErrors.None)
                                                    return true;

                                                if (sslPolicyErrors == SslPolicyErrors.RemoteCertificateChainErrors && chain != null && cer != null)
                                                {
                                                    chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
                                                    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
                                                    chain.ChainPolicy.ExtraStore.Add(rootCert);
                                                    chain.Build((X509Certificate2)cer);
                                                    return chain.ChainElements.Cast<X509ChainElement>().Any(a => a.Certificate.Thumbprint == rootCert.Thumbprint);
                                                }
                                            }
                                            catch { }

                                            return false;
                                        });
                            }
                        );
                    services.AddMqttConnectionHandler();
                    services.AddConnections();
                }
            )
            .Configure(
                app => {
                    app.UseRouting();
                    app.UseEndpoints(
                        endpoints =>
                        {
                            endpoints.MapConnectionHandler<MqttConnectionHandler>(
                                "/mqtt",
                                httpConnectionDispatcherOptions => httpConnectionDispatcherOptions.WebSockets.SubProtocolSelector =
                                    protocolList => protocolList.FirstOrDefault() ?? string.Empty);
                        }
                    );
                    app.UseMqttServer(
                        server =>
                        {
                            server.ValidatingConnectionAsync += eventArgs => { System.Console.WriteLine($"Client '{eventArgs.ClientId}' wants to connect. Accepting!"); return Task.CompletedTask; };
                            server.ClientConnectedAsync += eventArgs => { System.Console.WriteLine($"Client '{eventArgs.ClientId}' connected."); return Task.CompletedTask; };
                        }
                    );
                }
            );

    })
    .Build();

await mqttHostedServer.RunAsync();

mqttnet-tls.zip

leemorton avatar Jan 18 '24 16:01 leemorton