Mutual TLS with self signed certificates, with requests in python - python

I created both client and server certificates:
# client
openssl req -new -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out ssl/client.crt -keyout ssl/client.key
# server
openssl req -new -newkey rsa:4096 -x509 -sha256 -days 365 -nodes -out ssl/server.crt -keyout ssl/server
Then with python I have the following:
import requests
response = requests.get(
"https://localhost:8080/",
verify="ssl/server.crt",
cert=("ssl/client.crt", "ssl/client.key")
)
I also have a gunicorn server running with the server self signed certificate.
The code snippet is throwing me the following error:
requests.exceptions.SSLError: HTTPSConnectionPool(host='localhost', port=8080): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, '[SSL: TLSV1_ALERT_UNKNOWN_CA] tlsv1 alert unknown ca (_ssl.c:2633)')))
It is a self signed certificate so I am not sure what CA is it expecting.

tlsv1 alert unknown ca
The server is sending a TLS alert back since it cannot validate your client certificate - the certificate authority (ca) which signed the certificate is unknown to the server. You either need to disable client certificate validation in your server or (better) make the server trust your client certificate.
It is a self signed certificate so I am not sure what CA is it expecting.
A self-signed certificate is signed by itself, i.e. the CA is the certificate itself.

It looks like the server isn't able to validate your client certificate. If you're just using a pair of self-signed certificates for the client and server, then the server needs to also use the client's certificate as its CA, since it will attempt to validate it was signed by the CA - which in this case is the client.
I recently wrote a blog on deploying mTLS with self-signed certificates which might help you as it contains more details, specifically with how to configure the client and server. Check it out here: https://otterize.com/blog/so-you-want-to-deploy-mtls

Related

Validating an external certificate not in certifi package

I have a Python script that requests an https URL using the requests package. In so doing, I get a certificate error:
import requests
resp = requests.get('https://comicskingdom.com/', verify=True)
The error I see is:
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)
My system has the certifi package installed, but apparently the target server's certificate cannot be validated using that package's bundle. How can I verify this certificate properly? Where do I look to download the appropriate certificate chain? In the future, how do I know where to find the right certificate chain for any given certificate?
Solution:
requests documentation: https://requests.readthedocs.io/en/master/user/advanced/
(check args and kwargs possibilities (cert=...) in chapter SSL Cert Verification)
but to quickly resolve your issue:
(Firefox) go to your site. Click on the https icon left to the browser url (usually the icon looks like a lock),click on an arrow next to 'connection secure', click more info, click View certificates and scroll down to download Chain certificate. (You can even try here on stackoverflow site)
Then, in your requests.get, add path to the chain file
>>> requests.get('https://comicskingdom.com', verify='{path}/comicskingdom-com-chain.pem')
<Response [200]>
The certificate has some issue, so I will post here what I was able to find
What is problem?
What exactly is a problem can be found through this link or through finding the error
Source: https://security.stackexchange.com/questions/16085/how-to-get-public-key-of-a-secure-webpage
for you to examine the problem, run this command
This command will show you the certificate is ok, but there is issue
openssl s_client -connect comicskingdom.com:443 | openssl x509 -pubkey -noout
which outputs
openssl s_client -connect comicskingdom.com:443 | openssl x509 -pubkey -noout
depth=0 OU = Domain Control Validated, CN = *.comicskingdom.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, CN = *.comicskingdom.com
verify error:num=21:unable to verify the first certificate
verify return:1
Note this part
verify error:num=20:unable to get local issuer certificate
which matches requests error that I received with requests
requests.exceptions.SSLError: HTTPSConnectionPool(host='comicskingdom.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1091)')))

Python requests with https - certificate verify failed

I am attempting to estabilish a https connection between 2 applications: 1 is a api in nodejs and the other is a python client application.
After reading about https and certificates i have created a self-signed certificate.
To do so i used the following command:
openssl req -newkey rsa:2048 -nodes -keyout pvtkey.pem -x509 -days 365 -out domain.crt
And this to have the public key explicitely:
openssl rsa -in pvtkey.pem -pubout > pubkey.pem
Then on my python code i have the following line to make the request:
response = requests.post(endpoint, cert=("home/pi/se24-title.crt", "/home/pi/pvtkey.pem"), headers=self.headers, json=req_payload)
When i run to test my code i get the following error:
Max retries exceeded with url: /api/title
(Caused by SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed')])")))
Previously i had also tried to install the crt to the trusted certificates and make the requests like this:
response = requests.post(endpoint, verify=True, headers=self.headers, json=req_payload)
but still have the same result.
What am i doing wrong?
Could it be the certificate i have generated?
So i managed to figure out how to do it.
Somehow i must have missed some step along the way but this is how i ended up being able to install the self-signed-certificate:
STEPS:
1. Create a self-signed certificate
> openssl req -newkey rsa:2048 -nodes -keyout pvtkey.pem -x509 -days 365 -out domain.crt
2. Create the public key from the private key
> openssl rsa -in pvtkey.pem -pubout > pubkey.pem
3. To install the certificate on raspbian:
sudo mkdir /usr/local/share/ca-certificates/extra
sudo cp domain.crt /usr/local/share/ca-certificates/extra/domain.crt
sudo update-ca-certificates
Hope this helps other people with the same issue.

Flask application using TLS

I am trying to execute my Flask application over TLS, this is my example:
from flask import Flask
import ssl
app = Flask(__name__)
#app.route('/ping')
def ping():
return 'pong'
if __name__ == '__main__':
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations('./ca-crt.pem')
context.load_cert_chain('./server.crt', './server.key')
app.run('0.0.0.0', 8080, ssl_context=context)
and these is how I am generating the certificates:
# create server private key and server CSR
openssl req -nodes -new -keyout server.key -out server.csr
# generate certicate based on server's CSR using CA root certificate and CA private key
openssl x509 -req -days 365 -in server.csr -CA ca-crt.pem -CAkey ca.key -CAcreateserial -out server.crt
# verify the certificate (optionally)
openssl verify -CAfile ca-crt.pem server.crt
while for client certificate:
# create client private key and client CSR
openssl req -nodes -new -keyout client.key -out client.csr
# generate certicate based on client's CSR using CA root certificate and CA private key
openssl x509 -req -days 365 -in client.csr -CA ca-crt.pem -CAkey ca.key -CAcreateserial -out client.crt
# verify the certificate (optionally)
openssl verify -CAfile ca-crt.pem client.crt
But when I try to execute my curl request:
curl --insecure --cacert ca-crt.pem --key client.key --cert client.crt https://localhost:8080/ping -v
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
* found 1 certificates in ca-crt.pem
* found 597 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* gnutls_handshake() failed: CA is unknown
* Closing connection 0
curl: (35) gnutls_handshake() failed: CA is unknown
What is the problem?
In case I remove the part to identify the client, it works:
if __name__ == '__main__':
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
context.load_cert_chain('server.crt', 'server.key')
app.run('0.0.0.0', 8080, ssl_context=context)
curl --insecure https://localhost:8080/ping
pong
Moreover, in case of certificates with password, how to specify PEM password during load of certificates?

how to run flask app in localhost with SSL

I tried to run my Flask Application on localhost and as well as on my local network's IP address and it ran very well (without SSL).
However, when I tried to run the application with SSL then the web browsers didn't load the page and gives the error:
Your connection is not private : NET::ERR_CERT_INVALID
Methods I have tried but failed:
1. Using Self-signed .pem certificate (Subject Type=CA)
With generated certificate .pem, cert key, and configuring my flask app use it.
openssl req -x509 -newkey rsa:4096 -nodes -out cert.pem -keyout key.pem -days 365
app.run(
host='192.168.1.127', port="8282", debug=True,
ssl_context=('cert.pem', 'key.pem'),
)
2. Using Self-signed .crt certificate
With generated certificate .crt, cert key, and configuring my flask app use it.
$ openssl genrsa -des3 -out server.key 1024
$ openssl req -new -key server.key -out server.csr
$ cp server.key server.key.org
$ openssl rsa -in server.key.org -out server.key
$ openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
app.run(
host='192.168.1.127', port="8282", debug=True,
ssl_context=('server.crt', 'server.key')
)
3. Run Flask with ssl_context='adhoc'
```
app.run(
host='192.168.1.127', port="8282", debug=True,
ssl_context='adhoc'
)
```
I am trying to build a system where multiple raspberry pi are located at different rooms of the house but they are connected to the same home network.
There is the main computer on the same network which acts as a Controller and to implement the system successfully I need to make requests from the controller system to all the Raspberry PI over HTTPS.
Its working.
The message connection not private is misleading, what is actually happening is that the connection is encrypted with a certificate that is not in your chain of trust. Even if it was, I doubt the browser would accept a certificate for an IP address.
In any case, your connection is indeed encrypted.
You don't shoe the additional details. But you can try to add the generated certificate to your system's chain of trust.

Custom web server & self-signed certificate

First of all let me to say my knowledge of ssl and criptography protocols is very limited. Please be patient if I say something blatantly wrong :-) . Feel free to correct me!
I'm building a custom web server to be deployed inside an isolated local network; this is how I run my service (Python code):
ssl_context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
ssl_context.load_cert_chain(certfile='mykey.crt', keyfile='mykey.key')
... client connects to https port 443 ...
ssl_sock = ssl_context.wrap_socket(sock, server_side=True)
This is how I generated mykey.crt and mykey.key files:
$ openssl genrsa -des3 -out mykey.orig.key 2048
$ openssl rsa -in mykey.orig.key -out mykey.key
$ openssl req -new -key mykey.key -out mykey.csr
$ openssl x509 -req -days 3650 -in mykey.csr -signkey mykey.key -out mykey.crt
So far so good, my webserver works very well. But I have go past the "not secure" warning that Firefox rightfully shove in my face.
I'd like to install my self-signed certificate in the few clients that are going access my web server in order to permanently avoid the warning.
I followed every single certificate installation guide I was able to find but I absolutely cannot get Firefox (and Chrome) accept my certificate. And I get no error message whatsoever from the browsers.
I think I'm missing something in the certificate generation commands.
Somebody could help me?
Thanks a lot!
self-signed certificate can uses only for tests. You have to get the certificate from an 'Accredited certification authority'
2) check please : self-signed certificate need to has next data:
URL, address,
name,
email
3) you should use a certificate signed by a CA

Categories

Resources