Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent alpn_select_callback behavior #769

Closed
bmw opened this issue Jun 19, 2018 · 1 comment
Closed

Inconsistent alpn_select_callback behavior #769

bmw opened this issue Jun 19, 2018 · 1 comment

Comments

@bmw
Copy link

bmw commented Jun 19, 2018

Depending on the version of openssl cryptography is compiled against, I'm seeing different behavior when using OpenSSL.SSL.Context.set_alpn_select_callback.

If the registered callback raises an exception when a newer version of openssl is used, the connection is terminated and the certificate is not sent to the connecting client. With older versions of openssl, the connection is not immediately terminated and the certificate is sent. This was a problem for us with Certbot as we specifically didn't want to send the certificate if we weren't happy with the protocols given during ALPN.

To reproduce this, here's a simple Dockerfile to set up a common environment:

FROM ubuntu:17.10
RUN apt-get update && apt-get install gcc libffi-dev libssl-dev openssl python python-dev python-pip ssl-cert -y
RUN pip install --no-binary :all: PyOpenSSL
COPY server.py src/

We get one behavior when the Dockerfile is based on Ubuntu 17.10 and with Ubuntu 18.04.

The contents of server.py are:

import socket
from OpenSSL import crypto, SSL

with open('/etc/ssl/certs/ssl-cert-snakeoil.pem') as f:
    CERT = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
with open('/etc/ssl/private/ssl-cert-snakeoil.key') as f:
    KEY = crypto.load_privatekey(crypto.FILETYPE_PEM, f.read())

def alpn_raise(conn, protos):
    raise Exception

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('', 12345))
s.listen(0)
while True:
    conn, _ = s.accept()
    context = SSL.Context(SSL.SSLv23_METHOD)
    context.use_privatekey(KEY)
    context.use_certificate(CERT)
    context.set_alpn_select_callback(alpn_raise)
    conn = SSL.Connection(context, conn)
    conn.set_accept_state()
    conn.do_handshake()
    conn.close()

Once the Dockerfile is built, to see the different behavior, get a shell and run:

python src/server.py &
openssl s_client -connect localhost:12345 -alpn acme-tls/1
@bmw
Copy link
Author

bmw commented Feb 26, 2020

I think this can be closed. While I still see different behavior with different versions of OpenSSL, the behavior of PyOpenSSL when an exception is raised out of the ALPN callback is not documented and we can get the behavior we want by returning the empty string.

@bmw bmw closed this as completed Feb 26, 2020
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 15, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Development

No branches or pull requests

1 participant