diff --git a/google/auth/transport/cpp/windows_signer.cpp b/google/auth/transport/cpp/windows_signer.cpp index 83b2b32e9..5b502f999 100644 --- a/google/auth/transport/cpp/windows_signer.cpp +++ b/google/auth/transport/cpp/windows_signer.cpp @@ -10,7 +10,14 @@ #include #include -struct ECDSA_SIG_st { BIGNUM *r; BIGNUM *s;}; +#include + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +typedef struct ECDSA_SIG_st { + BIGNUM *r; + BIGNUM *s; +} ECDSA_SIG; +#endif #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) #define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0) @@ -269,11 +276,9 @@ bool WinCertStoreKey::Sign(unsigned char *sig, size_t *sig_len, const unsigned c return 1; } -extern "C" -#ifdef _WIN32 -__declspec(dllexport) -#endif -WinCertStoreKey* CreateCustomKey(bool is_rsa_type, bool local_machine_store, const char *store_name, const char *subject) { +extern "C" { + +__declspec(dllexport) WinCertStoreKey* CreateCustomKey(bool is_rsa_type, bool local_machine_store, const char *store_name, const char *subject) { // creating custom key std::cout << "is_rsa_type: " << is_rsa_type << std::endl; std::cout << "local_machine_store: " << local_machine_store << std::endl; @@ -284,45 +289,19 @@ WinCertStoreKey* CreateCustomKey(bool is_rsa_type, bool local_machine_store, con return key; } -extern "C" -#ifdef _WIN32 -__declspec(dllexport) -#endif -void DestroyCustomKey(WinCertStoreKey *key) { +__declspec(dllexport) void DestroyCustomKey(WinCertStoreKey *key) { // deleting custom key printf("In DestroyCustomKey\n"); delete key; } -static PyObject* sign_rsa(PyObject *self, PyObject *args) { - printf("calling sign\n"); - std::string store_name = "MY", subject = "localhost"; - WinCertStoreKey signer(true, false, store_name.c_str(), subject.c_str()); - signer.GetSignerCert(); - signer.GetPrivateKey(); - static const BYTE rgbMsg[] = {0x61, 0x62, 0x63}; - signer.CreateHash((PBYTE)rgbMsg, sizeof(rgbMsg)); - signer.NCryptSign(NULL, NULL); - Py_INCREF(Py_None); - return Py_None; +__declspec(dllexport) bool Sign(WinCertStoreKey *key, unsigned char *sig, size_t *sig_len, const unsigned char *tbs, size_t tbs_len) { + return key->Sign(sig, sig_len, tbs, tbs_len); } -static PyObject* sign_ec(PyObject *self, PyObject *args) { - printf("calling sign\n"); - std::string store_name = "MY", subject = "localhost"; - WinCertStoreKey signer(false, true, store_name.c_str(), subject.c_str()); - signer.GetSignerCert(); - signer.GetPrivateKey(); - static const BYTE rgbMsg[] = {0x61, 0x62, 0x63}; - signer.CreateHash((PBYTE)rgbMsg, sizeof(rgbMsg)); - signer.NCryptSign(NULL, NULL); - Py_INCREF(Py_None); - return Py_None; } static PyMethodDef Methods[] = { - {"sign_rsa", sign_rsa, METH_VARARGS, "The signer function"}, - {"sign_ec", sign_ec, METH_VARARGS, "The signer function"}, {NULL, NULL, 0, NULL} }; diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py index 198169a75..85951c63d 100644 --- a/google/auth/transport/requests.py +++ b/google/auth/transport/requests.py @@ -264,8 +264,8 @@ def __init__(self, cert, key): self._ctx_proxymanager = ctx_proxymanager self.signer = tls_sign.CustomSigner(cert, key) - tls_sign.configure_tls_offload(self.signer, cert, ctx_poolmanager) - tls_sign.configure_tls_offload(self.signer, cert, ctx_proxymanager) + tls_sign.attach_signer_and_cert_to_ssl_context(self.signer, cert, ctx_poolmanager) + tls_sign.attach_signer_and_cert_to_ssl_context(self.signer, cert, ctx_proxymanager) super(_MutualTlsOffloadAdapter, self).__init__() diff --git a/google/auth/transport/tls_sign.py b/google/auth/transport/tls_sign.py index 61811dbb1..e57594efa 100644 --- a/google/auth/transport/tls_sign.py +++ b/google/auth/transport/tls_sign.py @@ -1,17 +1,28 @@ import atexit +import base64 import cffi +import copy import ctypes import os import re from google.auth import exceptions +import requests +callback_type = ctypes.CFUNCTYPE( + ctypes.c_int, + ctypes.POINTER(ctypes.c_ubyte), + ctypes.POINTER(ctypes.c_size_t), + ctypes.POINTER(ctypes.c_ubyte), + ctypes.c_size_t, +) +custom_key_handle_type = ctypes.POINTER(ctypes.c_char) def _cast_ssl_ctx_to_void_p(ssl_ctx): return ctypes.cast(int(cffi.FFI().cast("intptr_t", ssl_ctx)), ctypes.c_void_p) -def offload_signing_ext(): +def _load_offload_signing_ext(): tls_offload_ext = None root_path = os.path.join(os.path.dirname(__file__), "../../../") for filename in os.listdir(root_path): @@ -21,20 +32,13 @@ def offload_signing_ext(): raise exceptions.MutualTLSChannelError( "tls_offload_ext shared library is not found" ) - custom_key_handle = ctypes.POINTER(ctypes.c_char) - callback_type = ctypes.CFUNCTYPE( - ctypes.c_int, - ctypes.POINTER(ctypes.c_ubyte), - ctypes.POINTER(ctypes.c_size_t), - ctypes.POINTER(ctypes.c_ubyte), - ctypes.c_size_t, - ) tls_offload_ext.CreateCustomKey.argtypes = [callback_type] - tls_offload_ext.CreateCustomKey.restype = custom_key_handle - tls_offload_ext.DestroyCustomKey.argtypes = [custom_key_handle] + tls_offload_ext.CreateCustomKey.restype = custom_key_handle_type + tls_offload_ext.DestroyCustomKey.argtypes = [custom_key_handle_type] return tls_offload_ext -def windows_signer_ext(): + +def _load_windows_signer_ext(): windows_signer_ext = None root_path = os.path.join(os.path.dirname(__file__), "../../../") for filename in os.listdir(root_path): @@ -44,28 +48,12 @@ def windows_signer_ext(): raise exceptions.MutualTLSChannelError( "windows_signer_ext shared library is not found" ) - custom_key_handle = ctypes.POINTER(ctypes.c_char) - callback_type = ctypes.CFUNCTYPE( - ctypes.c_int, - ctypes.POINTER(ctypes.c_ubyte), - ctypes.POINTER(ctypes.c_size_t), - ctypes.POINTER(ctypes.c_ubyte), - ctypes.c_size_t, - ) - windows_signer_ext.CreateCustomKey.restype = custom_key_handle - windows_signer_ext.DestroyCustomKey.argtypes = [custom_key_handle] + windows_signer_ext.CreateCustomKey.restype = custom_key_handle_type + windows_signer_ext.DestroyCustomKey.argtypes = [custom_key_handle_type] return windows_signer_ext def _create_pkcs11_sign_callback(key_info): - callback_type = ctypes.CFUNCTYPE( - ctypes.c_int, - ctypes.POINTER(ctypes.c_ubyte), - ctypes.POINTER(ctypes.c_size_t), - ctypes.POINTER(ctypes.c_ubyte), - ctypes.c_size_t, - ) - def sign_callback(sig, sig_len, tbs, tbs_len): import pkcs11 from pkcs11 import KeyType, Mechanism, MGF @@ -111,14 +99,6 @@ def sign_callback(sig, sig_len, tbs, tbs_len): def _create_raw_sign_callback(key_info): - callback_type = ctypes.CFUNCTYPE( - ctypes.c_int, - ctypes.POINTER(ctypes.c_ubyte), - ctypes.POINTER(ctypes.c_size_t), - ctypes.POINTER(ctypes.c_ubyte), - ctypes.c_size_t, - ) - def sign_callback(sig, sig_len, tbs, tbs_len): print("calling sign_callback for raw key....\n") @@ -156,28 +136,47 @@ def sign_callback(sig, sig_len, tbs, tbs_len): return callback_type(sign_callback) -def get_sign_callback(key): - if key["type"] == "pkc11": - return _create_pkcs11_sign_callback(key["key_info"]) - elif key["type"] == "raw": - return _create_raw_sign_callback(key["key_info"]) - raise exceptions.MutualTLSChannelError( - "currently only pkcs11 and raw type are supported" - ) +def _create_daemon_sign_callback(key_info): + def sign_callback(sig, sig_len, tbs, tbs_len): + print("calling sign_callback using daemon....\n") + + body = copy.deepcopy(key_info) + data = ctypes.string_at(tbs, tbs_len) + body["data"] = base64.encodebytes(data).decode('ascii') + print(body) + daemon_sign_endpoint = os.getenv("DAEMON_SIGN_ENDPOINT") + + res = requests.post(daemon_sign_endpoint, json=body) + if not res.ok: + print(res.json()) + return 0 + + signature = res.json()["signature"] + signature = base64.b64decode(signature) + + sig_len[0] = len(signature) + if sig: + for i in range(len(signature)): + sig[i] = signature[i] + + return 1 + + return callback_type(sign_callback) + class CustomSigner(object): def __init__(self, cert, key): + key_info = key["key_info"] + self.offload_signing_ext = _load_offload_signing_ext() if os.name == "nt" and key["type"] == "windows": from cryptography import x509 from cryptography.hazmat.primitives.asymmetric import rsa public_key = x509.load_pem_x509_certificate(cert).public_key() is_rsa = (isinstance(public_key, rsa.RSAPublicKey)) print(f"is_rsa is: {is_rsa}") - key_info = key["key_info"] is_local_machine_store = (key_info["provider"] == "local_machine") - self.offload_signing_ext = offload_signing_ext() self.offload_signing_function = self.offload_signing_ext.OffloadSigning - self.windows_signer_ext = windows_signer_ext() + self.windows_signer_ext = _load_windows_signer_ext() self.signer = self.windows_signer_ext.CreateCustomKey( ctypes.c_bool(is_rsa), ctypes.c_bool(is_local_machine_store), @@ -187,9 +186,17 @@ def __init__(self, cert, key): self.cleanup_func = self.windows_signer_ext.DestroyCustomKey atexit.register(self.cleanup) else: - self.offload_signing_ext = offload_signing_ext() self.offload_signing_function = self.offload_signing_ext.OffloadSigning - self.sign_callback = get_sign_callback(key) + if key["type"] == "pkc11": + self.sign_callback = _create_pkcs11_sign_callback(key_info) + elif key["type"] == "raw": + self.sign_callback = _create_raw_sign_callback(key_info) + elif key["type"] == "daemon": + self.sign_callback = _create_daemon_sign_callback(key_info) + else: + raise exceptions.MutualTLSChannelError( + "currently only pkcs11 and raw type are supported" + ) self.signer = self.offload_signing_ext.CreateCustomKey(self.sign_callback) self.cleanup_func = self.offload_signing_ext.DestroyCustomKey atexit.register(self.cleanup) @@ -199,7 +206,8 @@ def cleanup(self): print("calling self.offload_signing_ext.DestroyCustomKey") self.cleanup_func(self.signer) -def configure_tls_offload(signer, cert, ctx): + +def attach_signer_and_cert_to_ssl_context(signer, cert, ctx): if not signer.offload_signing_function( signer.signer, ctypes.c_char_p(cert), diff --git a/offload_sample/daemon.py b/offload_sample/daemon.py index d35cbe843..7ecc9aba2 100644 --- a/offload_sample/daemon.py +++ b/offload_sample/daemon.py @@ -1,4 +1,6 @@ from flask import Flask, request, jsonify +import google.auth.transport.tls_sign + app = Flask(__name__) @@ -14,5 +16,5 @@ def home(): @app.route('/sign', methods=['POST']) def sign(): content = request.json - print(content['mytext']) + print(content) return jsonify({"size":1, "signature": "haha"}) \ No newline at end of file diff --git a/offload_sample/sample.py b/offload_sample/sample.py index 11ab69060..8993cc4c7 100644 --- a/offload_sample/sample.py +++ b/offload_sample/sample.py @@ -75,6 +75,24 @@ def callback(): return cert, key return callback +def callback_daemon_windows_rsa(): + with open(rsa_cert_file, "rb") as f: + cert = f.read() + + key = { + "type": "daemon", + "key_info": { + "type": "windows", + "key_info": { + "provider": "local_machine", + "store_name": "MY", + "subject": "localhost" + } + } + } + + return cert, key + def run_sample(callback): authed_session = AuthorizedSession(creds) print("=== before configure_mtls_channel===") @@ -101,4 +119,6 @@ def run_sample(callback): print("================= using raw rsa key") run_sample(callback_raw(rsa_cert_file, rsa_key_file)) print("================= using raw ec key") - run_sample(callback_raw(ec_cert_file, ec_key_file)) \ No newline at end of file + run_sample(callback_raw(ec_cert_file, ec_key_file)) + + # run_sample(callback_daemon_windows_rsa) \ No newline at end of file