Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to use a .pfx file with Python requests – also works with .p12 files
import contextlib
import OpenSSL.crypto
import os
import requests
import ssl
import tempfile
@contextlib.contextmanager
def pfx_to_pem(pfx_path, pfx_password):
''' Decrypts the .pfx file to be used with requests. '''
with tempfile.NamedTemporaryFile(suffix='.pem') as t_pem:
f_pem = open(t_pem.name, 'wb')
pfx = open(pfx_path, 'rb').read()
p12 = OpenSSL.crypto.load_pkcs12(pfx, pfx_password)
f_pem.write(OpenSSL.crypto.dump_privatekey(OpenSSL.crypto.FILETYPE_PEM, p12.get_privatekey()))
f_pem.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, p12.get_certificate()))
ca = p12.get_ca_certificates()
if ca is not None:
for cert in ca:
f_pem.write(OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_PEM, cert))
f_pem.close()
yield t_pem.name
# HOW TO USE:
# with pfx_to_pem('foo.pem', 'bar') as cert:
# requests.post(url, cert=cert, data=payload)
@erikbern

This comment has been minimized.

Copy link
Owner Author

@erikbern erikbern commented May 16, 2016

This only took me like three hours to figure out – posting it here in case it's useful to anyone else!

@1999

This comment has been minimized.

Copy link

@1999 1999 commented Nov 21, 2016

@erikbern thank you for this snippet! Works like a charm.

@talespadua

This comment has been minimized.

Copy link

@talespadua talespadua commented Feb 9, 2017

@erikbern, In my attempt p12.get_ca_certificates() returns None. I dont know much about it. Do you know what am I missing?

@erikbern

This comment has been minimized.

Copy link
Owner Author

@erikbern erikbern commented Feb 9, 2017

@talespadua lol I actually googled "python requests p12" right now, found my own gist (which I had forgotten about), and saw your comment. pretty weird coincidence given that you commented on it 40 minutes ago. i'll let you know if i figure out how to make it work

@erikbern

This comment has been minimized.

Copy link
Owner Author

@erikbern erikbern commented Feb 9, 2017

Looks like just filtering out all the missing certs is fine. Code has been updated

@talespadua

This comment has been minimized.

Copy link

@talespadua talespadua commented Feb 9, 2017

@erikbern Yeah, I just saw you commenting in a issue on similar subject. The code now appears to work, although I am having bad handshake for some reason. I can acess the website with selenium + firefox, but having a hard time with requests or selenium + phantomjs. Thanks you for the answer!

@nmohanty28

This comment has been minimized.

Copy link

@nmohanty28 nmohanty28 commented May 3, 2017

@erikbern I am new to python and am trying to send a request using the client cert. You code helps me understand how to attach the pfx. One thing I am confused is what get_cert() is used for? and how do I call the method pfx_to_pem.

Your quick response will help me.

@chalivendri

This comment has been minimized.

Copy link

@chalivendri chalivendri commented May 24, 2017

I am getting error something like this - "PermissionError: [Errno 13] Permission denied:", can you please help?

@greenpau

This comment has been minimized.

Copy link

@greenpau greenpau commented Jun 14, 2017

@erikbern, 👍

@tjmcgi

This comment has been minimized.

Copy link

@tjmcgi tjmcgi commented Aug 31, 2017

Anyone get a ''tlsv1 alert unknown ca' error trying this?

@morefreeze

This comment has been minimized.

Copy link

@morefreeze morefreeze commented Sep 11, 2017

👍 @erikbern

@ghost

This comment has been minimized.

Copy link

@ghost ghost commented Sep 12, 2017

Nice! Exactly what I'm looking for, thanks a lot man!

If anyone's getting Permission denied or file not found error, and you're on Windows, you need to

  1. Remove the open temp file line because NamedTemporaryFile opens it for you and it can't be opened again on Windows
  2. Pass "delete=False" to NamedTemporaryFile as well, otherwise your key gets nuked after the file is closed.
@cttw

This comment has been minimized.

Copy link

@cttw cttw commented Sep 19, 2017

@erikbern
hi, I have a .pfx file and I want to sign some data in PKCS7 format in python. In Java, it is done by first converting .pfx file to .jks(java key store) file and then I use .jks file to sign the data in PKCS7 format. how do I do this in Python?

@mkane848

This comment has been minimized.

Copy link

@mkane848 mkane848 commented Sep 26, 2017

Thanks @erikbern! This has saved me a good bit of troubleshooting time trying to figure out why my requests weren't working :)

@mkane848

This comment has been minimized.

Copy link

@mkane848 mkane848 commented Sep 26, 2017

So I got through the [Errno 13] issue (thanks @d1t69 for the heads up about delete=False), but it seems my credentials are being rejected. They work fine in Postman (Make the request, it asks me to pick my cert, then returns the info I need), so I assume something's going wrong with how it's translating the cert. I checked the contents of the generated .pem file, and the Certificate matches the .pem I used to make the .pfx file but the Key doesn't match the .key file (and trying to substitute that out for the original key gives an SSL Error about asn1 encoding issues).

I also tried this method to no avail. Any insight would be greatly appreciated!

@daultonoryan

This comment has been minimized.

Copy link

@daultonoryan daultonoryan commented Oct 4, 2017

@d1t69 would you mind posting your actual code adjustment I seem to be messing it up somewhere along the road

@mkane848

This comment has been minimized.

Copy link

@mkane848 mkane848 commented Oct 5, 2017

@daultonoryan On Windows, all I had to do was change Line 11 to with tempfile.NamedTemporaryFile(suffix='.pem', delete=False) as t_pem:

The file remains in the folder after the script runs if you leave it like this, so I guess either manually delete it or add a line to delete it after the loop wraps up to clean it out.

@grubbsb

This comment has been minimized.

Copy link

@grubbsb grubbsb commented Nov 13, 2017

@erikbern works great and nice simple example of the implementation. Thank you for sharing 👍

@omedirk

This comment has been minimized.

Copy link

@omedirk omedirk commented Mar 27, 2018

I combined this with a hider based on: (https://benkurtovic.com/2014/06/01/obfuscating-hello-world.html)

that way at least the password is not there when you read the code

def pfx_helper(nIn):
    return (lambda f, n: f(f, n))(
        lambda f, n: chr(n % 256) + f(f, n // 256) if n else "",
        nIn)
def pfx_helperInverse(strInverse):
    codes = [ord(c) for c in strInverse]
    return sum(codes[i] * 256 ** i for i in range(len(codes)))

inverse = pfx_helperInverse("yourpasswordhere")
print ("pfx_helper(",inverse, ")")
print (pfx_helper(inverse))
@tigrus

This comment has been minimized.

Copy link

@tigrus tigrus commented Apr 25, 2018

# HOW TO USE:
# with pfx_to_pem('foo.pem', 'bar') as cert:
#     requests.post(url, cert=cert, data=payload)

Is it correct usage? What will happen, if you will send 100k signed requests?

@AleksandarSavic95

This comment has been minimized.

Copy link

@AleksandarSavic95 AleksandarSavic95 commented May 23, 2018

This is a really nice workaround, but there is a library called requests_pkcs12 which does this job 🙂

@slicendicen2

This comment has been minimized.

Copy link

@slicendicen2 slicendicen2 commented Jul 13, 2018

This was a huge help! Thank You. Worked perfectly for me.

@Lucky2094

This comment has been minimized.

Copy link

@Lucky2094 Lucky2094 commented Aug 7, 2018

I am getting permission denier error upon executing this piece of code
but when i keep delete=False , pem is getting created and not getting deleted, upon executing with this i get SSL Error

@matheussales

This comment has been minimized.

Copy link

@matheussales matheussales commented Oct 25, 2018

I am getting error something like this - "OpenSSL.SSL.Error: [('memory buffer routines', 'BUF_MEM_grow_clean', 'malloc failure'), ('SSL routines', 'read_state_machine', 'BUF lib')]", can you please help? This error occurs every 1 week, more or less.
Thanks.

@szhjia

This comment has been minimized.

Copy link

@szhjia szhjia commented Mar 5, 2019

Thanks a lot

@thedreamerl

This comment has been minimized.

Copy link

@thedreamerl thedreamerl commented Mar 14, 2019

Worked fine just about 5 months ago and now when I try to run my program I am getting an error 'certificate verify failed'. Can you please help?? Any suggestions?
Certificates are up to date((

@arthuralvim

This comment has been minimized.

Copy link

@arthuralvim arthuralvim commented Apr 17, 2019

VOCÊ É UM ARROMBADO!!! Valeuuuuuuuu!

@shacker

This comment has been minimized.

Copy link

@shacker shacker commented May 8, 2020

With this technique, for me anyway, I'm able to decrypt a .pfx file without error, but then it fails authentication when submitting to the server per the example, even though the same .pfx file with same password submits fine via Postman. Don't know why it won't work, but I used these instructions to "decompose" the .pfx into a pair of .pem files, and those can be submitted directly from python requests. And with that technique, you only have to do it once, not on every request.

@kadnan

This comment has been minimized.

Copy link

@kadnan kadnan commented Sep 2, 2020

It works on *nix machine but on Windows, it is giving error

[WinError 32] The process cannot access the file because it is being used by another process: 'C:\\path\to\\\tmpbnb1dy2v.pem'
@dsv-brazil-user-0

This comment has been minimized.

Copy link

@dsv-brazil-user-0 dsv-brazil-user-0 commented Oct 26, 2020

For anyone having "Permission Denied" error, here is the fix (delete=False):

with tempfile.NamedTemporaryFile(suffix='.pem', dir=mainDir, delete=False) as t_pem:

@jgm-ktg

This comment has been minimized.

Copy link

@jgm-ktg jgm-ktg commented Dec 4, 2020

with tempfile.NamedTemporaryFile(suffix='.pem') as t_pem:
        t_pem.close() # better solution on Windows than delete=False
        f_pem = open(t_pem.name, 'wb')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment