Python SSL with PKCS#12 certificates - python

Is there some way to wrap a socket connection with SSL using python's ssl module in python 2.6 using a pkcs#12 file? The file contains a private key and certificate. I want to use them for the client side of the connection. This post seems to hint that it may be possible but doesn't give a real definitive answer.

Not with python's ssl module. M2Crypto can't do this also at the moment, nor does python-gnutls. If you've got openssl command available on your client machine, you can re-export that pkcs12 to pem format running the openssl command, and use the results, something like:
openssl pkcs12 -in your_pkcs.p12 -out client_certs.pem -clcerts -nokeys [password options]
openssl pkcs12 -in your_pkcs.p12 -out keys.pem -nocerts [password options]
However PKCS12 is utterly broken by design, while still popular, you should avoid it if possible.

Related

How to validate x509 certificates in Python3

Using OpenSSL I can check the validity of user X.509 certificates through the following command:
openssl verify -crl_check -CAfile $CRL_chain_path $PEM_path
with:
$CRL_chain_path: the path of a base64 file containing the trusted certificate chain and the CRL entries
$PEM_path: the path of my base64 certificate to be checked.
How could the same thing be achieved with Python3? So far I'm using the cryptography library. Unfortunately, according to this issue, the functionality is not yet included. Moreover, I would like to avoid bash command usage (subprocess, os, etc.).
This question only covers the chain of trust topic (which is unfortunately not enough). This one checks SSL/TLS sessions, which cannot be used in my context due to the fact that I focus on user PKI public keys.
Is there a simple way with Python to check the validity of X.509 certificates (date ok, chain of trust, no revocation, any other check performed by OpenSSL?, etc.)?

How to establish TLS session in python using PKCS11

I’m trying to establish TLS channel between a client and a web server that are under my control. Both the client and server authenticates themselves using certificates that I’ve created under private PKI scheme. Client key and certificate are stored on usb dongle type HSM. Python is the main application language.
I’m able to do all required crypto operations for my project using python-pkcs11 package such as AES encryption, HMAC signing, RSA signing, and etc. However, I couldn’t find a way to “bind” pkcs11 to any TLS library. What I mean is a “Pythonic” way of calling a function that handles pkcs11 layer and establishes a TLS channel. Requests does not support pkcs11. libcurl has support for pkcs11 but it’s not implemented in pycurl, neither pyopenssl.
I’m able to do it openssl’s s_client CLI tool using engine api:
openssl s_client -engine pkcs11 -verify 2 -CAfile path/to/CA.pem -keyform engine -key "pkcs11:...;object=rsa;type=private" -cert path/to/client-cert.pem -connect localhost:8443
An example of what I’m looking for:
do_tls_with_pkcs(key=’pkcs11:URL’, cert=’cert.pem’, verify=’CA-cert.pem’)
As far as I could search around, no such library exists yet. Now I’m looking for a workaround.
I have read that if openssl, libp11, and python are compiled in such a way it is possible to abstract all of this, hence simple requests calls would go through HSM, transparent to application code. Although, I couldn’t find any material on how to do it.
I faced a similar problem as I wanted to use a PKCS#11 token (YubiKey, PIV applet) along Python requests.
I came up with https://github.com/cedric-dufour/scriptisms/blob/master/misc/m2requests.py
It's imperfect, in the sense that it does not use connections pools and does not support HTTP streams or proxying - like requests's stock HTTPS adapter does - but it does the job for simple connections to backends that require mTLS.

How to import OpenSSL in Python to fetch the serial number of the certificate

I have a certificate and i used the regular expression to strip the beginning and ending from certificate. How can i decode the serial number of the certificate using OpenSSL.
I have the cli command to decode:
openssl x509 -serial -noout
how can fetch it from Python

Is there a Python API that will return precise cipher information about a TLS connection?

I'm trying to write a python (or Java) program that makes an https connection to a website and then returns properties of the https connection. I've been using python's ssl (http://docs.python.org/2/library/ssl.html), specifically the .cipher() method. My main issue with the output is that it isn't very specific:
('RC4-SHA', 'TLSv1/SSLv3', 128)
This is the output for www.amazon.com. But when I go into my browser and manually examine the connection, I can really see that it is: RC4 with SHA1 message authentication, RSA key exchange and TLS v1.0. In fact, the .cipher() method outputs TLSv1/SSLv3 for TLS versions 1.0, 1.1 and 1.2 and outputs SHA for SHA1 and SHA256.
Is there any Python (or Java) API that will give me more information about the https connection?
The Python ssl module is just a wrapper around OpenSSL, and it can't provide any more information than the library provides. But really, I don't think you're missing any information. It is being specific. You're just always getting TLSv1.0 and SHA1.
First, TLSv1/SSLv3 in OpenSSL 0.9 means TLSv1.0. It cannot mean 1.1 or 1.2, because OpenSSL 0.9 does not support those protocols. (And you are probably using OpenSSL 0.9. For example, the 3.3.0 64-bit Mac binary installer I just got off Python.org uses 0.9.8r.) You can check this from Python with ssl.OPENSSL_VERSION.
Second, RC4-SHA means SHA1, not SHA256. RC4-SHA is just the OpenSSL name for the TLSv1.0 cipher suite TLS_RSA_WITH_RC4_128_SHA. That's a complete specification of the cipher; there are different ciphers with SHA256 on the end of their names. You can see the list of cipher suites specified in RFC 2246 and its addenda for TLS 1.0 (it's RFC4346 for 1.1 and RFC 5246 for 1.2). I don't think the mapping from OpenSSL names to RFC names is specified anywhere except inside the code, but if you have the command-line OpenSSL tools you can type openssl ciphers to dump out the list of OpenSSL names for all suggested cipher suites it will send, and then you can match them up to the values sent in the handshake. (To see the handshake, openssl s_client -connect www.amazon.com:443 -msg, or try -debug or other flags instead of/in addition to -msg.)
So, why does your browser show TLSv1.2 or SHA256 for some of those same sites? Because your browser has a completely different SSL library (or a newer OpenSSL), and therefore does a completely different handshake with the server, and ends up agreeing on different cipher suites, and therefore it reports different information.
So, it's not that Python is negotiating TLSv1.2 or SHA256 and just hiding that from you; it's negotiating TLSv1.0 and SHA1 with the same server, and telling you what it's done.
If you want to use a different library that can handle things OpenSSL 0.9 can't, there are lots of choices. If you install OpenSSL 1.0.1 or later and build PyOpenSSL against that, I believe (I haven't tested) that you should be able to negotiate newer protocols and ciphers and find out that you've done so. It might even rework if you rebuild Python, or the standalone ssl module, against it. (If neither of those works, there are a zillion more OpenSSL wrappers and other SSL or TLS modules at PyPI, or you can just ctypes your favorite yourself.)

https handshake with keystores in Python

I have an web server set up that denies connections without a valid .p12 certificate. I need to access a REST API that is running on the server in a Python script, but I can't find anything about how to do it. If anyone has a good tutorial on how to perform an SSL handshake using .p12 certificates in Python, please let me know.
The same methods described in the answers to this question, which asks about verifying a server certificate during the HTTPS connection (this is not done at all by default by urllib or httplib) should allow you to specify a client-certificate in addition to the CA certificate lists.
If you choose the option based on ssl.wrap_socket, pass a cerfile/keyfile parameter as described in the documentation.
Using PycURL, you should be able to call setopt(pycurl.SSLCERT, "/path/to/cert.pem") and setopt(pycurl.SSLKEY, "/path/to/key.pem"). The option names are based on the SSL and SECURITY OPTIONS section of the cURL documentation (there's an option for the password too).
It's likely that you will have to convert your PKCS#12 (.p12) file into PEM format. To do so:
# Extract the certificate:
openssl pkcs12 -in filename.p12 -nokeys -out certificate.pem
# Extract the private key:
openssl pkcs12 -in filename.p12 -nocerts -out privkey.pem

Categories