Me han proporcionado un certificado pem para autenticar con un tercero. La autenticación mediante certificados es un concepto nuevo para mí.
Dentro hay dos certificados y una clave privada.
El emisor ha informado que no admite la verificación SSL pero usa TLS (1.1/1.2).
He ejecutado un script como el siguiente:
import requests as req import json url = 'https://url.com/call' certificate_file = "C:/certs/cert.pem" headers = {"Content-Type": "application/json"} req_body ={ "network":{ "network_id": 12345 }, "branch":{ "branch_id": 12345, }, "export_period":{ "start_date_time": "16-11-2021 00:00:00", "end_date_time": "17-11-2021 00:00:00" } } jsonObject = json.dumps(req_body) response = req.post(url,headers=headers,params=jsonObject,verify=certificate_file)Recibo el siguiente error:
SSLError: HTTPSConnectionPool(host='url.com, port=443): Se excedieron los reintentos máximos con url: /call?%7B%22network%22:%20%7B%22network_id%22:%2012345%7D,%20%22branch %22:%20%7B%22branch_id%22:%2012345%7D,%20%22export_period%22:%20%7B%22start_date_time%22:%20%2216-11-2021%2000:00:00%22, %20%22end_date_time%22:%20%2217-11-2021%2000:00:00%22%7D%7D (Causado por SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] verificación de certificado fallida: no se pudo obtener certificado del emisor (_ssl.c:1123)')))
Agradecería orientación, mi instinto dice que debería estar haciendo algo específico para TLS, de ahí el error de SSL.
El emisor está utilizando una versión actualizada de HTTPS: SSL es el término más utilizado, pero TLS es el más correcto. Parece que su configuración es correcta, lo que significa que debe llamarlo con un certificado de cliente confiable, como parte de una solicitud HTTPS.
Recomendaría hacerlo primero con la herramienta curl para que pueda verificar que la API funciona como se espera.
curl -s -X GET "https://api.example.com/test" \ --cert ./certs/example.client.pem \ --key ./certs/example.client.key \ --cacert ./certs/ca.pem \ -H "Content-Type: application/json" Divida los certificados en archivos separados como se indicó anteriormente. Parece que uno de ellos es una autoridad de certificación raíz en la que debe decirle a la pila de tecnología del cliente que confíe; para curl, esto se hace usando el parámetro cacert como se indicó anteriormente.
Una vez que esto funcione, puede seguir el mismo enfoque en la biblioteca de solicitudes de Python. Creo que esto usa cert y verify parámetros como este. Entonces parece que su código no está muy lejos.
result = requests.get( 'https://api.example.com', cert=('example.pem', 'example.key'), verify='ca.pem')MÁS SOBRE TLS MUTUO
Por interés, si alguna vez desea desmitificar Mutual TLS y comprender más, eche un vistazo a estos recursos avanzados de Curity:
Estos incluyen un OpenSSL Script que puede ejecutar para ver cómo deberían verse los archivos de certificados separados.
El emisor ha informado que no admite la verificación SSL
Para mí, esto suena bastante arriesgado, pero si ese es el caso, un simple
verify=Falsedebería hacer el truco. Nota: esto deshabilita por completo la verificación de los certificados SSL para esta llamada.
Además, en caso de que aún desee los certificados SSL allí (copiar y pegar de mi comentario):
No creo que deba hacer nada con TLS, esto generalmente se recoge a medida que se realiza la conexión. En cambio, parece estar en algún lugar del certificado (no es correcto o autofirmado y no verificado) o falta un certificado intermedio en la cadena. Alternativamente, su lista de CA (autoridades de certificación) podría estar incompleta. Nunca he usado esto en python, pero aparentemente hay formas de actualizarlo usando certifi . La documentación sobre esto se puede encontrar en esta pregunta SO relevante .
Encontré una pregunta similar con respuestas. Parece que es posible que la biblioteca de seguridad del sistema no encuentre el certificado en la cadena porque "solo las cadenas de certificados que están almacenadas en cacert.pem se consideran válidas".