I solved it using :

requests.post(url,headers=hdr,json={"filterList":[{}]}, cert='myprivate.pem')
Answer from user5023028 on Stack Overflow
🌐
Python
docs.python.org › 3 › library › ssl.html
ssl — TLS/SSL wrapper for socket objects — Python 3.14.4 ...
Deprecated since version 3.6: It ... use SSLContext.wrap_socket() to wrap a socket. Changed in version 3.7: SSLSocket instances must to created with wrap_socket(). In earlier versions, it was possible to create instances directly. This was never documented or officially supported. Changed in version 3.10: Python now uses ...
🌐
Pythontic
pythontic.com › ssl › sslcontext › sslcontext
SSLcontext() method of SSLcontext class in Python | Pythontic.com
The SSLContext() method creates an SSLContext object which is used for storing SSL related settings and artefacts like SSL certificates, private key and CA certificates.
🌐
GitHub
github.com › encode › httpx › issues › 924
How can I use a custom SSLContext / PyOpenSSLContext when creating a Client? · Issue #924 · encode/httpx
May 2, 2020 - One very oft-asked feature for requests.py was making requests with user-provided SSLContexts 2118. Eventually that was resolved by allowing us to pass SSLContexts to Adapters, then mounting the adapter onto a session.
Author   kafonek
🌐
GitHub
github.com › python › cpython › blob › main › Lib › ssl.py
cpython/Lib/ssl.py at main · python/cpython
"""Create a SSLContext object for Python stdlib modules · · All Python stdlib modules shall use this function to create SSLContext · objects in order to keep common settings in one place. The configuration · is less restrict than create_default_context()'s to increase backward ·
Author   python
Top answer
1 of 2
6

In order to make the requests library use a custom ssl context, you need to create a custom HTTPAdapter class and override the init_poolmanager method to pass in extra arguments to the base class's implementation.

See sample code here:

from requests import Session
from requests.adapters import HTTPAdapter
import ssl


class CustomHTTPAdapter(HTTPAdapter):

    def init_poolmanager(self, *args, **kwargs):
        # this creates a default context with secure default settings,
        # which enables server certficiate verification using the
        # system's default CA certificates
        context = ssl.create_default_context()

        # alternatively, you could create your own context manually
        # but this does NOT enable server certificate verification
        # context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

        super().init_poolmanager(*args, **kwargs, ssl_context=context)


def main():
    client_session = Session()
    client_session.mount("https://", CustomHTTPAdapter())

    # now you can use the client_session to make requests
    # r = client_session.get("https://<web address>/rest/info?f=json")
2 of 2
1

Creating an ssl.SSLContext() on its own doesn't enable certificate verification or load CA certificates by default. This is why you're not seeing SSL errors. Using ssl.create_ssl_context() does set verification by default.

So the issue here isn't with SSLContext or certifi, it's with the website's certificate and how you're constructing your SSLContext. Next step would be to look into why the certificate the website is presenting isn't valid.

🌐
Electricmonk
electricmonk.nl › log › 2018 › 06 › 02 › ssl-tls-client-certificate-verification-with-python-v3-4-sslcontext
SSL/TLS client certificate verification with Python v3.4+ SSLContext | Electricmonk.nl weblog
June 2, 2018 - Since Python v3.4, the more secure, and thus preferred method of wrapping a socket in the SSL/TLS layer is to create an SSLContext instance and call SSLContext.wrap_socket(). However, the SSLContext.wrap_socket() method does not have the ca_certs parameter.
🌐
ProgramCreek
programcreek.com › python › example › 72757 › ssl.SSLContext
Python Examples of ssl.SSLContext
def __init__(self, target): # Target comes as protocol://target:port/path self.target = target proto, host, path = target.split(':') host = host[2:] self.path = '/' + path.split('/', 1)[1] if proto.lower() == 'https': #Create unverified (insecure) context try: uv_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) self.session = HTTPSConnection(host,context=uv_context) except AttributeError: #This does not exist on python < 2.7.11 self.session = HTTPSConnection(host) else: self.session = HTTPConnection(host) self.lastresult = None
🌐
Python.org
discuss.python.org › core development
`ssl`: changing the default `SSLContext.verify_flags`? - Core Development - Discussions on Python.org
July 25, 2023 - At the moment (CPython 3.11), the default SSLContext.verify_flags is set to just VERIFY_X509_TRUSTED_FIRST: >>> import ssl >>> ssl.create_default_context().verify_flags <VerifyFlags.VERIFY_X509_TRUSTED_FIRST: 32768> I…
Find elsewhere
🌐
MicroPython
docs.micropython.org › en › latest › library › ssl.html
ssl – SSL/TLS module — MicroPython latest documentation
Wrap the given sock and return a new wrapped-socket object. The implementation of this function is to first create an SSLContext and then call the SSLContext.wrap_socket method on that context object. The arguments sock, server_side and server_hostname are passed through unchanged to the method ...
🌐
Pyopenssl
pyopenssl.org › en › latest › api › ssl.html
SSL — An interface to the SSL-specific parts of OpenSSL — pyOpenSSL 26.0.0 documentation
protos – A list of the protocols to be offered to the server. This list should be a Python list of bytestrings representing the protocols to offer, e.g.
🌐
Python
docs.python.org › 3.3 › library › ssl.html
18.2. ssl — TLS/SSL wrapper for socket objects — Python 3.3.7 documentation
For more sophisticated applications, the ssl.SSLContext class helps manage settings and certificates, which can then be inherited by SSL sockets created through the SSLContext.wrap_socket() method.
🌐
Readthedocs
python-security.readthedocs.io › ssl.html
Python SSL and TLS security — Python Security 0.0 documentation
New in Python 3.2. ... SSLContext.load_verify_locations(): This method can also load certification revocation lists (CRLs) in PEM or DER format.
🌐
Stack Overflow
stackoverflow.com › questions › 36026846 › ssl-context-for-older-python-version
sockets - SSL Context for older python version - Stack Overflow
headers = {'content-type': 'ContentType.APPLICATION_XML'} uri = "www.client.url.com/hit-here/" clientCert = "path/to/cert/abc.crt" clientKey = "path/to/key/abc.key" PROTOCOL = ssl.PROTOCOL_TLSv1 context = ssl.SSLContext(PROTOCOL) context.load_default_certs() context.load_cert_chain(clientCert, clientKey) conn = httplib.HTTPSConnection(uri, some_port, context=context)
🌐
Medium
rob-blackbourn.medium.com › secure-communication-with-python-ssl-certificate-and-asyncio-939ae53ccd35
Secure Communication With Python SSL Certificate and Asyncio | by Rob Blackbourn | Medium
July 22, 2023 - import asyncio from os.path import expanduser import socket import ssl async def tcp_echo_client(message): host = socket.gethostname() context = ssl.SSLContext(ssl.PROTOCOL_TLS) # Load the client certificate.
🌐
w3resource
w3resource.com › python-exercises › urllib3 › python-urllib3-exercise-15.php
Custom SSL Context in Python urllib3 for secure HTTPS requests
Learn how to implement a custom SSL context in Python urllib3 for tailored SSL configurations, enabling secure and flexible HTTPS requests.
🌐
Pythontic
pythontic.com › ssl › sslcontext › introduction
The SSLContext class in Python | Pythontic.com
The SSLContext object in Python acts as a place to initialize SSL settings before connecting to a peer using SSL protocol. An SSLcontext object also has methods for validating the certificates and SSLSocket creation.
🌐
GitHub
github.com › ramikg › ssl-context-configurator
GitHub - ramikg/ssl-context-configurator: Configure Python SSLContext objects in a hacky way
Unfortunately, Python does not allow the full SSL/TLS configuration power offered by OpenSSL. Through some ctypes fun, this library finds the underlying SSL_CTX C object in memory, and configures it by calling the OpenSSL function SSL_CONF_cmd.
Author   ramikg
Top answer
1 of 2
3

In your callback, cb_context is the same context on which wrap_socket() was called, and the same as socket.context, so socket.context = cb_context sets the context to the same it was before.

Changing the certificate chain of a context does not affect the certificate used for the current wrap_socket() operation. The explanation for this lies in how openssl creates its underlying objects, in this case the underlying SSL structures have already been created and use copies of the chains:

NOTES

The chains associate with an SSL_CTX structure are copied to any SSL structures when SSL_new() is called. SSL structures will not be affected by any chains subsequently changed in the parent SSL_CTX.

When setting a new context, the SSL structures are updated, but that update is not performed when the new context is equal to the old one.

You need to set sock.context to a different context to make it work. You currently instantiate a new context on each new incoming connection, which is not needed. Instead you should instantiate your standard context only once and reuse that. Same goes for the dynamically loaded contexts, you could create them all on startup and put them in a dict so you can just do a lookup, e.g:

...

contexts = {}

for hostname in os.listdir("ssl"):
    print('Loading certs for {}'.format(hostname))
    server_cert = "ssl/{}/server".format(hostname)
    context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
    context.load_cert_chain(certfile="{}.crt".format(server_cert),
                            keyfile="{}.key".format(server_cert))
    contexts[hostname] = context

def servername_callback(sock, req_hostname, cb_context, as_callback=True):
    context = contexts.get(req_hostname)
    if context is not None:
        sock.context = context
    else:
        pass  # handle unknown hostname case

def run_server(hostname, port):
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.bind((hostname, port))
    s.listen(8)
    print("Serving on {}:{}".format(hostname, port))

    context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
    context.set_servername_callback(servername_callback)
    default_cert = "ssl/3.1/server"
    context.load_cert_chain(certfile="{}.crt".format(default_cert),
                            keyfile="{}.key".format(default_cert))

    try:
        while True:
            (c, a) = s.accept()
            ssl_sock = context.wrap_socket(c, server_side=True)
            try:
                handle_client(ssl_sock, a)
            finally:
                c.close()

    except KeyboardInterrupt:
        s.close()
2 of 2
2

So after looking at this post and a few others online, I put together a version of the code above, that worked for me perfectly... so I just thought I would share. In case it helps anyone else.

import sys
import ssl
import socket
import os

from pprint import pprint

DOMAIN_CONTEXTS = {}

ssl_root_path = "c:/ssl/"

# ----------------------------------------------------------------------------------------------------------------------
#
# As an example create domains in the ssl root path...ie
#
# c:/ssl/example.com
# c:/ssl/johndoe.com
# c:/ssl/test.com
#
# And then create self signed ssl certificates for each domain to test... and put them in the corresponding domain 
# directory... in this case the cert and key files are called cert.pem, and key.pem.... 
#

def setup_ssl_certs():

    global DOMAIN_CONTEXTS

    for hostname in os.listdir(ssl_root_path):

        #print('Loading certs for {}'.format(hostname))

        # Establish the certificate and key folder...for the various domains...
        server_cert = '{rp}{hn}/'.format(rp=ssl_root_path, hn=hostname)

        # Setup the SSL Context manager object, for authentication
        context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)

        # Load the certificate file, and key file...into the context manager.
        context.load_cert_chain(certfile="{}cert.pem".format(server_cert), keyfile="{}key.pem".format(server_cert))

        # Set the context object to the global dictionary
        DOMAIN_CONTEXTS[hostname] = context

    # Uncomment for testing only.
    #pprint(contexts)

# ----------------------------------------------------------------------------------------------------------------------

def servername_callback(sock, req_hostname, cb_context, as_callback=True):
    """
    This is a callback function for the SSL Context manager, this is what does the real work of pulling the
    domain name in the origional request.
    """

    # Uncomment for testing only
    #print(sock)
    #print(req_hostname)
    #print(cb_context)

    context = DOMAIN_CONTEXTS.get(req_hostname)

    if context:

        try:
            sock.context = context
        except Exception as error:
            print(error)
        else:
            sock.server_hostname = req_hostname

    else:
        pass  # handle unknown hostname case


def handle_client(conn, a):

    request_domain = conn.server_hostname

    request = conn.recv()

    client_ip = conn.getpeername()[0]

    resp = 'Hello {cip} welcome, from domain {d} !'.format(cip=client_ip, d=request_domain)

    conn.write(b'HTTP/1.1 200 OK\n\n%s' % resp.encode())


def run_server(hostname, port):

    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    s.bind((hostname, port))

    s.listen(8)

    #print("Serving on {}:{}".format(hostname, port))

    context = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)

    # For Python 3.4+
    context.set_servername_callback(servername_callback)

    # Only available in 3.7 !!!! have not tested it yet...
    #context.sni_callback(servername_callback)

    default_cert = "{rp}default/".format(rp=ssl_root_path)

    context.load_cert_chain(certfile="{}cert.pem".format(default_cert), keyfile="{}key.pem".format(default_cert))

    context.options |= ssl.OP_NO_TLSv1 | ssl.OP_NO_TLSv1_1  # optional

    context.set_ciphers('EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH')

    try:
        while True:

            ssock, addr = s.accept()

            try:
                conn = context.wrap_socket(ssock, server_side=True)

            except Exception as error:
                print('!!! Error, {e}'.format(e=error))

            except ssl.SSLError as e:
                print(e)

            else:
                handle_client(conn, addr)

                if conn:
                    conn.close()
                    #print('Connection closed !')

    except KeyboardInterrupt:
        s.close()

# ----------------------------------------------------------------------------------------------------------------------

def main():

    setup_ssl_certs()

    # Don't forget to update your static name resolution...  ie example.com = 127.0.0.1
    run_server('example.com', 443)

# ----------------------------------------------------------------------------------------------------------------------

if __name__ == '__main__':
    main()