SSL error in python (again)

Adrian4
Head in the Cloud

SSL error in python (again)

Hello,

 

I have been making and running python API scripts on my computer for about year now no problem. I have to specify the path to a certificate in each of my API calls with verify="path/cert".

However, I have compiled one of my applications into a exe with auto-py-exe so I can share it with co-workers (who do not have python installed).

The exe works fine on my computer but on anyone else's they get - 

requests.exceptions.SSLError: HTTPSConnectionPool(host='api.meraki.com', port=443): Max retries exceeded with url: /api/v1/organizations/xxxxx/networks (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:992)')))


When I test on my computer, I am using the actual exe that I am sending to other people, with the same app directory and certificate etc   DigiCert Global Root G2.crt. 

I tried installing the cert on their computers both for the machine and user - no effect.

Does anyone know why it doesnt work?

4 Replies 4
PhilipDAth
Kind of a big deal
Kind of a big deal

What about embedding the actual certificate into your code, rather than referencing it externally?

Adrian4
Head in the Cloud

Hi,

 

iv never done that before, would have to find out how to do it.

But I'm struggling to understand what the actual issue is. Its not like the code cant find the certificate because if i remove the cert it changes error and complains about cant find cert. And its not like the code somehow isn't handling the SSL ok because it works on my own computer.

The only significant difference between the laptop that works and all the others that dont, is that I have python installed - so maybe its something to do with how auto-py-to-exe is packaging the exe?

But then when i change the code to verify=False, it works ok - so if it is a packaging issue it must be something to do specifically with the SSL module?



PhilipDAth
Kind of a big deal
Kind of a big deal

An interesting experiment would be to install Python on one of the machines and see if it works.  If it does - you know it is auto-py-to-exe.

 

Can you share the code used to load the certificate, and the function it is used in?

Adrian4
Head in the Cloud

I was thinking of that, but I only have one test computer and I'm worried if installing python does fix the issue, I then wont be able to revert it easily to its previous state to continue testing.

At first (just in pycharm, before trying exe) my scripts were all using

verify=f"{root_path}/Cisco Umbrella Root CA.crt"

 

 

which is a cert I got from the Meraki Dashboard I think? That worked for months until one day it stopped, so I went to the Dashboard again and found the cert was now DigiCert Global Root G2.crt - so I swapped it and it worked fine.

DigiCert was the one I was using when I first tried to package into exe. When it didn't work I also tried Digicert TLS RSA etc etc.

Then I tried just relying on Certifi - didnt work for the exe but I noticed my pycharm code was using it ok (didnt work a year ago when I first started coding) - so I have now changed the api calls in every script to just remove the verify bit.

 

 

 

 

 

 
script_path = sys.argv[0]
root_path = os.path.dirname(os.path.abspath(script_path))

def get_network_names():
logging_config.log_function_start()
retry_count = 3
timeout = 1

networks_url = f"https://api.meraki.com/api/v1/organizations/{org_id}/networks"

for attempt in range(retry_count):
try:
networks = requests.get(networks_url, headers=headers, timeout=timeout)
logging_config.log_API_CALL(f"GET 1: {networks_url} {networks}")
time.sleep(DELAY)
network_data = networks.json()
print(network_data)

if networks.status_code not in [200, 201]:
logging_config.log_info(f"Error! HTTP status code: {networks.status_code}, Response text: {networks.text}")
messagebox.showerror("Error", (f"Error! HTTP status code: {networks.status_code}, Response text: {networks.text}"))
return [] # Return an empty list to indicate failure

for network in networks.json():
network_name_to_id[network["name"].lower()] = network["id"]


network_names = sorted([network["name"].lower() for network in networks.json()])

break

except requests.exceptions.Timeout:
logging_config.log_exception(f"Request timed out. Retrying... Attempt {attempt + 1}/{retry_count}")
time.sleep(DELAY)
except requests.exceptions.HTTPError as e:
logging_config.log_exception(f"HTTP Error occurred: {e}")
messagebox.showerror("Error", str(e))
return []
except requests.exceptions.RequestException as e:
logging_config.log_exception(f"Request Exception occurred: {e}")
messagebox.showerror("Error", str(e))
return []
except Exception as e:
logging_config.log_exception(f"Unhandled Exception occurred: {e}")
messagebox.showerror("Error", str(e))
return []

logging_config.log_function_finish()
return network_names, network_name_to_id, network_data
Get notified when there are additional replies to this discussion.