mldvx4 has asked for the wisdom of the Perl Monks concerning the following question:

Greetings. With the code down below I get the this error:

connect: SSL connect attempt failed error:0A000086:SSL routines::certificate verify failed

What is the right way to allow Net::MQTT::Simple::SSL to manage self-signed certificates?

#!/usr/bin/perl use Config::Tiny; use Net::MQTT::Simple::SSL; use strict; use warnings; my $config = $0; $config =~ s/\.pl$/.config/; my $configuration = Config::Tiny->read($config) or die("Could not read configuration file '$config': $!\n"); my $cpath = '/home/me/Certs'; my $mqtt = Net::MQTT::Simple::SSL->new("203.0.113.46:8883", { SSL_ca_file => "$cpath/certificate-authority.crt", SSL_cert_file => "$cpath/notifications-client.crt", SSL_key_file => "$cpath/notifications-client.key", # SSL_verify_mode => 0, }); $mqtt->login($configuration->{mqtt}->{account}, $configuration->{mqtt}->{password} ); $mqtt->subscribe('notifications', \&received); $mqtt->run(); $mqtt->disconnect(); exit(0); sub received { my ($topic, $message) = (@_); if ( $message =~ m/\x3b/ || $message =~ m/[\x00-\x08\x0a-\x1f]/ ) { warn "notify\tMalformed message\n"; } elsif ( $topic =~ m/\x3b/ || $topic =~ m/[\x00-\x08\x0a-\x1f]/ ) { warn "notify\tMalformed message\n"; } else { my ($title, $message) = ( $message =~ m/^([^\x09]+)\t(.*)$/ ); system("notify-send", "--icon=info", $title, $message); } }

If I uncomment SSL_verify_mode then it connects, but that seems rather unsafe and may partially defeat the encryption I would guess. I would like to find a way to verify the self-signed certificates here.

Replies are listed 'Best First'.
Re: Self-signed certificates and Net::MQTT::Simple::SSL
by choroba (Cardinal) on Aug 20, 2024 at 16:11 UTC
    You can try reusing the SSL_fingerprint option from IO::Socket::SSL , as the documentation says:
    The object oriented interface does support explicit SSL configuration. See IO::Socket::SSL for a comprehensive overview of all the options that can be supplied to the constructor, new.

    The option's documentation starts with

    Sometimes you have a self-signed certificate or a certificate issued by an unknown CA and you really want to accept it, but don't want to disable verification at all.
    which seems to be relevant.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      Thanks! Using IO::Socket::SSL I was able to lift the fingerprint from the MQTT broker by adding the following segment.

      ... use IO::Socket::SSL; ... print IO::Socket::SSL->new( PeerHost => "203.0.113.46:8883", SSL_verify_mode => 0, )->get_fingerprint,"\n"; ...

      Then I was able to modify the connection to include that information with SSL_fingerprint:

      ... my $mqtt = Net::MQTT::Simple::SSL->new("203.0.113.46:8883", { SSL_ca_file => "$cpath/certificate-authority.crt", SSL_cert_file => "$cpath/notifications-client.crt", SSL_key_file => "$cpath/notifications-client.key", SSL_fingerprint => 'sha256$a...2',}); ...

      All set. It's kind of a manual intervention and implementation of Trust on First Use, since the fingerprint is probably the right one when fetched that way. Alternatively, I can use OpenSSL over on the system with the broker and thus get the fingerprint via the file system directly:

      openssl x509 -fingerprint -sha256 \ -in /etc/mosquitto/certs/server.crt \ | sed -n -e '/Fingerprint/ { s/ .*=/$/; s/://g; p; }'

      So I guess there are two ways to get the checksum.