I want to implement a simple HTTP Server / Listener in C# which supports HTTPs with a self signed certificate.
Prerequisites
.NET Framework 4.6.1
Console Application
I am using EmbedIO for the Web Server. I've also tried CeenHttpd and Microsofts HttpListener class.
Creating the private / public key
To create a private / public key which I want to use for my X509 certificate, I run the following command in my machine's Linux Subsystem (Ubuntu):
openssl req -new -newkey rsa:1024 -days 365 -nodes -x509 -keyout test.key -out test.cert
To convert (or pack it?) into a pfx-File, I run the following command:
openssl pkcs12 -export -out test.pfx -inkey test.key -in test.cert
Application
This is my Console application's code:
using EmbedIO;
using EmbedIO.Actions;
using EmbedIO.Files;
using System;
using System.IO;
using System.Reflection;
using System.Security.Cryptography.X509Certificates;
namespace EmbedIoTest
{
class Program
{
public static DirectoryInfo GetExecutingDirectory()
{
var location = new Uri(Assembly.GetEntryAssembly().GetName().CodeBase);
return new FileInfo(location.AbsolutePath).Directory;
}
private static WebServer CreateWebServer(string url, int port)
{
var certificate = new X509Certificate2(#"XXX\test.pfx");
var exePath = GetExecutingDirectory();
var server = new WebServer(o => o
.WithMode(HttpListenerMode.EmbedIO)
.WithCertificate(certificate)
.WithAutoRegisterCertificate()
.WithUrlPrefix("https://*:" + port))
// First, we will configure our web server by adding Modules.
.WithStaticFolder("/", exePath.ToString(), true, m =>
{
m.WithDirectoryLister(DirectoryLister.Html).WithoutDefaultDocument().WithContentCaching(false);
})
.WithModule(new ActionModule("/", HttpVerbs.Any, ctx => ctx.SendDataAsync(new { Message = "Error" }))); ;
return server;
}
static void Main(string[] args)
{
var url = "127.0.0.1";
var port = 8080;
if (args.Length > 0)
url = args[0];
using (var server = CreateWebServer(url, port))
{
server.RunAsync();
Console.ReadKey(true);
}
}
}
}
When I run the server as a normal user, I get an error that I need to run the application as administrator to import the certificate.
If I run it as administrator, I get the error:
SSL Certificate add failed, Error: 1312 A specified logon session does not exist. It may already have been terminated.
If I remove the line "WithAutoRegisterCertificate()" from the WebServer instance, the console applications starts. But when I call the endpoint via CURL or Postman, I get no response.
Postman outputs:
Error: Client network socket disconnected before secure TLS connection was established
Curl outputs:
curl: (35) OpenSSL SSL_connect: SSL_ERROR_SYSCALL in connection to 127.0.0.1:8080
Solution
What I need is a simple HTTP Server which supports HTTPS. That's all. But it should run independend of IIS / Apache / nginx etc. Is there a simple way to implement this?
Related
I am trying to set up a local MQTT broker using mosquito image and connect to it with MQTTNet as publisher and subscribe using Dapr MQTT binding. Everything works fine if I am using anonymous mode (both in Docker self-hosted and in K8S). But we need to use SSL... and here things stopped working. And I am literally out of ideas.
Anyone done this setup already?
I am following this guide for creating certificates: Mosquito SSL setup
This is my broker Dockerfile:
FROM eclipse-mosquitto:latest
COPY ./mqtt/mosquitto/mosquitto.conf /mosquitto/config/mosquitto.conf
COPY ./mqtt/mosquitto/certificates /mosquitto/certs
COPY ./mqtt/mosquitto/certificates /mosquitto/ca_certificates
and mosquitto.conf file:
listener 8883
protocol mqtt
listener 9001
protocol websockets
allow_anonymous false
cafile ./mosquitto/certs/ca.crt
keyfile ./mosquitto/certs/server.key
certfile ./mosquitto/certs/server.crt
require_certificate true
use_identity_as_username true
tls_version tlsv1.2
Broker is starting fine:
2023-01-02 23:44:16 1672699456: mosquitto version 2.0.15 starting
2023-01-02 23:44:16 1672699456: Config loaded from /mosquitto/config/mosquitto.conf.
2023-01-02 23:44:16 1672699456: Opening ipv4 listen socket on port 8883.
2023-01-02 23:44:16 1672699456: Opening ipv6 listen socket on port 8883.
2023-01-02 23:44:16 1672699456: Opening websockets listen socket on port 9001.
2023-01-02 23:44:16 1672699456: mosquitto version 2.0.15 running
Now, I am trying to use MQTTNet library and I wrote a simple c# console app:
using MQTTnet;
using MQTTnet.Client;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.Json;
var caCert = new X509Certificate2("ca.crt");
var clientCert = new X509Certificate2("client.pfx", "password");
var url = "localhost";
var factory = new MqttFactory();
var client = factory.CreateMqttClient();
var options = new MqttClientOptionsBuilder()
.WithTcpServer(url, 8883)
.WithClientId("Device1")
.WithTls(new MqttClientOptionsBuilderTlsParameters
{
UseTls = true,
SslProtocol = System.Security.Authentication.SslProtocols.Tls12,
CertificateValidationHandler = (certContext) =>
{
X509Chain chain = new X509Chain();
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
chain.ChainPolicy.RevocationFlag = X509RevocationFlag.ExcludeRoot;
chain.ChainPolicy.VerificationFlags = X509VerificationFlags.NoFlag;
chain.ChainPolicy.VerificationTime = DateTime.Now;
chain.ChainPolicy.UrlRetrievalTimeout = new TimeSpan(0, 0, 0);
chain.ChainPolicy.CustomTrustStore.Add(caCert);
chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
var x5092 = new X509Certificate2(certContext.Certificate);
return chain.Build(x5092);
},
AllowUntrustedCertificates = true,
Certificates = new List<X509Certificate2>
{
clientCert, caCert
},
})
.Build();
await client.ConnectAsync(options);
var message = new MqttApplicationMessageBuilder()
.WithTopic("sensor/reporting")
.WithPayload(Encoding.UTF8.GetBytes("test"))
.Build();
await client.PublishAsync(message);
And I am not able to connect with client error:
MQTTnet.Exceptions.MqttCommunicationException: ' Received an unexpected EOF or 0 bytes from the transport stream.'
And server error:
2023-01-02 23:47:00 1672699620: New connection from 172.19.0.1:37912 on port 8883.
2023-01-02 23:47:00 1672699620: Client disconnected due to protocol error.
Tried different options and never succeded.
On the subscriber side, I am following this guide: Dapr MQTT Binding with below config file:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: sensorreporting
spec:
type: bindings.mqtt
version: v1
metadata:
- name: url
value: ssl://localhost:8883
- name: topic
value: sensor/reporting
- name: consumerID
value: "{uuid}"
- name: caCert
value: -----BEGIN CERTIFICATE-----\nMIIEGzCCAwOgAwIBAgIUYbZRJpxF3knVBs4A9FIc9KU6YskwDQYJKoZIhvcNAQEL\nBQAwgZwxCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdBbGJlcnRhMRAwDgYDVQQHDAdD\nYWxnYXJ5MRMwEQYDVQQKDAptQ2xvdWRDb3JwMRYwFAYDVQQLDA1DZXJ0QXV0aEFk\nbWluMQ0wCwYDVQQDDARhZGNhMS0wKwYJKoZIhvcNAQkBFh5taWNoYWwua29zb3dz\na2lAbWNsb3VkY29ycC5jb20wHhcNMjMwMTAyMjE0MzU5WhcNMjgwMTAyMjE0MzU5\nWjCBnDELMAkGA1UEBhMCQ0ExEDAOBgNVBAgMB0FsYmVydGExEDAOBgNVBAcMB0Nh\nbGdhcnkxEzARBgNVBAoMCm1DbG91ZENvcnAxFjAUBgNVBAsMDUNlcnRBdXRoQWRt\naW4xDTALBgNVBAMMBGFkY2ExLTArBgkqhkiG9w0BCQEWHm1pY2hhbC5rb3Nvd3Nr\naUBtY2xvdWRjb3JwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAMxZASmaTBj+8nVnQwngdjQ3632AVforWdZWSW7a/Z9mhlCis8Lmg/B7Hun9NUh3\nlwg3GxB9RN0K3A+aeHObWfSUl+R1NiTVAMWh+CtUVibjWnDJGk+TNQ9Drq5Lh/iX\nNPc2ztUm+iaFyWdXcthWjeYqsnLD4NHbD0470F4mNidg93cPvB66c0Eam01pAAkR\nQ/jUU0W8gncN3SEHc/FAUahGp1xZzxWhawBAr/oa7xjDMZsz4cLBHjnUH/wNuTrZ\nxQ7g/ArO9DsDaITj7+tzKvOLkCza3LzjW7Ye19XL5l9DisX3xBNCeERIIdndwkOm\ndkEif6QIMgZjaYyyMH6JSsECAwEAAaNTMFEwHQYDVR0OBBYEFDDUsLcvER/gEJgl\nstJ3VutBQ/t+MB8GA1UdIwQYMBaAFDDUsLcvER/gEJglstJ3VutBQ/t+MA8GA1Ud\nEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBALzcZ32VWo37Da5wfFmONo1I\n+bnnP4dc6i90/6MVuLoco6nt63XE+DwL53Ib8tPYVMssKCLOBCI+y+tRtpIAIF+y\ntg41SP5iLIU4eV4rjzdd3iirZOavvcx2cLVfMRHFVr1/8V5o4LaQOpiwVycndcHY\noRTXW6h49YpZt914oEwezSRBrN5h8Rc4cJB/alVpj/2FMq0+C6qQmgJ56xLT9Yu+\nAFz2X4zoFX69WsGm+h/cOfrMjqdR96UoS8cUgEjeNPZCxrZLWGEvphnjmjCom+SQ\nJ+qvQQBCGlNW6Hajd6yBybynB4ImwsqySlWYuX/JwfCDxq1rt++lWjha7hzGSdY=\n-----END CERTIFICATE-----
- name: clientCert
value: -----BEGIN CERTIFICATE-----\nMIIDwDCCAqgCFA7Zd6l6GgZYMtdtTwKHM7b3jn0HMA0GCSqGSIb3DQEBCwUAMIGc\nMQswCQYDVQQGEwJDQTEQMA4GA1UECAwHQWxiZXJ0YTEQMA4GA1UEBwwHQ2FsZ2Fy\neTETMBEGA1UECgwKbUNsb3VkQ29ycDEWMBQGA1UECwwNQ2VydEF1dGhBZG1pbjEN\nMAsGA1UEAwwEYWRjYTEtMCsGCSqGSIb3DQEJARYebWljaGFsLmtvc293c2tpQG1j\nbG91ZGNvcnAuY29tMB4XDTIzMDEwMjIxNTcwMVoXDTIzMTIyODIxNTcwMVowgZsx\nCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdBbGJlcnRhMRAwDgYDVQQHDAdDYWxnYXJ5\nMRMwEQYDVQQKDAptQ2xvdWRDb3JwMRIwEAYDVQQLDAlhZC1jbGllbnQxEDAOBgNV\nBAMMB2RldmljZTExLTArBgkqhkiG9w0BCQEWHm1pY2hhbC5rb3Nvd3NraUBtY2xv\ndWRjb3JwLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOZ2d3jm\n240jQ9JdTAoAEe/LaoFD+0q7TisXLeHBruCZWjMCbiqinT+GtvyhOvNVVJk8/0jH\n1pTkAIads1hIqve6AUNinrZd9LRbW8CNeESz+w29GcOcdZ9fMsQf42PqHd+Y8Aes\nF/2TSU9Qu+dVpplrdHOfz5WjmC88/AD9btMDrrJQOhi4MFD8Buy4S5Lrw4ZRQ4be\n72hHAuD3nVT+/WS9EJtVSANHaIHsOPDmyJAPFVS6wWZRAHv5BEf5D/UtjmGg3VRn\nGN2krK1/MLMSv20kjePi7dErOtAE1Q2fsvEfs0zko3/qrGZlELVlxKqYgnAMfY2w\nsVf8sGvTz9sJIKkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAc/+wE8Efgmi1GB5G\nSlPpFbDmM+pAXm7cAbELTkQK4i70TZ4R7aRS9QulxSxL1MwpHkyQqvW9bN0s+WtX\nUqh3ERyXCyeuOc6KpskROryyCD03rL2j83KIeTvbLSwsx3gwzE0nBy336Y2A1fYT\nJVkYUhi4Gh9LqSovw8yn+O/DjGhzfBPo1MaPZihtVGmTlhvY9ypUsefggC+FE8E8\n8UmvesY7H+/h5TammDoHTFBupQG9JIx76DZJFQlyyGGanttfBooya4ZLzpZ+zmeW\nFOvz+RmekQzjt+Jrtrzv1zkyrhFB129kr9/cNzZBtR2Hte2ezSgmPHFjIPZ0Z4ZC\nTW47cw==-----END CERTIFICATE-----
- name: clientKey
value: -----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA5nZ3eObbjSND0l1MCgAR78tqgUP7SrtOKxct4cGu4JlaMwJu\nKqKdP4a2/KE681VUmTz/SMfWlOQAhp2zWEiq97oBQ2Ketl30tFtbwI14RLP7Db0Z\nw5x1n18yxB/jY+od35jwB6wX/ZNJT1C751WmmWt0c5/PlaOYLzz8AP1u0wOuslA6\nGLgwUPwG7LhLkuvDhlFDht7vaEcC4PedVP79ZL0Qm1VIA0dogew48ObIkA8VVLrB\nZlEAe/kER/kP9S2OYaDdVGcY3aSsrX8wsxK/bSSN4+Lt0Ss60ATVDZ+y8R+zTOSj\nf+qsZmUQtWXEqpiCcAx9jbCxV/ywa9PP2wkgqQIDAQABAoIBAQDP28dztxwMFuNj\nx5v+ZQPIeHot7oemZnthJ/3M4Sh+EDInUajVMWeMVU+TWUPXFn4/26EQHpVuIppK\nz89i79+roQrkoP0u1F0RkliVucLgjEgBoy2qnOIFhRI/i9dGVXDuK31KHjBhF8eG\nDvX69uhU9XLJmjja6Psol+NebTXYgIISUz0S39KGqH3BZ9IcRre/peNDh4LqUot9\n+Wmrj/4kIgwC2FXLWw5Bz5wH4cvZbrSrf+p4jf8MZehBBTlkJ2270aEwU2Di+rDx\nS4o1rzDEB3FO6eoDJk+vxseZhqUjAX7Vm2HDZhEM+y1rXuOXY11ya2phIA7Y4YzX\nBuXvNQKBAoGBAP8PI4wk8XjVt5mD6KUbvPzcmEtTG43PrTKh9vXdsP9bkW8+RUEp\npwpguSxPYCXRGSl4A3Ava/8uT8grAx1978LY7l65uCK9EUTdYs5a3BrjhxBVE3Bj\np/e3VSmE8qD1ixlnfcRUf0Dv8CrivKmW4Lz226A3hS6AlWfzI9amEfG5AoGBAOdQ\nGcKSUijcNkASud4VZyOqNqjKtj5SKx1HblnOq7HERblPW53wD8Mg9jeQ8X7Flaox\n52m1W3EcO1VVLveQ6FYsBXVz+9FwHblztizVlty48XmzpQDbAL1xI+G0WT7cpDt8\nDdnlOmZX4hxBsmrkOFz/gP4yn6sL0u0wbRTk995xAoGAcBe1Jaguv04djEgefEF+\ngxpni+MQXviAQ5pOsKsnWHJjriINyZ+Gm9b6SnDv7m7AwirOSAVvTwyJX40Xp2Rr\ndJRl3hd8xzeUWVF6VPo1dVO9Tf41ttT1Qra9pKua/gYrhZSn/xqrelx4jkBrbZSz\nXBiZWQZNb6xu/OosO+9sP3ECgYEA3KoVaQCdUE2Dk2xJ1Asm8WcX7b40TQ+mAbB7\nHUGDmXpb6YRDKlAxOTzgpfGn8AAd3tbspHNWYHlGQQmaXKHogwxLyNh0ikAimyA/\n0lWQLdBgzHEMH9zMv+yHBnI+ETH7mqOlsxByvd9o3PvvcPl2q4EzVUyF9W66MXvZ\nE+26aIECgYBtDK+8hffO3N1yXW+tMFuCbbzMPrPJC5o4VII8pm+oNcsvW1Ao9kpZ\nL7yVVJCozo0omvuY2ohVchiQ5jC1nxd17Xa0DuIrKgtcEmpoae16e2h7kcSjv63y\nbKEEUIKRyWfhx6iJb8o03lq1UUxRDhaB5leiUUddibJyhh7EDfCHfQ==\n-----END RSA PRIVATE KEY-----
and dapr sidecar is failing with following error:
mqtt-sample-mqtt-api-dapr-1 | time="2023-01-02T23:19:05.428410597Z" level=fatal msg="process component sensorreporting error: [INIT_COMPONENT_FAILURE]: initialization error occurred for sensorreporting (bindings.mqtt/v1): mqtt binding error: invalid ca certificate" app_id=mqtt-api instance=2c64804e20f1 scope=dapr.runtime type=log ver=1.9.5
mqtt-sample-mqtt-api-dapr-1 exited with code 1
I do not know where I am making mistake. I am going to test that on AKS now (maybe the problem is with running it locally? Anonymous mode is working with AKS).
I was able to set up the whole thing without SSL, but need this to go to prod.
The TLS certificate setup is per listener, so if you want both the listener on port 8883 and the Websocker listener on port 9001 to use TLS then you need to specify the certificates twice e.g.
listener 8883
protocol mqtt
cafile ./mosquitto/certs/ca.crt
keyfile ./mosquitto/certs/server.key
certfile ./mosquitto/certs/server.crt
require_certificate true
use_identity_as_username true
tls_version tlsv1.2
listener 9001
protocol websockets
allow_anonymous false
cafile ./mosquitto/certs/ca.crt
keyfile ./mosquitto/certs/server.key
certfile ./mosquitto/certs/server.crt
tls_version tlsv1.2
You also need to be very careful about requiring a client certificate for the websocker listener and using it as a the username, because if you are accessing from a Web Browser it is VERY tricky to set up client certificates. Hence I have removed that requirement from the WebSocket listener
You have the listener on port 8883 configured to use websockets; you appear to be connecting using plain MQTT over TCP, not over websockets.
Your client needs to use the same protocol as the broker is configured for on the port the client connects to.
Try commenting out the websockets line in the mosquitto config file, restarting the broker and connecting again.
I use an OData service with an C# ASP.NET Core 3.1 service inside a docker container from SAP with a customer self-signed certificate.
In the meantime I have tried a thousand things, but the error persists.
System.InvalidOperationException: An error occurred while processing
this request. mdt2oowvsap_1 | --->
System.Data.Services.Client.DataServiceTransportException: The SSL
connection could not be established, see inner exception. The remote
certificate is invalid according to the validation procedure.
Even the unsafe solutions like using HttpClientHandler.ServerCertificateCustomValidationCallback with direct return true did not change anything.
public MyService()
{
:
handler = new HttpClientHandler()
{
Credentials = new NetworkCredential(Username, Password, Domain),
PreAuthenticate = true,
ServerCertificateCustomValidationCallback = (message, cert, chain, sslPolicyErrors) =>
{
if (sslPolicyErrors == SslPolicyErrors.None)
{
logger.LogDebug($"No SSL policy errors!");
return true; //Is valid
}
logger.LogDebug($"Get certificate hash: {cert.GetCertHashString()}");
// From: https://stackoverflow.com/questions/2675133/c-sharp-ignore-certificate-errors
if (!String.IsNullOrEmpty(certificateHash) && cert.GetCertHashString().Equals(certificateHash))
{
// Get hash string via: openssl s_client -connect <host>:<port> < /dev/null 2>/dev/null | openssl x509 -fingerprint -noout -in /dev/stdin
// see: https://stackoverflow.com/questions/5164804/get-certificate-fingerprint-of-https-server-from-command-line
logger.LogDebug($"Using certificate hash: {certificateHash}");
return true;
}
return false;
},
UseCookies = true,
CookieContainer = cookieContainer
};
String[] files = Directory.GetFiles("./certs/", "*.*", SearchOption.TopDirectoryOnly);
logger.LogInformation($"Found {files.Length} certificate files");
// see: https://stackoverflow.com/questions/40014047/add-client-certificate-to-net-core-httpclient
foreach (string cfile in files)
{
try
{
logger.LogDebug($"Try adding {cfile} as trusted client certificate...");
handler.ClientCertificates.Add(new X509Certificate2(Path.GetFullPath(cfile)));
}catch(Exception e)
{
logger.LogInformation($"Exception while adding certificate file {cfile} to 'ClientCertificates'");
logger.LogError(e.ToString());
}
}
httpClient = new HttpClient(handler);
:
}
The last attempt was to download the certificate and give it to the HttpClientHandler using ClientCertificates.Add. Without success.
Using curl, passing this certificate file works.
$> curl --location --request GET 'https://customer.de:1234/sap/opu/odata/something/useful_srv' \
--header 'Authorization: Basic ABCDEFGHIJKLMNOPQRST='
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
:
$> echo -n | openssl s_client -connect customer.de:1234 -servername customer.de | \
openssl x509 > /full/path/to/customer.cert
depth=0 CN = customer.de
verify error:num=18:self signed certificate
verify return:1
depth=0 CN = customer.de
verify return:1
DONE
$>
$> curl --location --cacert '/full/path/to/customer.cert' --request GET \
'https://customer.de:1234/sap/opu/odata/something/useful_srv' \
--header 'Authorization: Basic ABCDEFGHIJKLMNOPQRST='
<?xml version="1.0" encoding="utf-8"?><app:service xml:lang="de" xml:base="https:blablabla.../></app:service>
$> _
Does anyone have another idea?
Solutions viewed (incomplete):
c-sharp-ignore-certificate-errors
add-client-certificate-to-net-core-httpclient
allowing-untrusted-ssl-certificates-with-httpclient
how-do-i-add-a-ca-root-certificate-inside-a-docker-image
the-ssl-connection-could-not-be-established
c-sharp-core-3-1-getting-error-message-the-ssl-connection-could-not-be-establ
the-ssl-connection-could-not-be-established-between-webapp-and-webapi-asp-core
how-to-fix-the-ssl-connection-could-not-be-established-see-inner-exception-w
Thanks in advance.
The solution to the problem was to make the "self-signed" certificate available to the Docker container or the operating system it contains (Ubuntu) and provide it with
cp certs/customer.cert /usr/local/share/ca-certificates/customer.crt &&
update-ca-certificates
Now the communication works over SSL.
I would like to add to Buckaroo Banzai's answer that for others running .NET applications in a docker container, the package update-ca-certificates might not even be installed by default.
Get shell access by executing this command:
sudo docker exec -it containerName /bin/bash
And execute this to update package lists, install and run update-ca-certificates:
apt update && \
apt install -y ca-certificates && \
update-ca-certificates
Now i can communicate with my(and others) web api again from my .NET application running inside the container.
To make this permanent you should add this snippet to your dockerfile for the image used before the ENTRYPOINT.
RUN \
apt update && \
apt install -y ca-certificates && \
update-ca-certificates
Find a great explanation to why this issue occurs and get a better understanding of how Certificate Authority works here:
What is CA certificate, and why do we need it?
question: with minio sdk,I have error:
MinIO API responded with message=Connection error: The SSL connection could not be established, see inner exception.. Status code=0, response=The SSL connection could not be established, see inner exception., content=
my Answer:
I registed self-signed certificate:
Import-Certificate -FilePath “public.crt” -CertStoreLocation 'Cert:\LocalMachine\Root'
system echo:
PSParentPath:Microsoft.PowerShell.Security\Certificate::LocalMachine\Root
Thumbprint Subject
E021FFABABAF32318D31BB18867F3BFAB788FFC0 OU=BETVSYS\andy#andy-tp (andy), O=Certgen Development
so problem resolved. don't change any code.
ref link:
1 https://github.com/minio/certgen
2 https://github.com/minio/minio-go/issues/1000#issuecomment-550262204
I have a Mosquitto server configured to use MQTT over TLS, using the following configuration, with certificates and keys generated through certbot:
user mosquitto
listener 1883 localhost
listener 8883
cafile /etc/letsencrypt/live/my.mqtt.domain/chain.pem
keyfile /etc/letsencrypt/live/my.mqtt.domain/privkey.pem
certfile /etc/letsencrypt/live/my.mqtt.domain/cert.pem
I'm having trouble with the paho python client and mosquitto-clients (mosquitto_sub and mosquitto_pub), whereas I have no trouble at all using the M2MQTT client in C# or MQTT.fx GUI client (which uses Paho Java client).
The following is my python code:
import paho.mqtt.client as mqtt
import ssl
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
# chain.pem is the exact same file of the mosquitto configuration
# /etc/letsencrypt/live/my.mqtt.domain/chain.pem
client.tls_set(ca_certs="chain.pem", certfile=None, keyfile=None,
cert_reqs=ssl.CERT_REQUIRED, tls_version=ssl.PROTOCOL_TLSv1_2, ciphers=None)
client.connect("my.mqtt.domain", 8883, 60)
And the following is the error I get trying to run this code:
Traceback (most recent call last):
File "subscriber.py", line 26, in <module>
client.connect("my.mqtt.domain", 8883, 60)
File "venv\lib\site-packages\paho\mqtt\client.py", line 839, in connect
return self.reconnect()
File "\venv\lib\site-packages\paho\mqtt\client.py", line 994, in reconnect
sock.do_handshake()
File "C:\Program Files\Python3\lib\ssl.py", line 1108, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get issuer certificate (_ssl.c:1045)
while on the server side I get the following:
1540452676: OpenSSL Error: error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
1540452676: OpenSSL Error: error:140940E5:SSL routines:ssl3_read_bytes:ssl handshake failure
I would have thought of a configuration error server side, but if I try to use a C# client, with M2MQTT, I have no problem at all:
MqttClient client = new MqttClient("my.mqtt.domain",
MqttSettings.MQTT_BROKER_DEFAULT_SSL_PORT,
true,
new X509Certificate("chain.pem"),
null,
MqttSslProtocols.TLSv1_2);
byte code = client.Connect(new Guid().ToString());
Console.WriteLine(code);
var message = "message";
client.Publish("test", Encoding.UTF8.GetBytes(message), 2, true);
and, all the same, no issue at all with Mqtt.fx:
All the same, trying
openssl s_client -connect my.mqtt.domain:8883 -CAfile /etc/letsencrypt/live/my.mqtt.domain/chain.pem
works fine, with no error and return code 0 for the verification.
Any help is welcome.
certificate has some thing error;
Perhaps python make a strict check
when you use openssl s_client, did you unstand all the message which s_client echoed.
I have meet some trouble with test ssl communication, finnally, I found the certifacte
has wrong time like "not before" or "not after" etc error,
I am trying to use PushSharp to send a push notification to my app. I have two Apple accounts... one is a regular account, and the other is an Enterprise account. I have a developer certificate on the regular account that works, but both my development and distribution certificates fail to work from the Enterprise account. I get an Authentication Exception..
A call to SSPI failed, see inner exception.
Inner Exception:
[System.ComponentModel.Win32Exception]: {"An unknown error occurred while processing the certificate"}
This occurs in this code of PushSharp (I didn't comment the line out):
try
{
stream.AuthenticateAsClient(this.appleSettings.Host, this.certificates, System.Security.Authentication.SslProtocols.Ssl3, false);
//stream.AuthenticateAsClient(this.appleSettings.Host);
}
catch (System.Security.Authentication.AuthenticationException ex)
{
throw new ConnectionFailureException("SSL Stream Failed to Authenticate as Client", ex);
}
Here is the code from my test project:
public static void SendPingToApple()
{
try
{
var devicetoken = "mytoken";
var appleCert = File.ReadAllBytes(AssemblyPathName + #"\Resources\DistPrivKey1.p12");
var push = new PushBroker();
push.RegisterAppleService(new ApplePushChannelSettings(IsProduction, appleCert, "password"));
push.QueueNotification(new AppleNotification()
.ForDeviceToken(devicetoken.ToUpper())
.WithAlert("Test Notification"));
push.StopAllServices();
}
catch (Exception ex)
{
throw;
}
}
Convert your ssl certificates to pem format using following commands
openssl pkcs12 -in yourP12File.pfx -nocerts -out privateKey.pem
openssl pkcs12 -in yourP12File.pfx -clcerts -nokeys -out publicCert.pem
Then run following command to ensure that there is no issue with your certificate or network connection.
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert
YourSSLCertAndPrivateKey.pem -debug -showcerts -CAfile "Entrust.net
Certification Authority (2048).pem"
You should download Entrust certificate and convert it to pem as APNS certificates are signed by Entrust.
I'm trying to authenticate myself against WebService using my client certificate, but, for some reasons (I explain), I don't want to load certificate from store, rather read it from disc.
The following:
// gw is teh WebService client
X509Certificate cert = new X509Certificate(PathToCertificate);
_gw.ClientCertificates.Add(ClientCertificate());
ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true;
_gw.DoSomeCall();
returns always 403 - the Service doesn't authorize me. But, when I save that certificate into CertStore, it works. (As stated in MSDN.)
Is it possible to use certificate not in store?
(the reason is, that I got windows service(client) sometimes calling webservice(server), and after unspecified amount of time the service 'forgets' my certificates and doesnt authorize against server, with no apparent reason)
What type of file is PathToCertificate? If it's just a .cer file, it will not contain the private key for the certificate and trying to use that certificate for SSL/TLS will fail.
However, if you have a PKCS7 or PKCS12 file that includes the public and private key for the certificate, your code will work (you might need to use the overload that takes a password if the private key has one).
To test this, I went to http://www.mono-project.com/UsingClientCertificatesWithXSP and created my client.p12 file following those instructions. I also created a simple HTTPS server using HttpListener for testing.
Then I compiled the following program into 'client.exe' and run like:
client.exe https://<MYSSLSERVER>/ client.p12 password
where client.p12 is the PKCS12 file generated before and 'password' is the password I set for the private key of the certificate.
using System;
using System.IO;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Text;
public class HttpWebRequestClientCertificateTest : ICertificatePolicy {
public bool CheckValidationResult (ServicePoint sp, X509Certificate certificate,
WebRequest request, int error)
{
return true; // server certificate's CA is not known to windows.
}
static void Main (string[] args)
{
string host = "https://localhost:1234/";
if (args.Length > 0)
host = args[0];
X509Certificate2 certificate = null;
if (args.Length > 1) {
string password = null;
if (args.Length > 2)
password = args [2];
certificate = new X509Certificate2 (args[1], password);
}
ServicePointManager.CertificatePolicy = new HttpWebRequestClientCertificateTest ();
HttpWebRequest req = (HttpWebRequest) WebRequest.Create (host);
if (certificate != null)
req.ClientCertificates.Add (certificate);
WebResponse resp = req.GetResponse ();
Stream stream = resp.GetResponseStream ();
StreamReader sr = new StreamReader (stream, Encoding.UTF8);
Console.WriteLine (sr.ReadToEnd ());
}
}
Let me know if you want me to upload the server code and the certificates used on both sides of the test.
The potential problem could be caching of SSL sessions (Schannel cache). Only first request negotiates the SSL handshake. Subsequent requests will use the same session ID and hope that the server accept it. If the server clears the SessionId, the requests will fail with 403 error. To disable local ssl session caching (and force SSL negotiation for each request) you have to open windows registry folder:
[HKEY_LOCAL_MACHINE][System][CurrentControlSet][Control][SecurityProviders][SCHANNEL]
and add the key named ClientCacheTime (DWORD) with value 0.
This issue is covered here:
http://support.microsoft.com/?id=247658
You have the potential for at least two problems...
First...
Your client certificate file cannot contain a private key unless it's accessed with a password. You should be using a PKCS #12 (*.pfx) certificate with a password so that your client has access to the private key. You client code will have to provide the password when opening the certificate as others have already posted. There are several ways to create this, the easiest is to use the following command-line to first generate the certificate, then use the MMC certificate manager to export the certificates private key:
Process p = Process.Start(
"makecert.exe",
String.Join(" ", new string[] {
"-r",// Create a self signed certificate
"-pe",// Mark generated private key as exportable
"-n", "CN=" + myHostName,// Certificate subject X500 name (eg: CN=Fred Dews)
"-b", "01/01/2000",// Start of the validity period; default to now.
"-e", "01/01/2036",// End of validity period; defaults to 2039
"-eku",// Comma separated enhanced key usage OIDs
"1.3.6.1.5.5.7.3.1," +// Server Authentication (1.3.6.1.5.5.7.3.1)
"1.3.6.1.5.5.7.3.2", // Client Authentication (1.3.6.1.5.5.7.3.2)
"-ss", "my",// Subject's certificate store name that stores the output certificate
"-sr", "LocalMachine",// Subject's certificate store location.
"-sky", "exchange",// Subject key type <signature|exchange|<integer>>.
"-sp",// Subject's CryptoAPI provider's name
"Microsoft RSA SChannel Cryptographic Provider",
"-sy", "12",// Subject's CryptoAPI provider's type
myHostName + ".cer"// [outputCertificateFile]
})
);
Second...
Your next problem is going to be server-side. The server has to allow this certificate. You have the right logic, but on the wrong side of the wire, move this line to the web server handling the request. If you cannot, you must then take the '.cer' file saved above to the server and add it to the server computer's trust list:
ServicePointManager.ServerCertificateValidationCallback = (a,b,c,d) => true;
Do you need a password for the certificate? If so, there is a field for it in the constructor.
X509Certificate cert = new X509Certificate(PathToCertificate,YourPassword);