Repository: pypa/pipenv

Issue:
verify_ssl broken in 2023.6.2
When upgrading pipenv from `2023.5.19` to `2023.6.2` verify_ssl=false seems to be ignored, resulting in the following error:
```bash
Max retries exceeded with URL: [...] certificate verify failed: self signed certificate in certificate chain
````
I am still able to reproduce on master. Also I tried digging into the few commits between those two versions without success.

### Workaround:

Revert to `2023.5.19`

### Steps to replicate

Create a simple Pipefile with a private self-signed PyPi repo and verify_ssl=false

### Platform

win32 (not tested on unix/linux/mac)



Discussion:
I wonder if it has anything to do with the `_get_hashes_from_remote_index_urls` pep 508 work to get hashes from the URLs ... it uses a requests session during the lock phase, and that definitely doesn't consider `verify_ssl` at all ... could you help me further understand what action you are taking when getting the error?
Sure, here is the full log. Please note that when using `sync` instead of `install` pipenv is able to properly bypass the ssl certificate check. This also points to a missing `verify_ssl` support during the lock phase.
<details>
<blockquote>
$ pipenv install
Creating a virtualenv for this project...
Pipfile: PIPFILE_ROOT\Pipfile
Using HOME/AppData/Local/Programs/Python/Python39/python.exe (3.9.12) to create virtualenv...
[   =] Creating virtual environment...created virtual environment CPython3.9.12.final.0-64 in 9236ms
  creator CPython3Windows(dest=HOME\.virtualenvs\riKWXtd8, clear=False, no_vcs_ignore=False, global=False)
  seeder FromAppData(download=False, pip=bundle, setuptools=bundle, wheel=bundle, via=copy, app_data_dir=HOME\AppData\Local\pypa\virtualenv)
    added seed packages: pip==23.1.2, setuptools==67.7.2, wheel==0.40.0
  activators BashActivator,BatchActivator,FishActivator,NushellActivator,PowerShellActivator,PythonActivator

Successfully created virtual environment!
Virtualenv location: HOME\.virtualenvs\riKWXtd8
Pipfile.lock not found, creating...
Locking [packages] dependencies...
Building requirements...
Resolving dependencies...
Locking Failed!
[=   ] Locking...
Traceback (most recent call last):
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\urllib3\connectionpool.py", line 703, in urlopen
    httplib_response = self._make_request(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\urllib3\connectionpool.py", line 386, in _make_request
    self._validate_conn(conn)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\urllib3\connectionpool.py", line 1042, in _validate_conn
    conn.connect()
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\urllib3\connection.py", line 419, in connect
    self.sock = ssl_wrap_socket(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\urllib3\util\ssl_.py", line 449, in ssl_wrap_socket
    ssl_sock = _ssl_wrap_socket_impl(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\urllib3\util\ssl_.py", line 493, in _ssl_wrap_socket_impl
    return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 1040, in _create
    self.do_handshake()
  File "HOME\AppData\Local\Programs\Python\Python39\lib\ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1129)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\requests\adapters.py", line 489, in send
    resp = conn.urlopen(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\urllib3\connectionpool.py", line 787, in urlopen
    retries = retries.increment(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\urllib3\util\retry.py", line 592, in increment
    raise MaxRetryError(_pool, url, error or ResponseError(cause))
pipenv.patched.pip._vendor.urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host='artifactory-pm.mlp.com', port=443): Max retries exceeded with url: /artifactory/api/pypi/pm-one11cap-pypi-virtual/simple/o11pandas/ (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1129)')))
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\resolver.py", line 845, in <module>
    main()
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\resolver.py", line 831, in main
    _main(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\resolver.py", line 811, in _main
    resolve_packages(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\resolver.py", line 759, in resolve_packages
    results, resolver = resolve(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\resolver.py", line 738, in resolve
    return resolve_deps(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\utils\resolver.py", line 1154, in resolve_deps
    results, hashes, markers_lookup, resolver, skipped = actually_resolve_deps(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\utils\resolver.py", line 954, in actually_resolve_deps
    hashes = resolver.resolve_hashes()
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\utils\resolver.py", line 855, in resolve_hashes
    self.hashes[ireq] = self.collect_hashes(ireq)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\utils\resolver.py", line 835, in collect_hashes
    hashes = self._get_hashes_from_remote_index_urls(ireq, source)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\utils\resolver.py", line 783, in _get_hashes_from_remote_index_urls
    response = session.get(pkg_url, timeout=10)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\requests\sessions.py", line 600, in get
    return self.request("GET", url, **kwargs)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\requests\sessions.py", line 587, in request
    resp = self.send(prep, **send_kwargs)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\requests\sessions.py", line 701, in send
    r = adapter.send(request, **kwargs)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\patched\pip\_vendor\requests\adapters.py", line 563, in send
    raise SSLError(e, request=request)
pipenv.patched.pip._vendor.requests.exceptions.SSLError: HTTPSConnectionPool(host='artifactory-pm.mlp.com', port=443): Max retries exceeded with url: /artifactory/api/pypi/pm-one11cap-pypi-virtual/simple/o11pandas/ (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate in certificate chain (_ssl.c:1129)')))

Traceback (most recent call last):
  File "HOME\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 197, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "HOME\AppData\Local\Programs\Python\Python39\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "HOME\AppData\Local\Programs\Python\Python39\Scripts\pipenv.exe\__main__.py", line 7, in <module>
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\vendor\click\core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\cli\options.py", line 58, in main
    return super().main(*args, **kwargs, windows_expand_args=False)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\vendor\click\core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\vendor\click\core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\vendor\click\core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\vendor\click\core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\vendor\click\decorators.py", line 84, in new_func
    return ctx.invoke(f, obj, *args, **kwargs)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\vendor\click\core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\cli\command.py", line 235, in install
    do_install(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\routines\install.py", line 195, in do_install
    do_init(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\routines\install.py", line 800, in do_init
    do_lock(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\routines\lock.py", line 79, in do_lock
    venv_resolve_deps(
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\utils\resolver.py", line 1096, in venv_resolve_deps
    c = resolve(cmd, st, project=project)
  File "HOME\AppData\Local\Programs\Python\Python39\lib\site-packages\pipenv\utils\resolver.py", line 990, in resolve
    raise RuntimeError("Failed to lock Pipfile.lock!")
RuntimeError: Failed to lock Pipfile.lock!
<blockquote>
</details>
I've also been having this issue with version 2023.6.2.

Downgrading to version 2023.5.19 has fixed the issue as suggested by @epizut.
This broke pipenv on my work laptop due to MITM Cisco Umbrella. Downgrading to 2023.5.19 is a workaround as mentioned above.

Resolving patch:
diff --git a/pipenv/utils/internet.py b/pipenv/utils/internet.py
--- a/pipenv/utils/internet.py
+++ b/pipenv/utils/internet.py
@@ -1,21 +1,18 @@
 import re
 from urllib.parse import urlparse
 
+from pipenv.patched.pip._vendor import requests
+from pipenv.patched.pip._vendor.requests.adapters import HTTPAdapter
 from pipenv.patched.pip._vendor.urllib3 import util as urllib3_util
 
-requests_session = None  # type: ignore
 
-
-def _get_requests_session(max_retries=1):
+def _get_requests_session(max_retries=1, verify_ssl=True):
     """Load requests lazily."""
-    global requests_session
-    if requests_session is not None:
-        return requests_session
-    from pipenv.patched.pip._vendor import requests
-
     requests_session = requests.Session()
-    adapter = requests.adapters.HTTPAdapter(max_retries=max_retries)
-    requests_session.mount("https://pypi.org/pypi", adapter)
+    adapter = HTTPAdapter(max_retries=max_retries)
+    requests_session.mount("https://", adapter)
+    if verify_ssl is False:
+        requests_session.verify = False
     return requests_session
 
 
@@ -46,6 +43,7 @@ def create_mirror_source(url, name):
 def download_file(url, filename, max_retries=1):
     """Downloads file from url to a path with filename"""
     r = _get_requests_session(max_retries).get(url, stream=True)
+    r.close()
     if not r.ok:
         raise OSError("Unable to download file")
 
@@ -117,6 +115,7 @@ def proper_case(package_name):
     r = _get_requests_session().get(
         f"https://pypi.org/pypi/{package_name}/json", timeout=0.3, stream=True
     )
+    r.close()
     if not r.ok:
         raise OSError(f"Unable to find package {package_name} in PyPI repository.")
 
diff --git a/pipenv/utils/resolver.py b/pipenv/utils/resolver.py
--- a/pipenv/utils/resolver.py
+++ b/pipenv/utils/resolver.py
@@ -180,6 +180,7 @@ def __init__(
         self._pip_command = None
         self._retry_attempts = 0
         self._hash_cache = None
+        self._sessions = {}
 
     def __repr__(self):
         return (
@@ -594,7 +595,7 @@ def ignore_compatibility_finder(self):
                 session=self.session,
             )
             # It would be nice if `shims.get_package_finder` took an
-            # `ignore_compatibility` parameter, but that's some vendorered code
+            # `ignore_compatibility` parameter, but that's some vendored code
             # we'd rather avoid touching.
             index_lookup = self.prepare_index_lookup()
             ignore_compatibility_finder._ignore_compatibility = True
@@ -744,9 +745,19 @@ def prepend_hash_types(cls, checksums, hash_type):
             cleaned_checksums.add(checksum)
         return cleaned_checksums
 
-    def _get_hashes_from_pypi(self, ireq):
+    def _get_requests_session_for_source(self, source):
+        if self._sessions.get(source["name"]):
+            session = self._sessions[source["name"]]
+        else:
+            session = _get_requests_session(
+                self.project.s.PIPENV_MAX_RETRIES, source.get("verify_ssl", True)
+            )
+            self._sessions[source["name"]] = session
+        return session
+
+    def _get_hashes_from_pypi(self, ireq, source):
         pkg_url = f"https://pypi.org/pypi/{ireq.name}/json"
-        session = _get_requests_session(self.project.s.PIPENV_MAX_RETRIES)
+        session = self._get_requests_session_for_source(source)
         try:
             collected_hashes = set()
             # Grab the hashes from the new warehouse API.
@@ -776,7 +787,7 @@ def _get_hashes_from_pypi(self, ireq):
 
     def _get_hashes_from_remote_index_urls(self, ireq, source):
         pkg_url = f"{source['url']}/{ireq.name}/"
-        session = _get_requests_session(self.project.s.PIPENV_MAX_RETRIES)
+        session = self._get_requests_session_for_source(source)
         try:
             collected_hashes = set()
             # Grab the hashes from the new warehouse API.
@@ -828,7 +839,7 @@ def collect_hashes(self, ireq):
         source = sources[0] if len(sources) else None
         if source:
             if is_pypi_url(source["url"]):
-                hashes = self._get_hashes_from_pypi(ireq)
+                hashes = self._get_hashes_from_pypi(ireq, source)
                 if hashes:
                     return hashes
             else:


Test patch: