summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIvan Alejandro <ivanalejandro0@gmail.com>2015-02-19 14:12:15 -0300
committerIvan Alejandro <ivanalejandro0@gmail.com>2015-02-20 14:23:05 -0300
commit00b8cbaa31d48326b36928228269ac14276fd5ee (patch)
treeb01d1b66bc933815104ee73b1805c1ef00d17e14
parentff705af455af17710bab34c7959f1c54fb963839 (diff)
Fall back to plain ZMQ if Curve is not available.
Use global flag for ZMQ_HAS_CURVE. Closes #6646
-rw-r--r--changes/non-curve-zmq1
-rw-r--r--src/leap/bitmask/backend/backend.py31
-rw-r--r--src/leap/bitmask/backend/backend_proxy.py18
-rw-r--r--src/leap/bitmask/backend/signaler.py18
-rw-r--r--src/leap/bitmask/backend/signaler_qt.py29
-rw-r--r--src/leap/bitmask/backend/utils.py54
-rw-r--r--src/leap/bitmask/backend_app.py4
-rw-r--r--src/leap/bitmask/config/flags.py3
8 files changed, 114 insertions, 44 deletions
diff --git a/changes/non-curve-zmq b/changes/non-curve-zmq
new file mode 100644
index 00000000..8c1097ee
--- /dev/null
+++ b/changes/non-curve-zmq
@@ -0,0 +1 @@
+- Gracefully fall back to plain ZMQ if CurveZMQ is not available (Feature #6646)
diff --git a/src/leap/bitmask/backend/backend.py b/src/leap/bitmask/backend/backend.py
index 75eff8a9..32f5c953 100644
--- a/src/leap/bitmask/backend/backend.py
+++ b/src/leap/bitmask/backend/backend.py
@@ -28,10 +28,14 @@ import psutil
from twisted.internet import defer, reactor, threads
import zmq
-from zmq.auth.thread import ThreadAuthenticator
+try:
+ from zmq.auth.thread import ThreadAuthenticator
+except ImportError:
+ pass
from leap.bitmask.backend.api import API, PING_REQUEST
from leap.bitmask.backend.utils import get_backend_certificates
+from leap.bitmask.config import flags
from leap.bitmask.backend.signaler import Signaler
import logging
@@ -73,18 +77,19 @@ class Backend(object):
context = zmq.Context()
socket = context.socket(zmq.REP)
- # Start an authenticator for this context.
- auth = ThreadAuthenticator(context)
- auth.start()
- # XXX do not hardcode this here.
- auth.allow('127.0.0.1')
-
- # Tell authenticator to use the certificate in a directory
- auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY)
- public, secret = get_backend_certificates()
- socket.curve_publickey = public
- socket.curve_secretkey = secret
- socket.curve_server = True # must come before bind
+ if flags.ZMQ_HAS_CURVE:
+ # Start an authenticator for this context.
+ auth = ThreadAuthenticator(context)
+ auth.start()
+ # XXX do not hardcode this here.
+ auth.allow('127.0.0.1')
+
+ # Tell authenticator to use the certificate in a directory
+ auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY)
+ public, secret = get_backend_certificates()
+ socket.curve_publickey = public
+ socket.curve_secretkey = secret
+ socket.curve_server = True # must come before bind
socket.bind(self.BIND_ADDR)
diff --git a/src/leap/bitmask/backend/backend_proxy.py b/src/leap/bitmask/backend/backend_proxy.py
index 3e79289f..06e6d840 100644
--- a/src/leap/bitmask/backend/backend_proxy.py
+++ b/src/leap/bitmask/backend/backend_proxy.py
@@ -30,6 +30,7 @@ import zmq
from leap.bitmask.backend.api import API, STOP_REQUEST, PING_REQUEST
from leap.bitmask.backend.utils import generate_zmq_certificates_if_needed
from leap.bitmask.backend.utils import get_backend_certificates
+from leap.bitmask.config import flags
import logging
logger = logging.getLogger(__name__)
@@ -59,15 +60,16 @@ class BackendProxy(object):
logger.debug("Connecting to server...")
socket = context.socket(zmq.REQ)
- # public, secret = zmq.curve_keypair()
- client_keys = zmq.curve_keypair()
- socket.curve_publickey = client_keys[0]
- socket.curve_secretkey = client_keys[1]
+ if flags.ZMQ_HAS_CURVE:
+ # public, secret = zmq.curve_keypair()
+ client_keys = zmq.curve_keypair()
+ socket.curve_publickey = client_keys[0]
+ socket.curve_secretkey = client_keys[1]
- # The client must know the server's public key to make a CURVE
- # connection.
- public, _ = get_backend_certificates()
- socket.curve_serverkey = public
+ # The client must know the server's public key to make a CURVE
+ # connection.
+ public, _ = get_backend_certificates()
+ socket.curve_serverkey = public
socket.setsockopt(zmq.RCVTIMEO, 1000)
socket.setsockopt(zmq.LINGER, 0) # Terminate early
diff --git a/src/leap/bitmask/backend/signaler.py b/src/leap/bitmask/backend/signaler.py
index 43cba994..a8498d11 100644
--- a/src/leap/bitmask/backend/signaler.py
+++ b/src/leap/bitmask/backend/signaler.py
@@ -26,6 +26,7 @@ import zmq
from leap.bitmask.backend.api import SIGNALS
from leap.bitmask.backend.utils import get_frontend_certificates
+from leap.bitmask.config import flags
import logging
logger = logging.getLogger(__name__)
@@ -49,15 +50,16 @@ class Signaler(object):
logger.debug("Connecting to signaling server...")
socket = context.socket(zmq.REQ)
- # public, secret = zmq.curve_keypair()
- client_keys = zmq.curve_keypair()
- socket.curve_publickey = client_keys[0]
- socket.curve_secretkey = client_keys[1]
+ if flags.ZMQ_HAS_CURVE:
+ # public, secret = zmq.curve_keypair()
+ client_keys = zmq.curve_keypair()
+ socket.curve_publickey = client_keys[0]
+ socket.curve_secretkey = client_keys[1]
- # The client must know the server's public key to make a CURVE
- # connection.
- public, _ = get_frontend_certificates()
- socket.curve_serverkey = public
+ # The client must know the server's public key to make a CURVE
+ # connection.
+ public, _ = get_frontend_certificates()
+ socket.curve_serverkey = public
socket.setsockopt(zmq.RCVTIMEO, 1000)
socket.setsockopt(zmq.LINGER, 0) # Terminate early
diff --git a/src/leap/bitmask/backend/signaler_qt.py b/src/leap/bitmask/backend/signaler_qt.py
index 433f18ed..94c24648 100644
--- a/src/leap/bitmask/backend/signaler_qt.py
+++ b/src/leap/bitmask/backend/signaler_qt.py
@@ -24,10 +24,14 @@ import time
from PySide import QtCore
import zmq
-from zmq.auth.thread import ThreadAuthenticator
+try:
+ from zmq.auth.thread import ThreadAuthenticator
+except ImportError:
+ pass
from leap.bitmask.backend.api import SIGNALS
from leap.bitmask.backend.utils import get_frontend_certificates
+from leap.bitmask.config import flags
import logging
logger = logging.getLogger(__name__)
@@ -67,17 +71,18 @@ class SignalerQt(QtCore.QObject):
context = zmq.Context()
socket = context.socket(zmq.REP)
- # Start an authenticator for this context.
- auth = ThreadAuthenticator(context)
- auth.start()
- auth.allow('127.0.0.1')
-
- # Tell authenticator to use the certificate in a directory
- auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY)
- public, secret = get_frontend_certificates()
- socket.curve_publickey = public
- socket.curve_secretkey = secret
- socket.curve_server = True # must come before bind
+ if flags.ZMQ_HAS_CURVE:
+ # Start an authenticator for this context.
+ auth = ThreadAuthenticator(context)
+ auth.start()
+ auth.allow('127.0.0.1')
+
+ # Tell authenticator to use the certificate in a directory
+ auth.configure_curve(domain='*', location=zmq.auth.CURVE_ALLOW_ANY)
+ public, secret = get_frontend_certificates()
+ socket.curve_publickey = public
+ socket.curve_secretkey = secret
+ socket.curve_server = True # must come before bind
socket.bind(self.BIND_ADDR)
diff --git a/src/leap/bitmask/backend/utils.py b/src/leap/bitmask/backend/utils.py
index 18e70743..b2674330 100644
--- a/src/leap/bitmask/backend/utils.py
+++ b/src/leap/bitmask/backend/utils.py
@@ -22,20 +22,63 @@ import os
import shutil
import stat
-import zmq.auth
+import zmq
+try:
+ import zmq.auth
+except ImportError:
+ pass
+
+from leap.bitmask.config import flags
from leap.bitmask.util import get_path_prefix
from leap.common.files import mkdir_p
+from leap.common.check import leap_assert
logger = logging.getLogger(__name__)
KEYS_DIR = os.path.join(get_path_prefix(), 'leap', 'zmq_certificates')
+def _zmq_has_curve():
+ """
+ Return whether the current ZMQ has support for auth and CurveZMQ security.
+
+ :rtype: bool
+
+ Version notes:
+ `zmq.curve_keypair()` is new in version 14.0, new in version libzmq-4.0.
+ Requires libzmq (>= 4.0) to have been linked with libsodium.
+ `zmq.auth` module is new in version 14.1
+ `zmq.has()` is new in version 14.1, new in version libzmq-4.1.
+ """
+ zmq_version = zmq.zmq_version_info()
+ pyzmq_version = zmq.pyzmq_version_info()
+
+ if pyzmq_version >= (14, 1, 0) and zmq_version >= (4, 1):
+ return zmq.has('curve')
+
+ if pyzmq_version < (14, 1, 0):
+ return False
+
+ if zmq_version < (4, 0):
+ # security is new in libzmq 4.0
+ return False
+
+ try:
+ zmq.curve_keypair()
+ except zmq.error.ZMQError:
+ # security requires libzmq to be linked against libsodium
+ return False
+
+ return True
+
+
def generate_zmq_certificates():
"""
Generate client and server CURVE certificate files.
"""
+ leap_assert(flags.ZMQ_HAS_CURVE, "CurveZMQ not supported!")
+
# Create directory for certificates, remove old content if necessary
if os.path.exists(KEYS_DIR):
shutil.rmtree(KEYS_DIR)
@@ -53,6 +96,8 @@ def get_frontend_certificates():
"""
Return the frontend's public and secret certificates.
"""
+ leap_assert(flags.ZMQ_HAS_CURVE, "CurveZMQ not supported!")
+
frontend_secret_file = os.path.join(KEYS_DIR, "frontend.key_secret")
public, secret = zmq.auth.load_certificate(frontend_secret_file)
return public, secret
@@ -62,6 +107,8 @@ def get_backend_certificates(base_dir='.'):
"""
Return the backend's public and secret certificates.
"""
+ leap_assert(flags.ZMQ_HAS_CURVE, "CurveZMQ not supported!")
+
backend_secret_file = os.path.join(KEYS_DIR, "backend.key_secret")
public, secret = zmq.auth.load_certificate(backend_secret_file)
return public, secret
@@ -84,5 +131,8 @@ def generate_zmq_certificates_if_needed():
Generate the needed ZMQ certificates for backend/frontend communication if
needed.
"""
- if not _certificates_exist():
+ if flags.ZMQ_HAS_CURVE and not _certificates_exist():
generate_zmq_certificates()
+
+
+flags.ZMQ_HAS_CURVE = _zmq_has_curve()
diff --git a/src/leap/bitmask/backend_app.py b/src/leap/bitmask/backend_app.py
index 286b04f7..3e88a95a 100644
--- a/src/leap/bitmask/backend_app.py
+++ b/src/leap/bitmask/backend_app.py
@@ -23,6 +23,7 @@ import signal
from leap.bitmask.backend.leapbackend import LeapBackend
from leap.bitmask.backend.utils import generate_zmq_certificates
+from leap.bitmask.config import flags
from leap.bitmask.logs.utils import create_logger
from leap.bitmask.util import dict_to_flags
@@ -57,7 +58,8 @@ def run_backend(bypass_checks=False, flags_dict=None, frontend_pid=None):
"""
# The backend is the one who always creates the certificates. Either if it
# is run separately or in a process in the same app as the frontend.
- generate_zmq_certificates()
+ if flags.ZMQ_HAS_CURVE:
+ generate_zmq_certificates()
# ignore SIGINT since app.py takes care of signaling SIGTERM to us.
signal.signal(signal.SIGINT, signal.SIG_IGN)
diff --git a/src/leap/bitmask/config/flags.py b/src/leap/bitmask/config/flags.py
index 6b70659d..cdde1971 100644
--- a/src/leap/bitmask/config/flags.py
+++ b/src/leap/bitmask/config/flags.py
@@ -55,3 +55,6 @@ OPENVPN_VERBOSITY = 1
# Skip the checks in the wizard, use for testing purposes only!
SKIP_WIZARD_CHECKS = False
+
+# This flag tells us whether the current pyzmq supports using CurveZMQ or not.
+ZMQ_HAS_CURVE = None