Mqtt TLS certificate verify failed : self signed certificate - python

Am trying to implement TLS for mqtt and has followed the tutorials from the link below
http://www.steves-internet-guide.com/mosquitto-tls/
I followed exactly how it has been instructed to generate certificates using openssl and pasted in the location of mqtt and changed the conf of mqtt and restarted the service.
But when I try to connect to mqtt using tls it shows the below error message
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1124)
And python code is
client1 = paho.Client("control1")
client1.tls_set(ca_certs="ca.crt")
client1.tls_insecure_set(True)
client1.connect("localhost", 8883)
client1.loop_forever()
where ca.crt is in the project directory.

The message you are receiving indicates that the broker's server certificate is not trusted (because it is self-signed), therefore paho is not being correctly told it is trustworthy.
It is possible your fake certificate authority's root certificate (the ca.crt file you feed to paho) is not properly signed or generated, or the certificates that Mosquitto is using are not signed correctly. Either way, you likely need to start the entire process over to be 100% certain everything was done right.
Generate the fake certificate authority's (CA) signing key
$ openssl genrsa -des3 -out ca.key 2048
Generate a certificate signing request for the fake CA
$ openssl req -new -key ca.key -out ca-cert-request.csr -sha256
Give the organization a name like "Fake Authority" and do not enter a common name (since your fake CA does not actually live on a server with a name)
Create the fake CA's root certificate
$ openssl x509 -req -in ca-cert-request.csr -signkey ca.key -out ca-root-cert.crt -days 365 -sha256
Create the server / mqtt broker's keypair
$ openssl genrsa -out server.key 2048
Create a certificate signing request using the server key to send to the fake CA for identity verification
$ openssl req -new -key server.key -out server-cert-request.csr -sha256
Give the organization a name like "Localhost MQTT Broker Inc." and the common name should be localhost or the exact domain you use to connect to the mqtt broker
Now acting as the fake CA, you receive the server's request for your signature. You have verified the server is who it says it is (an MQTT broker operating on localhost), so create a new certificate & sign it with all the power of your fake authority.
$ openssl x509 -req -in server-cert-request.csr -CA ca-root-cert.crt -CAkey ca.key -CAcreateserial -out server.crt -days 360
Now you have everything you need. Make sure (as in Steve's tutorial) Mosquitto is loading the following in mosquitto.conf:
listener 8883
cafile certs\ca-root-cert.crt
keyfile certs\server.key
certfile certs\server.crt
Make sure paho-mqtt is loading the fake CA's root certificate.
client1.tls_set(ca_certs="ca-root-cert.crt")
This is how it knows that mosquitto's server.crt is legitimately signed by a "real and trusted authority" and is not "self-signed" and thus untrusted. Mosquitto and paho should now be able to securely connect and communicate.

Related

How to fetch Certificate Issuer name by loading a pem file in python?

I am trying to fetch the certificate issuer name from a pem file. But I am getting an error.
ValueError: Unable to load certificate. See https://cryptography.io/en/latest/faq/#why-can-t-i-import-my-pem-file for more details.
Here are the commands which I used to create the keys.
openssl ecparam -name secp256k1 -genkey -noout -out PrivateKey.pem
openssl ec -in PrivateKey.pem -pubout -conv_form compressed -out PublicKey.pem
And when I executing the below command,
openssl x509 -noout -text -in PublicKey.pem
getting the error:
unable to load certificate
140351154677056:error:0909006C:PEM routines:get_name:no start line:../crypto/pem/pem_lib.c:745:Expecting: TRUSTED CERTIFICATE
And here is the my python code to fetch issuer name,
*.py
with open('PublicKey.pem','r') as pub_key:
pubkey = pub_key.read().encode()
cert_info = x509.load_pem_x509_certificate(pubkey, default_backend())
print('cert_info',cert_info)
print('cn',cn)
cn = cert_info.issuer.get_attributes_for_oid(NameOID.COMMON_NAME)[0].value
print('cn------',cn)
Am getting the error Unable to load certificate.
I also need to fetch the serial number.
How can i solve this?

The handshake operation timed out

I've mbedtls nonRTOS server device. I'm trying to communicate with PLC Client. But before the using PLC, I'm trying to use python tls client.
I've a problem with when I use below cert and key file with below method:
Generate 2048-bit RSA private key:
openssl genrsa -out key.pem 2048
Generate a Certificate Signing Request:
openssl req -new -sha256 -key key.pem -out csr.csr
Generate a self-signed x509 certificate suitable for use on web servers.
openssl req -x509 -sha256 -days 365 -key key.pem -in csr.csr -out certificate.pem
Create SSL identity file in PKCS12 as mentioned here
openssl pkcs12 -export -out client-identity.p12 -inkey key.pem -in certificate.pem
I get above code from here: Creating a .p12 file
I need to p12 file using in PLC Client. When I trying to use certificate.pem and key.pem in mbedtls-servers system and when I use the certificate.pem in python client side, I get below situation:
Server couldnt send key exchange message waiting forever.
But If I generate the key and cert file below method:
openssl req -new -x509 -days 365 -nodes -out cert.pem -keyout key.pem
They communicate successfuly.
How can I solve the problem why the server waiting to send key exchange message when I generate key and cert file with first method

Vault returns CERTIFICATE_VERIFY_ERROR when authenticating with tls

I am newbie to vault and currently trying to enable client tls authentication (all on the only CentOS 7 node) via self-signed certificates.
Of course, first of all i ran: vault auth-enable cert
Then, I created a policy.hcl file with such contents:
path "secret/policy/test/foo" {policy="read"}
Then I did the following:
$ vault policy-write test policy.hcl
$ vault write "secret/policy/test/foo" vaule=s3cr3t policy=test
Generate client certificate:
$ openssl genrsa -out client.key 2048
$ openssl req -new -key client.key -out client.csr
$ openssl x509 -req -in client.csr -signkey client.key -out client.crt
And the final action:
$ vault write auth/cert/certs/test display_name=test policies=test certificate=#/home/vagrant/ssl/client.crt
And it all execute without any errors or warnings. Then, i wrote a simple script which must read just a one value after authentication with TLS:
import os
import hvac
client = hvac.Client(url='https://127.0.0.1:8200', cert=('client.crt', 'client.key'))
print(client.read('secret/policy/test/foo'))
But when I run it I get the following error:
requests.exceptions.SSLError: HTTPSConnectionPool(host='127.0.0.1', port=8200): Max retries exceeded with url: /v1/secret/policy/test/foo (Caused by SSLError(SSLError(1, u'[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:579)'),))
Server log says:
http: TLS handshake error from 127.0.0.1:33744: remote error: tls: unknown certificate authority
Any help is highly appreciated
EDIT:
to clarify what the actual problem is, I'd like to mention that when i authenticate to the Vault using CLI:
$ vault auth -method=cert -client-cert=client.crt -client-key=client.key
# returns:
The token below is already saved in the session. You do not
need to "vault auth" again with the token.
token: 8afdb5bd-b6f1-e33e-a391-ced99fa18b5f
token_duration: 2764800
token_policies: [default test]
... it seems to be working just fine cuz the policy I've created is being attached and I can read the data from secret/policy/test/foo, but Python+HVAC approach does not work.

Ansible for Windows: WinRM HTTPS setup

I have some Ansible playbooks I want to run against some Windows hosts. I've followed the various Ansible guides for setting up WinRM and they have worked fine, but the default setups are very insecure and I want something more production ready. However, the instructions for how to do this are incredibly sparse. So far I've done the following:
On my Windows box:
Enabled WinRM using the supplied ConfigureRemotingForAnsible.ps1 script
Configured target machine to to use a valid cert on HTTPS/5986 rather than the self-signed one generated by the above script
Enabled both Kerberos and CredSSP auth methods on the target machine in WinRM. Some of my role steps require CredSSP to work reliably.
So far so good, the Windows side seems to work fine. However, getting Ansible to connect is proving a nightmare. I can't figure out how to get Ansible to trust the HTTPS cert on the target despite adding it. On my Centos 7 'push box' I've done the following:
Install Ansible and pip with the pywinrm, requests_kerberos and requests_credssp modules
Added my CA certificate to both /etc/pki/tls/certs and /etc/pki/ca-cert
Set my inventory to the following:
ansible_user=ADMINISTRATOR#DOMAIN.COM
ansible_password=Password1
ansible_port=5986
ansible_connection=winrm
ansible_winrm_scheme=https
/#ansible_winrm_server_cert_validation=ignore
ansible_winrm_transport=credssp
With certification validation turned on the connection fails with the following error:
fatal: [host.domain.com]:
UNREACHABLE! => {
"changed": false,
"msg": "credssp: HTTPSConnectionPool(host='host.domain.com', port=5986): Max retries exceeded with url: /wsman (Caused by SSLError(SSLError(\"bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')],)\",),))",
"unreachable": true}
With cert validation turned off it works fine.
So my question: How do I get Ansible to trust my CA cert?
This isn't simple. The problem is there are 3 different groups that don't really want to play:
Ansible: doesn't want to be responsible for OpenSSL or Windows details
OpenSSL: doesn't want to be used as a certficate authority
Microsoft: doesn't want you to use anything but Windows tools
First, you will need 3 sets of OpenSSL certs/keys: the self-signed Certificate Authority (CA), the server winRM HTTPS, and the target user.
There is nothing magic about the CA cert/key; it can be generated with the following:
openssl req -new -out caroot.req -keyout caroot.key -days 730 ...
openssl x509 -req -in caroot.req -extensions v3_ca -signkey caroot.key -out cacert.pem -days 730
There are a myriad of other options to these OpenSSL commands which may (or not) work in your specific environment. This is one of those instances of "don't want to be responsible for OpenSSL".
Second, you will need the WinRM HTTPS cert/key. First, you have to generate the server cert. The key detail of generating the cert is that the 'common name' attribute on the cert MUST match the target hostname, as with any HTTPS cert.
openssl req -new -out server.req -keyout server.key -days 730 -nodes ...
Now, here comes the tricky part. You can't just sign the key as-is; the signing process must add a couple of additional attributes to the cert or it won't work. Create a text file I'll call 'attributes.txt' with the following two lines:
subjectAltName=DNS:hostname.mycompany.com,DNS:hostname
extendedKeyUsage=serverAuth
The first line, the 'subjectAltName', is required or the Python/OpenSSL client will reject the key. You need to substitute the proper values for the target hostname. The second line is required by Windows, or Windows will not use this as for an HTTPS server.
Now sign the key with the CA generated earlier:
openssl x509 -req -in server.req -out server.pem -days 730 -CA caroot.pem -CAkey caroot.key -extfile attributes.txt
Another little wrinkle: Windows will not import a server key unless you combine the key and cert into a PKCS#12 file. This can be done with the following command, which creates a PKCS#12 file with no password:
openssl pkcs12 -export -password pass: -inkey server.key -in server.pem -out windows.pfx
This will generate a file 'windows.pfx' which we'll need later.
Bored yet?
Next we need another key/cert for the user login. This is assuming that we're going to be using a local user on the system, not a domain user. (You're on your own for that.) Generating the key is almost the same as for the server key, except that the 'commom name' attribute (CN) MUST match the target username. (In later usage, I'll call our user 'ansible').
openssl req -new -out winlogin.req -keyout winlogin.key -days 730
This private key is going to be the login key, analogous to an SSH private key. Next, we must sign the req. As with the server key, we need to add some extended attributes, or it won't work. Our 'attributes.txt' file must contain the following lines:
subjectAltName=otherName:1.3.6.1.4.1.311.20.2.3;UTF8:ansible#localhost
extendedKeyUsage=clientAuth
The oddball identifier in the 'altNames' is some proprietary Microsoft thingy, which must contain the 'username#localhost'. As I mentioned before, I'm using a local user 'ansible'. The extendedKeyUsage attribute is required or Windows will not allow the key to be used for user authentication. Finally, we sign the cert:
openssl x509 -req -in winlogin.req -out winlogin.pem -days 730 -CA caroot.pem -CAkey caroot.key -extfile attributes.txt
Just so you know, I'm starting to get on my own nerves here. We're almost there. Finally, copy the CA cert (caroot.pem), the server PKCS#12 cert/key (windows.pfx), and the user cert (winlogin.pem) to the target windows system somewhere. Run the following PowerShell script from the same directory. It will create the local ansible user and import all of the SSL artifacts into their proper target locations. Sorry if this isn't commercial quality code. This also has a hardcoded password for the ansible user, but that is irrelevant and can be freely changed. If this actually runs successfully, and you survive the shock, the file artifacts (the PFX and PEM files) can be removed from the Windows server.
Also note that this script adds a firewall rule at the end. This, of course, will have to be appropriately modified for your environment.
# master script to enable winRM via HTTPS and allow certificate-based
# authentication
# add the local 'ansible' user
$username = "ansible"
$password = ConvertTo-SecureString -string "Ans!b123" -AsPlainText -Force
New-LocalUser -Name $username -AccountNeverExpires -Description "Ansible Remote Management" -Password $password
Add-LocalGroupMember -Member "ansible" -Group "Administrators"
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $username, $password
# import the Ansible root CA; certlm should show this in the
# 'Trusted Root Certification Authorities' folder
$caroot = Import-Certificate -FilePath ".\caroot.pem" -CertStoreLocation "Cert:\LocalMachine\Root"
# import the user cert; certlm should show this in the 'Trusted People' folder
$userkey = Import-Certificate -FilePath ".\winlogin.pem" -CertStoreLocation "Cert:\LocalMachine\TrustedPeople"
New-Item -Path WSMan:\localhost\ClientCertificate -subject "ansible#localhost" -URI "*" -Issuer $caroot.Thumbprint -Credential $credential -Force
# import the server certs - should appear in 'Personal' folder. The PFX file
# must contain both the cert and private key
$srvcert = Get-ChildItem -Path ".\windows.pfx" | Import-PFXCertificate -CertStoreLocation "Cert:\LocalMachine\MY" -Exportable
# Now create the winRM instance
$selector_set = #{Address= "*" Transport = "HTTPS" }
$value_set = #{CertificateThumbprint = $srvcert.Thumbprint}
New-WSManInstance -ResourceURI "winrm/config/Listener" -SelectorSet $selector_set -ValueSet $value_set
Set-Item -Path WSMan:\localhost\Service\Auth\Certificate -value $true
# add a firewall rule
New-NetFirewallRule -DisplayName "Ansible WinRM" -Direction Inbound -Protocol "TCP" -LocalPort "5986" -Action Allow -RemoteAddress #("192.16.2.3")
Okay, now that Windows is done, we should be ready for Ansible. Within your inventory, you will need the following variables to apply to the Windows systems:
ansible_port: 5986
ansible_connection: winrm
ansible_winrm_ca_trust_path: /path/to/caroot.pem
ansible_winrm_transport: certficate
ansible_winrm_cert_pem: /path/to/winlogin.pem
ansible_winrm_cert_key_pem: /path/to/winlogin.key
At this point, Ansible should connect to the Windows server using HTTPS and certificate authentication. I hope I hit all of the steps, it was a while ago I set this up.
Run this on the ansible control host:
python -c "import ssl; print(ssl.get_default_verify_paths())"
this way you will see where python expects to find the certificate
Ensure that the CA trust certificate is pem-encoded
regards
This worked for me..
https://dodgydudes.se/validate-ca-certificate-in-ansible-connecting-with-winrm/
ansible_winrm_ca_trust_path: /etc/ssl/certs #TLS 1.2
ansible_winrm_transport: ntlm

PyAPNs throws IOError Operation not supported by device

I am trying to implement APNS for my iOS push app from this tutorial raywenderlich tutorial.
As per the description I have done everything.
After running this command
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushChatCert.pem -key PushChatKey.pem
I got a big message showing that everything is connected as expected.
I have two files now PushChatCert.pem and PushChatKey.pem
and token_hex = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
So for sending push notification from server I following PyAPNs.
After doing all these in my python shell it is throwing IOError: [Errno 19] Operation not supported by device
import time
from apns import APNs, Frame, Payload
apns = APNs(use_sandbox=True, cert_file='PushChatCert.pem', key_file='PushChatKey.pem')
# Send a notification
token_hex = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
payload = Payload(alert="Hello World!", sound="default", badge=1)
apns.gateway_server.send_notification(token_hex, payload)
Error
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
apns.gateway_server.send_notification(token_hex, payload)
File "/Library/Python/2.7/site-packages/apns.py", line 544, in send_notification
self.write(self._get_notification(token_hex, payload))
File "/Library/Python/2.7/site-packages/apns.py", line 273, in write
return self._connection().write(string)
File "/Library/Python/2.7/site-packages/apns.py", line 254, in _connection
self._connect()
File "/Library/Python/2.7/site-packages/apns.py", line 230, in _connect
self._ssl = wrap_socket(self._socket, self.key_file, self.cert_file)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 891, in wrap_socket
ciphers=ciphers)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py", line 509, in __init__
self._context.load_cert_chain(certfile, keyfile)
IOError: [Errno 19] Operation not supported by device
Edit :
After running this comment in my terminal
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushChatCert.pem -key PushChatKey.pem I was getting an entrust issue as follows
depth=1 /C=US/O=Entrust, Inc./OU=www.entrust.net/rpa is incorporated by reference/OU=(c) 2009 Entrust, Inc./CN=Entrust Certification Authority - L1C
verify error:num=20:unable to get local issuer certificate
So I downloaded the entrust_2048_ca.cer file and kept in the same folder then from terminal I am running as
openssl s_client -connect gateway.sandbox.push.apple.com:2195 -CAfile entrust_2048_ca.cer -cert PushChatCert.pem -key PushChatKey.pem
Then that problem has been solved but how to execute that in PyAPNs?
Problem has been solved. It was some SSL security issue for that python was not able to access the files from that file dir.
I was following this tutorial apple-push-notification-services.
As described in this tutorial after creating the aps_development.cer file I was doing these to get the .pem files
$ openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem
Convert the private key’s .p12 file into a .pem file:
$ openssl pkcs12 -nocerts -out PushChatKey.pem -in PushChatKey.p12
Enter Import Password:
MAC verified OK
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
After doing all I had PushChatKey.pem and PushChatCert.pem files and using those files I was not able to send push notifications to my device PyAPNs
apns = APNs(use_sandbox=True, cert_file='PushChatKey.pem', key_file='PushChatCert.pem')
How did I solve?
Finally I tried those certificate creation from the beginning but this time following some other tutorial
Create your APNS certificates.
After creating the SSL Certificate that you download as named aps_developer_identity.cer. Double-click on it to install it in the Keychain Access application. The SSL certificate will be used by your provider application so that it can contact the APNs to send push notifications to your applications.
Launch Keychain Assistant from your local Mac and from the 'login' keychain, filter by the 'Certificates' category. You will see an expandable option called “Apple Development iOS Push Services”:
Expand this option then right click on “Apple Development iOS Push Services” -> Export “Apple Development iOS Push Services ...″. Save this as apns-dev-cert.p12 file somewhere you can access it.
Now from apns-dev-cert.p12 you make .pem using these command from your terminal
openssl pkcs12 -in apns-dev-cert.p12 -out apns.crt.pem -clcerts -nokeys
openssl pkcs12 -in apns-dev-cert.p12 -out apns.key.pem -nocerts -nodes
If you want to create single .pem
openssl pkcs12 -in apns-dev-cert.p12 -out apns_development.pem -nodes -clcerts
Now use these apns.crt.pem and apns.key.pem files with PyAPNs and it works like magic.
Create your provision profile carefully.
Thanks.

Categories