MQTT and SSL/TLS - ssl

I registered for an account on a mqtt server provider.
They provide 3 ports:
port: 1xxxx
ssl port: 2xxxx
websockets(TLS only): 3xxxx
I am publishing and receiving data from port 1xxx.
I would like to add encryption though. The mqtt server provider gives a "shared" subdomain but says:
If you want to use a custom domain for your instance you have to provide your own certificate to use with MQTT+TLS and Websockets. Certificates must be PEM encoded and the privte key unencrypted. Certs are only stored on your dedicated instance. When certs are installed you can point your domain as a CNAME to hairdresser.cloudmqtt.com.
I added a CNAME on my domain panel which I call it (mqtt.mydomain.com) and resolves to the above subdomain.
On my domain panel also I added ssl from letsenrypt(free) to my subdomain mqtt.mydomain.com(which points to mqtt server domain).
After adding the ssl I downloaded a zip file from the domain panel which contains 3 files:
mqtt.mydomain.com.ca
mqtt.mydomain.com.cert
mqtt.mydomain.com.key
I paste the contents of ca file to CA chain, cert file to Certificate and key file to Private key
Saved everything and restarted instance(mqtt server).
Then I tried from my computer:
mosquitto_pub -h "mqtt.mydomain.com" -p 1xxxx -i test1 -u test1 -P pass1 -t mytopics/test1 -m "hi everyone" -d -c
works but since its port 1xxxx its not SSL.
Trying the ssl:
mosquitto_pub -h "mqtt.mydomain.com" -p 2xxxx -i test1 -u test1 -P pass1 -t mytopics/test1 -m "hi everyone" -d -c --cafile C:\Users\CT\Downloads\certs\mqtt.mydomain.com.ca
gives me error on cmd:
OpenSSL Error[0]: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed
Error: A TLS error occurred.
Tried many different commands like passing cert file appart from ca and even key file(which is probably wrong i guess) and I am getting different errors on the server logs like:
OpenSSL Error: error:14094418:SSL routine
s:ssl3_read_bytes:tlsv1 alert unknown ca
OpenSSL Error: error:1408F10B:SSL routines:ssl3_get_record:wrong version number
Client connection from xx.xx.xx.xx failed: error:1408F10B:SSL routines:ssl3_get_record:wrong version number.

Related

Where do I find the ca certificates for mosquitto_sub and pub?

In this article mosquitto_sub with TLS enabled I understand that you need to provide a capath or cafile option to mosquitto_sub (and pub) but I am having trouble figuring out where those files/paths come from.
Back in October I was able to run mosquitto_sub -h mymosquitto.com -p 8883 -v -t 'jim/#' -u <u> -P <pw> --capath ssl/certs from my desktop computer (running Mint 19). That no longer works. I did an apt install ca-certificates and found the .crt files in /usr/share/ca-certificates/mozilla/ but when I used that path, it still gave me: Error: A TLS error occurred.
This is a Ubuntu 18.04 server running Let'sencrypt. I tried to point the --cafile to the chain.pem file which came from:
allow_anonymous false
password_file /etc/mosquitto/pwfile
listener 1883
listener 8883
certfile /etc/letsencrypt/live/mymosquitto.com/cert.pem
cafile /etc/letsencrypt/live/mymosquitto.com/chain.pem
keyfile /etc/letsencrypt/live/mymosquitto.com/privkey.pem
But that didn't work either. Can someone please help me understand what I should be doing?
From the mosquitto_sub man page:
--capath
Define the path to a directory containing PEM encoded CA certificates that are trusted. Used to enable SSL communication.
For --capath to work correctly, the certificate files must have ".crt" as the file ending and you must run "openssl rehash [path to
capath]" each time you add/remove a certificate.
If you want to use a directory of certs you will have to make sure the openssl rehash command mentioned has been run on that directory.
If you want use a file from the letsencrypt --cafile with the fullchain.pem file
I have rethought my situation. Since my certs get regenerated every 3 months or so I'm going to have to redo my apps using the new files so I decided to just go back to rolling my own. I did that using this site: http://www.steves-internet-guide.com/mosquitto-tls/ and I'm back to where I was in October.Thanks to hardillb for the advise.
Jim.

Redis 6 with TLS

I am trying to get Redis 6 (with TLS enabled during compilation, tests after compilation were successful) to work. I am using Lets Encrypt certificate and following configuration:
tls-port 63790
tls-cert-file /etc/letsencrypt/live/myserver.net/cert.pem
tls-key-file /etc/letsencrypt/live/myserver.net/privkey.pem
tls-ca-cert-dir /etc/letsencrypt/live/myserver.net/
tls-auth-clients no
tls-protocols "TLSv1.2 TLSv1.3"
and this client command from localhost
redis-cli --tls --cert /etc/letsencrypt/live/myserver.net/cert.pem --key /etc/letsencrypt/live/myserver.net/privkey.pem --cacert /etc/letsencrypt/live/myserver.net/fullchain.pem -h myserver.net -p 63790 -a password
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
Could not connect to Redis at myserver.net:63790: SSL_connect failed: certificate verify failed
this is output from redis log:
Error accepting a client connection: error:14094418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca
While I am using openssl client with same certificates, i am able to connect and get ping reply from Redis server
No matter if I change
tls-ca-cert-dir /etc/letsencrypt/live/myserver.net/
to
tls-ca-cert
on server side
or
--cacert /etc/letsencrypt/live/myserver.net/fullchain.pem to chain.pem on client side
I tried to all versions of
tls-protocols ""
and change
tls-auth-clients no
to
tls-auth-clients optional
but I am still stuck with same error
OpenSSL version is 1.1.1
Redis version is 6.0.8
OS: Ubuntu 20.04
Can you help me to find out reason why is TLS not working, please?
Thank you
Wil
Ahh, SOLVED!
I was putting wrong CA chain. I had to chain root and intermediate certs downloaded from LE website into new file. It may come handy for someone with same problem.

How to make the TLS work in MQTT via port 8883?

I need help to configure this MQTT to work on TLS mode.
I have setup the MQTT in the server. The server is protected by letsencrypt certificate that's why it has https in its domain, then I set it up also in a remote computer.
the server runs this command
mosquitto_sub -h localhost -t 'testtopic' -p 1883
the remote computer runs this command
mosquitto_pub -h domainName -t 'testtopic' -m "test message" -p 1883
the MQTT configuration on both computers is like this
pid_file /var/run/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
port 1883
persistence_file mosquitto.db
log_dest syslog
log_dest stdout
log_dest topic
log_type error
log_type warning
log_type notice
log_type information
connection_messages true
log_timestamp true
allow_anonymous true
tls_version tlsv1.2
this one works. but how to make the communication into TLS mode?
can someone please let me know what's the proper configuration?
how to pass parameters in both computers?
I have tried changing the port of the config into 8883
In both computers I have tried passing the --cafile whereby the cafile
is a .pem certificate which came from the server which was generated by letsencrypt. So I just copied that and pasted it to the remote computer
those are the things I have tried so far, but in the wireshark it cannot detect TLS communication at all and the connection is being refused or something wrong with CA file
By setting allow anonymous true, anyone can publish to your broker without authentication.
TLS is not used directly in MQTT brokers, you need to configure MQTTS which uses TLS.
To use a secure MQTT connection,your Mosquitto configuration file found in /etc/mosquitto/mosquitto.conf needs to have the following lines:
listener 8883
cafile <path-to-cafile>
certfile <path-to-server-cert>
keyfile <path-to-server-key-file>
where <path-to-cafile>, and needs to be replaced by your absolute path where your ca file, server certificate i.e. your .pem file and server-key certificate is found.
For example in my case my mosquitto.conf looks like this:
pid_file /var/run/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/
log_dest file /var/log/mosquitto/mosquitto.log
listener 1883
protocol mqtt
listener 8883
cafile /etc/ssl/certs/broker/ca.pem
certfile /etc/ssl/certs/broker/server.pem
keyfile /etc/ssl/certs/broker/server-key.pem
tls_version tlsv1.2
Save this configuration and restart mosquitto using the above configuration
You can test your TLS connection by running:
mosquitto_pub -t test -m test-message -p 8883 --cafile <path-to-your-ca-file> --insecure
In my case it is:
mosquitto_pub -t test -m test-message -p 8883 --cafile /etc/ssl/certs/broker/ca.pem --insecure
You need to use --insecure option because the certificates are all self-signed. Self-signed server certificates cannot be verified by the mosquitto client.
If you don't use the --insecure option, you'll get an error which says
Error: host name verification failed.
OpenSSL Error: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed
Error: A TLS error occurred.
To setup authentication, create a text file with content
<user>:<password>
where is a placeholder for the username you want to allow
and is a placeholder for the password you want to set
For example:
panda:black
will create a user called panda and the password for the user panda will be black.
To encrypt the password, run the command
mosquitto_passwd -U <path-to-passwordfile>
This will now have contents like this:
panda:$6$a2foLssTVgMG4QY6$3rWvoLqwo1uCz6jZH6KDK3yAcWtIFlATbOSbwx7XJx2Q5Mix2S+iRqWI7KDqp43nSDdPV7mMvnYJS6tgHb7QjA==
Now add these two lines to the mosquitto configuration file
allow_anonymous false
password_file <path-to-passwordfile>
Restart/reload the mosquitto broker to have a fully authenticated MQTTS connection
To publish to the broker with username and password use:
mosquitto_pub -t test -m test-message -p 8883 --cafile <path-to-ca-file> -u panda -P black --insecure

Setting up a Docker registry with Letsencrypt certificate

I'm setting up a domain registry as described here:
https://docs.docker.com/registry/deploying/
I generated a certificate for docker.mydomain.com and started the docker using their command on my server:
docker run -d -p 5000:5000 --restart=always --name registry \
-v `pwd`/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2
I've started the docker and pointed to certificates I obtained using letsencrypt (https://letsencrypt.org/).
Now, when I browse to https://docker.mydomain.com:5000/v2/ I will get a page with just '{}', with a green lock (succesful secure page request).
But when I try to do a docker login docker.mydomain.com:5000 from a different server I see a error in the registry docker:
TLS handshake error from xxx.xxx.xxx.xxx:51773: remote error: bad certificate
I've tried some different variations in setting up the certificates, and gotten errors like:
remote error: unknown certificate authority
and
tls: first record does not look like a TLS handshake
What am I missing?
Docker seams to not support SNI : https://github.com/docker/docker/issues/9969
Update : Docker now should support SNI.
It's mean, when connecting to your server during the tls transaction, the docker client do not specify the domain name, so your server show the default certificate.
The solution could be to change to default certificate of your server to be to one valid for the docker domain.
This site works only in browsers with SNI support.
To check if your (sub-)domain works with clients not SNI-aware, you can use ssllabs.com/ssltest : If you DONT see the message, "This site works only in browsers with SNI support. " then it will works.

Docker Registry incorrectly claims an expired CA cert

I followed the Docker Registry installation docs precisely, and have a registry running on a remote Ubuntu VM. On that VM, the Docker container is running with the following command:
docker run -d -p 5000:5000 --restart=always --name registry \
-v `pwd`/auth:/auth \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-v `pwd`/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/registry.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/registry.key \
registry:2
On the remote VM, I have the following directory structure:
/home/myuser/
certs/
registry.crt
registry.key
/etc/docker/certs.d/myregistry.example.com:5000/
ca.crt
ca.key
The ca.crt is the same exact cert as ~/certs/registry.crt (just renamed); same goes for ca.key and registry.key being the same/just renamed. I created the ca* files per a suggestion from the error output you'll see below.
I am almost 100% sure the CA cert is still valid, although any help ruling that out (e.g. how can I actually tell?) would be appreciated. When I start the container and look at the Docker logs, I don't see any errors.
I then attempt to login from my local laptop (Mac):
docker login myregistry.example.com:5000
It queries me for my username, password and email (although I don't recall ever specifying an email when setting up Basic Auth). After entering these correctly (I have checked and double checked...) I get the following error:
myuser#mymachine:~/tmp$docker login myregistry.example.com:5000
Username: my_ciuser
Password:
Email: myuser#example.com
Error response from daemon: invalid registry endpoint https://myregistry.example.com:5000/v0/:
unable to ping registry endpoint https://myregistry.example.com:5000/v0/ v2 ping attempt failed with error:
Get https://myregistry.example.com:5000/v2/: x509: certificate has expired or is not yet valid
v1 ping attempt failed with error: Get https://myregistry.example.com:5000/v1/_ping: x509:
certificate has expired or is not yet valid. If this private registry supports only HTTP or
HTTPS with an unknown CA certificate, please add
`--insecure-registry myregistry.example.com:5000` to the daemon's
arguments. In the case of HTTPS, if you have access to the registry's CA
certificate, no need for the flag; simply place the CA certificate
at /etc/docker/certs.d/myregistry.example.com:5000/ca.crt
So from my perspective, I guess the following are possible:
The CA cert is invalid (if so, why?!?)
The CA cert is an intermediary cert (if so, how can I tell?)
The CA cert is expired (if so, how do I tell?)
This is a bad error message, and some other facet of the registry is not configured properly (if so, how do I troubleshoot further?)
Perhaps my cert is not located in the correct place on the server, or doesn't have the right permissions set (if so, where does the cert need to be?)
Something else that I would never expect in a million years
Any ideas/thoughts?
As said in the error message:
... In the case of HTTPS, if you have access to the registry's CA
certificate, no need for the flag; simply place the CA certificate
at /etc/docker/certs.d/myregistry.example.com:5000/ca.crt
where myregistry.example.com:5000 - your CN with port.
You should copy your ca.crt into each Docker Daemon that will connect to your Docker Registry and put it in this folder: /etc/docker/certs.d/myregistry.example.com:5000/ca.crt
After this action you need to restart Docker daemon, for example, via sudo service docker stop && service docker start on CentOS (or call similar procedure on your OS).
I had the similar error:
Then I added my private registry to the insecureregistries list.
See below image for docker-desktop