Last active
March 18, 2024 19:50
-
-
Save klali/3a20c28c0fc78c924756bfb94b498f1c to your computer and use it in GitHub Desktop.
sample for using a yubihsm2 with python requests
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
try: | |
from OpenSSL._util import ( | |
ffi as _ffi, | |
lib as O, | |
lib as S | |
) | |
pyopenssl = True | |
import sys | |
null = _ffi.NULL | |
# the engine loaded here has to have an ABI matching that of the openssl that | |
# is used by cryptography, that means it's probably openssl 1.1 | |
p11 = b"/tmp/openssl-p11/prefix/lib/engines-1.1/pkcs11.so" | |
except ImportError: | |
pyopenssl = False | |
import ctypes | |
O = ctypes.CDLL("/usr/lib/x86_64-linux-gnu/libcrypto.so") | |
S = ctypes.CDLL("/usr/lib/x86_64-linux-gnu/libssl.so") | |
null = None | |
p11 = b"/usr/lib/ssl/engines/libpkcs11.so" | |
O.ENGINE_load_dynamic() | |
e = O.ENGINE_by_id(b"dynamic") | |
print(e) | |
print(O.ENGINE_ctrl_cmd_string(e, b"SO_PATH", p11, 0)) | |
print(O.ENGINE_ctrl_cmd_string(e, b"LOAD", null, 0)) | |
# where to find the yubihsm_pkcs11.so | |
print(O.ENGINE_ctrl_cmd_string(e, b"MODULE_PATH", b"yubihsm_pkcs11.so", 0)) | |
# authenticate to the YubiHSM (id+password) | |
print(O.ENGINE_ctrl_cmd_string(e, b"PIN", b"0001password", 0)) | |
print(O.ENGINE_init(e)) | |
# load a key with id 0x0001 | |
key = O.ENGINE_load_private_key(e, b"0:0001", null, null) | |
import requests | |
from requests.adapters import HTTPAdapter | |
from requests.packages.urllib3.util.ssl_ import create_urllib3_context | |
from requests.packages.urllib3.poolmanager import PoolManager | |
class YubihsmAdapter(HTTPAdapter): | |
def init_poolmanager(self, connections, maxsize, block=False, *args, **kwargs): | |
context = create_urllib3_context() | |
if(pyopenssl): | |
# if pyopenssl is in use we can find the SSL_CTX in a semi-clean way | |
ctx = context._ctx._context | |
else: | |
# if the builtin ssl module is in use we have to jump blindly to the | |
# third element in the struct and rely on cpython returning the adress | |
# with id() on an object. | |
ctx = ctypes.c_void_p.from_address(id(context) + ctypes.sizeof(ctypes.c_void_p) * 2) | |
# point the SSL_CTX to a certificate matching our key | |
print(S.SSL_CTX_use_certificate_file(ctx, b"cert.pem", 1)) | |
# and load the key into the SSL_CTX | |
print(S.SSL_CTX_use_PrivateKey(ctx, key)) | |
kwargs['ssl_context'] = context | |
self.poolmanager = PoolManager( | |
num_pools=connections, maxsize=maxsize, | |
block=block, *args, **kwargs) | |
s = requests.Session() | |
# the URL "mounted" has to be longer than https:// and match whatever it is | |
# we're going to use for our requests | |
s.mount("https://127.0.0.1", YubihsmAdapter()) | |
print(s.get("https://127.0.0.1:8443", verify=False)) |
This was useful to me, wanted to share a cleaner (IMO) way of accessing the context object with ssl
:
You have this:
ctx = ctypes.cast(id(context) + ctypes.sizeof(ctypes.c_void_p) * 2, ctypes.POINTER(ctypes.c_void_p)).contents
This also works:
from ctypes import c_void_p, sizeof
ctx = c_void_p.from_address(id(context) + sizeof(c_void_p) * 2)
from_address uses the value at the given address
to create the c_void_p
.
Second question, When I import OpenSSL._util as your code. Python reports error as following do you know why? Did I do something wrong?
_lib.ENGINE_load_builtin_engines() AttributeError: module 'lib' has no attribute 'ENGINE_load_builtin_engines' or AttributeError: module 'lib' has no attribute 'ENGINE_load_dynamic'
You probably need to use cryptography==2.5 as cryptography==2.6.1 remove a lot of "unused" function.
Commit:
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thank you so much @klali. I tried that as your suggested. But I still get the same error:
I'm actually using ctypes not the
OpenSSL._util
. Here is my setup:I assume it should not matter but I do not know if it makes a difference?
Second question, When I import OpenSSL._util as your code. Python reports error as following do you know why? Did I do something wrong?
Thank you so much for your help!