duo_client_python icon indicating copy to clipboard operation
duo_client_python copied to clipboard

SSL error

Open glennbach opened this issue 4 years ago • 20 comments

I'm trying to use this in Amazon Linux 2, with python 3.7.9 and the latest duo_client. I get:

  File "/usr/local/lib/python3.8/site-packages/duo_client/admin.py", line 528, in get_users
    return list(self.get_users_iterator())
  File "/usr/local/lib/python3.8/site-packages/duo_client/client.py", line 406, in json_paging_api_call
    (response, data) = self.api_call(method, path, params)
  File "/usr/local/lib/python3.8/site-packages/duo_client/admin.py", line 196, in api_call
    return super(Admin, self).api_call(method, path, params)
  File "/usr/local/lib/python3.8/site-packages/duo_client/client.py", line 276, in api_call
    return self._make_request(method, uri, body, encoded_headers)
  File "/usr/local/lib/python3.8/site-packages/duo_client/client.py", line 344, in _make_request
    response, data = self._attempt_single_request(
  File "/usr/local/lib/python3.8/site-packages/duo_client/client.py", line 357, in _attempt_single_request
    conn.request(method, uri, body, headers)
  File "/usr/lib64/python3.8/http/client.py", line 1255, in request
    self._send_request(method, url, body, headers, encode_chunked)
  File "/usr/lib64/python3.8/http/client.py", line 1301, in _send_request
    self.endheaders(body, encode_chunked=encode_chunked)
  File "/usr/lib64/python3.8/http/client.py", line 1250, in endheaders
    self._send_output(message_body, encode_chunked=encode_chunked)
  File "/usr/lib64/python3.8/http/client.py", line 1010, in _send_output
    self.send(msg)
  File "/usr/lib64/python3.8/http/client.py", line 950, in send
    self.connect()
  File "/usr/local/lib/python3.8/site-packages/duo_client/https_wrapper.py", line 121, in connect
    self.sock = self.default_ssl_context.wrap_socket(self.sock)
  File "/usr/lib64/python3.8/ssl.py", line 500, in wrap_socket
    return self.sslsocket_class._create(
  File "/usr/lib64/python3.8/ssl.py", line 1040, in _create
    self.do_handshake()
  File "/usr/lib64/python3.8/ssl.py", line 1309, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLEOFError: EOF occurred in violation of protocol (_ssl.c:1123)

Any suggestions? Python requests doesn't have any ssl issues, so I don't see why this would.

glennbach avatar Apr 22 '21 21:04 glennbach

I am having the same issue - also using AL2, but I've tried several other things without any luck:

  • tried locally (macOS) from command line
  • tried in both alpine and ubuntu containers
  • I've also tried tried version 3.8 and 3.7
  • tried adding ndg-httpsclient, pyopenssl, pyasn1 and requests[security]
  • tried unsetting https_proxywith the same results.
  • tried both connected and disconnected from my VPN

The only thing that really changes is the line number in (_ssl.c:####)

This was working correctly on Thursday April 23rd (2021) in the evening (PST) - I dont recall if I had tried or not on Friday, but it started failing when I started it back up on Saturday (2021-04-25)

Any assistance on this would be GREATLY appreciated

brian-snopek avatar Apr 26 '21 00:04 brian-snopek

Because I was desperate to finish my work, I cloned and modified my local copy (quick and dirty) by replacing your api requests with one from the python module 'requests':

    def _attempt_single_request(self, method, uri, body, headers):
        print('Trying:', method, uri, body, headers)
        if method == 'GET':
            response = requests.get(f"https://{self.host}{uri}", headers=headers, data=body)
        elif method == 'POST':
            response = requests.post(f"https://{self.host}{uri}", headers=headers, data=body)
        data = response.json()
        return (response, data)

it worked perfectly, so it isn't a fundamental system issue. (and I know that this is a stupid way to switch between get and put. As I said, it was just quick and dirty...) I did have to make a few other changes to accommodate this change.

glennbach avatar Apr 26 '21 01:04 glennbach

Thanks @glennbach - I attempted what you suggested here - and it did make the request without generating the SSLEOF error - but the response and data returned are missing a lot of properties that caused several other errors.

I think its a great start into identifying where the problem is - and I'll continue looking into this myself in the meantime, but I'm still hoping for a full solution that doesn't require a one-off patch ;)

Thanks again for the info - appreciated

brian-snopek avatar Apr 26 '21 03:04 brian-snopek

Sorry to hear you've been having issues with the client. I'm looking into this issue now. Which API host are you connecting to? Are you specifying any extra configuration options besides the ikey/skey/host?

mbish avatar Apr 26 '21 16:04 mbish

I have no extra configuration - I'm specifically connecting through the admin api, and updating user status only. Thanks

brian-snopek avatar Apr 26 '21 17:04 brian-snopek

Which URL are you using to access the admin api?

mbish avatar Apr 26 '21 17:04 mbish

This is the exact (and only) method we have using the duo_client_python:

def set_duo_status(status='disabled'): status = status if status in ('disabled', 'bypass') else 'disabled'

admin_api = duo_client.Admin(
    ikey=get_param('duo-api-key'),
    skey=get_param('duo-api-secret'),
    host=get_param('duo-api-host'),
)
userData = admin_api.update_user(
    user_id=get_param('duo-api-userid'),
    status=status
)

brian-snopek avatar Apr 26 '21 17:04 brian-snopek

are you asking what host we're passing ?

brian-snopek avatar Apr 26 '21 17:04 brian-snopek

yeah. If you could post the value of your duo-api-host that would be helpful.

mbish avatar Apr 26 '21 17:04 mbish

No problem: api-7cafe99d.duosecurity.com

Thanks again.

brian-snopek avatar Apr 26 '21 17:04 brian-snopek

Mine is api-a3b78b57.duosecurity.com

glennbach avatar Apr 26 '21 17:04 glennbach

Can you post the output of curl -vvI https://<insert api URL> from the AL2 machine having this issue?

mbish avatar Apr 26 '21 18:04 mbish

bash-4.2# curl -vvI https://api-7cafe99d.duosecurity.com
* Rebuilt URL to: https://api-7cafe99d.duosecurity.com/
*   Trying 54.241.191.167...
* TCP_NODELAY set
* Connected to api-7cafe99d.duosecurity.com (54.241.191.167) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: C=US; ST=Michigan; L=Ann Arbor; O=Duo Security, Inc.; CN=*.duosecurity.com
*  start date: Dec 18 00:00:00 2019 GMT
*  expire date: Mar  9 12:00:00 2022 GMT
*  subjectAltName: host "api-7cafe99d.duosecurity.com" matched cert's "*.duosecurity.com"
*  issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert SHA2 High Assurance Server CA
*  SSL certificate verify ok.
> HEAD / HTTP/1.1
> Host: api-7cafe99d.duosecurity.com
> User-Agent: curl/7.61.1
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
HTTP/1.1 301 Moved Permanently
< Server: Duo/1.0
Server: Duo/1.0
< Date: Mon, 26 Apr 2021 18:15:48 GMT
Date: Mon, 26 Apr 2021 18:15:48 GMT
< Content-Type: text/html
Content-Type: text/html
< Content-Length: 180
Content-Length: 180
< Connection: keep-alive
Connection: keep-alive
< Location: https://duo.com/
Location: https://duo.com/
< Strict-Transport-Security: max-age=31536000
Strict-Transport-Security: max-age=31536000
< Content-Security-Policy: default-src 'self'; frame-src 'self' ; img-src 'self'  ; connect-src 'self'    
Content-Security-Policy: default-src 'self'; frame-src 'self' ; img-src 'self'  ; connect-src 'self'    

< 
* Connection #0 to host api-7cafe99d.duosecurity.com left intact
bash-4.2# 

brian-snopek avatar Apr 26 '21 18:04 brian-snopek

Mine shows:

* Rebuilt URL to: https://api-a3b78b57.duosecurity.com/
*   Trying 54.241.191.183...
* TCP_NODELAY set
* Connected to api-a3b78b57.duosecurity.com (54.241.191.183) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: C=US; ST=Michigan; L=Ann Arbor; O=Duo Security, Inc.; CN=*.duosecurity.com
*  start date: Dec 18 00:00:00 2019 GMT
*  expire date: Mar  9 12:00:00 2022 GMT
*  subjectAltName: host "api-a3b78b57.duosecurity.com" matched cert's "*.duosecurity.com"
*  issuer: C=US; O=DigiCert Inc; OU=www.digicert.com; CN=DigiCert SHA2 High Assurance Server CA
*  SSL certificate verify ok.
> HEAD / HTTP/1.1
> Host: api-a3b78b57.duosecurity.com
> User-Agent: curl/7.61.1
> Accept: */*
> 
< HTTP/1.1 301 Moved Permanently
HTTP/1.1 301 Moved Permanently
< Server: Duo/1.0
Server: Duo/1.0
< Date: Mon, 26 Apr 2021 18:21:19 GMT
Date: Mon, 26 Apr 2021 18:21:19 GMT
< Content-Type: text/html
Content-Type: text/html
< Content-Length: 180
Content-Length: 180
< Connection: keep-alive
Connection: keep-alive
< Location: https://duo.com/
Location: https://duo.com/
< Strict-Transport-Security: max-age=31536000
Strict-Transport-Security: max-age=31536000
< Content-Security-Policy: default-src 'self'; frame-src 'self' ; img-src 'self'  ; connect-src 'self'    
Content-Security-Policy: default-src 'self'; frame-src 'self' ; img-src 'self'  ; connect-src 'self'    

< * Connection #0 to host api-a3b78b57.duosecurity.com left intact

glennbach avatar Apr 26 '21 18:04 glennbach

is it possible this is related to the recent tls 1.1 deprecation ?

brian-snopek avatar Apr 26 '21 18:04 brian-snopek

I wish I had better news but I haven't been able to reproduce this using the AL2 container (or anything else for that matter). Nothing looks suspicious in the curl output and those api hosts are operating as expected. At this point the next step would be to get a packet capture of the api request / TLS negotiation and analyze that but that's not something I'd want on a public github issue. Could you file a support request with Duo, link this issue, and tell them you've been speaking with the applications team? That way we can have a private / secure way of exchanging information.

mbish avatar Apr 26 '21 20:04 mbish

Thanks @mbish - Request sent - if you can let me know there details on what you need in the dump, I'll get it generated right away..

Additionally, its running in container - I could give you a dockerfile that should produce the same error

brian-snopek avatar Apr 26 '21 21:04 brian-snopek

Yeah if there's nothing sensitive in the dockerfile that would be great to have.

mbish avatar Apr 27 '21 13:04 mbish

Mine is docker as well.

glennbach avatar Apr 27 '21 14:04 glennbach

I've been fighting with this in a Docker container also. Adding ca_certs="DISABLE" to my duo_client.Admin(...) line got the client working. Still trying to figure out how to get it working without setting ca_certs to DISABLE

doing the follow does not seem to fix the issue either: root@75fd7785ad90:/usr/src/app# apt-get update root@75fd7785ad90:/usr/src/app# apt-get install ca-certificates root@75fd7785ad90:/usr/src/app# update-ca-certificates

root@75fd7785ad90:/usr/src/app# export SSL_CERT_FILE=/usr/lib/ssl/ca-certificates.crt OR root@75fd7785ad90:/usr/src/app# export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt

ragrella avatar May 10 '21 13:05 ragrella