sslerror requests insecurerequestwarning failed error certificate_verify_failed python openssl python-requests

python - requests - sslerror ssl certificate_verify_failed certificate verify failed(_ ssl c 777



openssl, python solicita error: "error de verificación del certificado" (3)

Si ejecuto el siguiente comando desde mi caja de desarrollo:

$ openssl s_client -connect github.com:443

Obtengo la siguiente última línea de salida:

Verify return code: 20 (unable to get local issuer certificate)

Si trato de hacer esto con las solicitudes, obtengo otra solicitud fallida:

>>> import requests >>> r = requests.get(''https://github.com/'', verify=True)

Con una excepción planteada:

SSLError: [Errno 1] _ssl.c:507: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

También puedo ejecutar el primer comando con el indicador de verificación y obtener un resultado similar:

$ openssl s_client -connect github.com:443 -verify 9 ... Verify return code: 27 (certificate not trusted)

Básicamente, esto me dice que hay un problema con los certificados. Puedo especificar un certificado específico con ambos métodos y funcionará:

$ openssl s_client -connect github.com:443 -CAfile /etc/ssl/certs/DigiCert_High_Assurance_EV_Root_CA.pem -verify 9 ... Verify return code: 0 (ok)

y:

>>> r = requests.get(''https://github.com/'', verify=''/etc/ssl/certs/DigiCert...pem'') <Response [200]>

Entonces, a mi pregunta, ¿qué es exactamente lo que está mal aquí? ¿Las solicitudes / openssl ya no deberían saber dónde encontrar certificados válidos?

Otra información:

  • Python == 2.7.6
  • peticiones == 2.2.1
  • openssl 0.9.8h

También, sé que el método verify=False al método requests.get también funcionará, pero quiero verificar.

EDITAR

He confirmado que, como lo indicó @Heikki Toivonen en una respuesta, especificar el indicador -CAfile para la versión de openssl que estoy ejecutando funciona.

$ openssl s_client -connect github.com:443 -CAfile `python -c ''import requests; print(requests.certs.where())''` ... Verify return code: 0 (ok)

Así que no hay nada malo con la versión de openssl que estoy ejecutando, y no hay nada malo con el archivo cacert.pem predeterminado que las solicitudes proporcionan.

Ahora que sé que openssl está destinado a funcionar de esa manera, que el archivo de CA o el lugar para encontrar certificados debe especificarse, me preocupa más que las solicitudes funcionen.

Si corro:

>>> r = requests.get(''https://github.com/'', verify=''path to cacert.pem file'')

Todavía estoy recibiendo el mismo error que antes. Incluso intenté descargar el archivo cacert.pem desde http://curl.haxx.se/ca y aún no funcionó. las solicitudes solo parecen funcionar (en esta máquina específica) si especifico un archivo de certificado de proveedor específico.

Una nota al margen: en mi máquina local todo funciona como se espera. Sin embargo, hay varias diferencias entre las dos máquinas. Hasta ahora no he podido determinar cuál es la diferencia específica que causa este problema.


Si ejecuto el siguiente comando desde mi caja de desarrollo:

$ openssl s_client -connect github.com:443

Obtengo la siguiente última línea de salida:

Verify return code: 20 (unable to get local issuer certificate)

Le falta DigiCert High Assurance EV CA-1 como raíz de confianza:

$ openssl s_client -connect github.com:443 CONNECTED(00000003) depth=1 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV CA-1 verify error:num=20:unable to get local issuer certificate verify return:0 --- Certificate chain 0 s:/businessCategory=Private Organization/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/serialNumber=5157550/street=548 4th Street/postalCode=94107/C=US/ST=California/L=San Francisco/O=GitHub, Inc./CN=github.com i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV CA-1 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV CA-1 i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA --- Server certificate ... Start Time: 1393392088 Timeout : 300 (sec) Verify return code: 20 (unable to get local issuer certificate)

Descargue DigiCert High Assurance EV CA-1 de DigiCert Trusted Root Authority Certificates :

$ wget https://www.digicert.com/CACerts/DigiCertHighAssuranceEVCA-1.crt --2014-02-26 00:27:50-- https://www.digicert.com/CACerts/DigiCertHighAssuranceEVCA-1.crt Resolving www.digicert.com (www.digicert.com)... 64.78.193.234 ...

Convertir el certifcado codificado DER a PEM:

$ openssl x509 -in DigiCertHighAssuranceEVCA-1.crt -inform DER -out DigiCertHighAssuranceEVCA-1.pem -outform PEM

Luego, -CAfile con OpenSSL a través del -CAfile :

$ openssl s_client -CAfile DigiCertHighAssuranceEVCA-1.pem -connect github.com:443 CONNECTED(00000003) depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA verify return:1 depth=1 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV CA-1 verify return:1 depth=0 businessCategory = Private Organization, 1.3.6.1.4.1.311.60.2.1.3 = US, 1.3.6.1.4.1.311.60.2.1.2 = Delaware, serialNumber = 5157550, street = 548 4th Street, postalCode = 94107, C = US, ST = California, L = San Francisco, O = "GitHub, Inc.", CN = github.com verify return:1 --- Certificate chain 0 s:/businessCategory=Private Organization/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/serialNumber=5157550/street=548 4th Street/postalCode=94107/C=US/ST=California/L=San Francisco/O=GitHub, Inc./CN=github.com i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV CA-1 1 s:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV CA-1 i:/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV Root CA --- Server certificate -----BEGIN CERTIFICATE----- MIIHOjCCBiKgAwIBAgIQBH++LkveAITSyvjj7P5wWDANBgkqhkiG9w0BAQUFADBp MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 d3cuZGlnaWNlcnQuY29tMSgwJgYDVQQDEx9EaWdpQ2VydCBIaWdoIEFzc3VyYW5j ZSBFViBDQS0xMB4XDTEzMDYxMDAwMDAwMFoXDTE1MDkwMjEyMDAwMFowgfAxHTAb BgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVT MRkwFwYLKwYBBAGCNzwCAQITCERlbGF3YXJlMRAwDgYDVQQFEwc1MTU3NTUwMRcw FQYDVQQJEw41NDggNHRoIFN0cmVldDEOMAwGA1UEERMFOTQxMDcxCzAJBgNVBAYT AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNpc2Nv MRUwEwYDVQQKEwxHaXRIdWIsIEluYy4xEzARBgNVBAMTCmdpdGh1Yi5jb20wggEi MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDt04nDXXByCfMzTxpydNm2WpVQ u2hhn/f7Hxnh2gQxrxV8Gn/5c68d5UMrVgkARWlK6MRb38J3UlEZW9Er2TllNqAy GRxBc/sysj2fmOyCWws3ZDkstxCDcs3w6iRL+tmULsOFFTmpOvaI2vQniaaVT4Si N058JXg6yYNtAheVeH1HqFWD7hPIGRqzPPFf/jsC4YX7EWarCV2fTEPwxyReKXIo ztR1aE8kcimuOSj8341PTYNzdAxvEZun3WLe/+LrF+b/DL/ALTE71lmi8t2HSkh7 bTMRFE00nzI49sgZnfG2PcVG71ELisYz7UhhxB0XG718tmfpOc+lUoAK9OrNAgMB AAGjggNUMIIDUDAfBgNVHSMEGDAWgBRMWMsl8EFPUvQoyIFDm6aooOaS5TAdBgNV HQ4EFgQUh9GPGW7kh29TjHeRB1Dfo79VRyAwJQYDVR0RBB4wHIIKZ2l0aHViLmNv bYIOd3d3LmdpdGh1Yi5jb20wDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsG AQUFBwMBBggrBgEFBQcDAjBjBgNVHR8EXDBaMCugKaAnhiVodHRwOi8vY3JsMy5k aWdpY2VydC5jb20vZXZjYTEtZzIuY3JsMCugKaAnhiVodHRwOi8vY3JsNC5kaWdp Y2VydC5jb20vZXZjYTEtZzIuY3JsMIIBxAYDVR0gBIIBuzCCAbcwggGzBglghkgB hv1sAgEwggGkMDoGCCsGAQUFBwIBFi5odHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9z c2wtY3BzLXJlcG9zaXRvcnkuaHRtMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4A eQAgAHUAcwBlACAAbwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQA ZQAgAGMAbwBuAHMAdABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUA IABvAGYAIAB0AGgAZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAA YQBuAGQAIAB0AGgAZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcA cgBlAGUAbQBlAG4AdAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIA aQBsAGkAdAB5ACAAYQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQA ZQBkACAAaABlAHIAZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMH0G CCsGAQUFBwEBBHEwbzAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQu Y29tMEcGCCsGAQUFBzAChjtodHRwOi8vY2FjZXJ0cy5kaWdpY2VydC5jb20vRGln aUNlcnRIaWdoQXNzdXJhbmNlRVZDQS0xLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqG SIb3DQEBBQUAA4IBAQBfFW1nwzrVo94WnEUzJtU9yRZ0NMqHSBsUkG31q0eGufW4 4wFFZWjuqRJ1n3Ym7xF8fTjP3fdKGQnxIHKSsE0nuuh/XbQX5DpBJknHdGFoLwY8 xZ9JPI57vgvzLo8+fwHyZp3Vm/o5IYLEQViSo+nlOSUQ8YAVqu6KcsP/e612UiqS +UMBmgdx9KPDDzZy4MJZC2hbfUoXj9A54mJN8cuEOPyw3c3yKOcq/h48KzVguQXi SdJbwfqNIbQ9oJM+YzDjzS62+TCtNSNWzWbwABZCmuQxK0oEOSbTmbhxUF7rND3/ +mx9u8cY//7uAxLWYS5gIZlCbxcf0lkiKSHJB319 -----END CERTIFICATE----- subject=/businessCategory=Private Organization/1.3.6.1.4.1.311.60.2.1.3=US/1.3.6.1.4.1.311.60.2.1.2=Delaware/serialNumber=5157550/street=548 4th Street/postalCode=94107/C=US/ST=California/L=San Francisco/O=GitHub, Inc./CN=github.com issuer=/C=US/O=DigiCert Inc/OU=www.digicert.com/CN=DigiCert High Assurance EV CA-1 --- No client certificate CA names sent --- SSL handshake has read 4139 bytes and written 446 bytes --- New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES128-GCM-SHA256 Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1.2 Cipher : ECDHE-RSA-AES128-GCM-SHA256 Session-ID: 59D2883BBCE8E81E63E5551FAE7D1ACC00C49A9473C1618237BBBB0DD9016B8D Session-ID-ctx: Master-Key: B6D2763FF29E77C67AD83296946A4D44CDBA4F37ED6F20BC27602F1B1A2D137FACDEAC862C11279C01095594F9776F79 Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None Start Time: 1393392673 Timeout : 300 (sec) Verify return code: 0 (ok)

¿Las solicitudes / openssl ya no deberían saber dónde encontrar certificados válidos?

No. OpenSSL no confía en nada por defecto. Es un polo opuesto al modelo de un navegador, donde casi todo es de confianza por defecto.

$ openssl s_client -connect github.com:443 -CAfile `python -c ''import requests; print(requests.certs.where())''` ... >>> r = requests.get(''https://github.com/'', verify=''path to cacert.pem file'')

¿Por qué confiaría en cientos de CA y CA subordinadas (re: cacert.pem ) cuando conoce la única CA que certifica la clave pública del sitio? Confíe en la única raíz necesaria y nada más: DigiCert High Assurance EV CA-1 .

Confiar en todo, como en el modelo del navegador, es lo que permitió a Comodo Hacker falsificar certificados para Gmail, Hotmail, Yahoo, etc. cuando la raíz de Diginotar se vio comprometida.


Desde la Solicitud 2.4.0, el autor recommends usar certifi , que es una colección de Certificados de raíz. Hay un paquete de python para ello:

pip install certifi


openssl s_client de forma predeterminada no utilizará el archivo de certificados de CA con el que se envía, pero intenta verificar la conexión. Esta es la razón por la que su prueba falla sin ningún parámetro y funciona con -CAfile.

De manera similar, Requests intenta verificar la conexión de forma predeterminada, pero parece que no sabe dónde están los certificados de CA. Esto podría ser un problema de configuración en su entorno al compilar / instalar OpenSSL, Python o Requests. Digo esto porque el sitio web de solicitudes muestra que su ejemplo funciona en contra de https://github.com sin necesidad de establecer la ruta de CA.