I'm attempting to use the requests library to connect to a server that requires a client certificate be provided. I can get the certificates, but not the private key.
I'm able to extract certificates from the smartcard (using the cryptography library to load the x509 certificate being access through pkcs11) and I'm able to serialize these certificates in the PEM format expected by requests. pkcs11 also provides access to the private keys located on the card; I can use them to perform operations such as signing or decryption. However, as they're marked as non-exportable (which makes sense, they're private keys after all), I can't serialize them to a file to provide when I create the SSL context.
I've seen solutions to this problem written in Java, where a keystore/key manager on the card is accessed, and the key is associated with the context that way, but I have yet to find a way of doing so in Python.
Edit: This is being done on a Windows machine. I have tried to look into using the M2Crypto library as well, however I have not been able to get the library to successfully install (even when using M2CryptoWin64).
import pkcs11
from pkcs11.constants import ObjectClass
from pkcs11.mechanisms import KeyType, Mechanism
from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.serialization import Encoding
lib = pkcs11.lib("path/to/pkcs11/dll")
slots = lib.get_slots(token_present=True)
token = slots[0].get_token()
with token.open(rw=True, user_pin="1234") as session:
attrs = {
pkcs11.Attribute.CLASS: ObjectClass.CERTIFICATE
}
certs = tuple(session.get_objects(attrs))
x509cert = x509.load_der_x509_certificate(certs[0][pkcs11.Attribute.VALUE], default_backend())
with open("cert_file", 'wb') as certfile:
certfile.write(x509cert.public_bytes(Encoding.PEM))
r = requests.get("https://www.google.com",
verify=False,
cert="cert_file")
print(r.text)