Reputation: 31
I want to invoke a web request using a client certificate (public+private key) stored in the Windows certificate store.
With PowerShell my call would look like this (this works):
Invoke-WebRequest -CertificateThumbprint $thumbprint -Uri $uri
Now I am searching for an equivalent in python. I do not want to extract the certificate and pass the file but directly use the store or at least only keep the certificate in memory.
I have tried wincertstore but the certificate lies in the UserStore(cert:\CurrentUser\My) so I cannot access it. Same problem with sslContext.
Installing python-certifi-win32 as mentioned in this answer seems to only load the CA-certificates in order to verify the server, but what I need is a client certificate to verify myself against the server.
Are there any ways other than calling powershell with subprocess to achieve this?
Many thanks in advance.
Upvotes: 1
Views: 2829
Reputation: 31
For anyone with the same problem. I solved it using clr to export the certificate into memory and requests_toolbelt to use it with requests.
Code example to make it work:
import clr
import requests
import requests_toolbelt
from cryptography.hazmat.primitives.serialization.pkcs12 import load_key_and_certificates
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
from cryptography.hazmat.backends import default_backend
from requests_toolbelt.adapters.x509 import X509Adapter
clr.AddReference('System')
clr.AddReference('System.Linq')
clr.AddReference('System.Security.Cryptography.X509Certificates')
clr.AddReference('System.Security.Cryptography')
from System.Security.Cryptography.X509Certificates import X509Store, StoreName, StoreLocation,OpenFlags,X509Certificate2Collection,X509FindType,X509Certificate2, X509ContentType
from System.Security.Cryptography import AsymmetricAlgorithm
store = X509Store(StoreName.My, StoreLocation.CurrentUser)
store.Open(OpenFlags.ReadOnly)
user = os.environ['USERNAME']
certCollection = store.Certificates.Find(
X509FindType.FindBySubjectName,
user,
False)
cert = certCollection.get_Item(0)
pkcs12 = cert.Export(X509ContentType.Pkcs12, <passphrase>)
backend = default_backend()
pkcs12_password_bytes = "<password>".encode('utf8')
pycaP12 = load_key_and_certificates(pkcs12, pkcs12_password_bytes, backend)
cert_bytes = pycaP12[1].public_bytes(Encoding.DER)
pk_bytes = pycaP12[0].private_bytes(Encoding.DER, PrivateFormat.PKCS8, NoEncryption())
adapter = X509Adapter(max_retries=3, cert_bytes=cert_bytes, pk_bytes=pk_bytes, encoding=Encoding.DER)
session = requests.Session()
session.mount('https://', adapter)
session.get('url', verify=True)
Upvotes: 2